summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Machniak <machniak@kolabsys.com>2014-10-13 09:04:50 (GMT)
committerAleksander Machniak <machniak@kolabsys.com>2014-10-13 09:04:50 (GMT)
commit3efb3d021520a2f163df5679ee2be6198dfbd5dc (patch)
tree82e9522a351ae6143011001a9b75284a19728461
parentcca411d89888983c3c3b0aa5fcbba1f0d9e2665a (diff)
downloadkolab-chwala-3efb3d021520a2f163df5679ee2be6198dfbd5dc.tar.gz
Added interface to manage external storage(s)
-rw-r--r--lib/api/common.php21
-rw-r--r--lib/api/folder_auth.php81
-rw-r--r--lib/api/folder_create.php51
-rw-r--r--lib/api/folder_delete.php10
-rw-r--r--lib/api/folder_list.php9
-rw-r--r--lib/api/folder_move.php20
-rw-r--r--lib/api/folder_types.php60
-rw-r--r--lib/client/file_ui_client_main.php25
-rw-r--r--lib/drivers/kolab/kolab.pngbin0 -> 1092 bytes
-rw-r--r--lib/drivers/kolab/kolab_file_storage.php37
-rw-r--r--lib/drivers/seafile/seafile.pngbin0 -> 1107 bytes
-rw-r--r--lib/drivers/seafile/seafile_api.php14
-rw-r--r--lib/drivers/seafile/seafile_file_storage.php70
-rw-r--r--lib/file_api.php31
-rw-r--r--lib/file_locale.php122
-rw-r--r--lib/file_storage.php17
-rw-r--r--lib/file_ui.php96
-rw-r--r--lib/file_ui_output.php3
-rw-r--r--lib/locale/en_US.php10
19 files changed, 550 insertions, 127 deletions
diff --git a/lib/api/common.php b/lib/api/common.php
index bbde2e2..6cdb6cf 100644
--- a/lib/api/common.php
+++ b/lib/api/common.php
@@ -118,4 +118,25 @@ class file_api_common
closedir($handle);
}
}
+
+ /**
+ * Parse driver metadata information
+ */
+ protected function parse_metadata($metadata, $default = false)
+ {
+ if ($default) {
+ unset($metadata['form']);
+ $metadata['name'] .= ' (' . $this->api->translate('localstorage') . ')';
+ }
+
+ // localize form labels
+ foreach ($metadata['form'] as $key => $val) {
+ $label = $this->api->translate('form.' . $val);
+ if (strpos($label, 'form.') !== 0) {
+ $metadata['form'][$key] = $label;
+ }
+ }
+
+ return $metadata;
+ }
}
diff --git a/lib/api/folder_auth.php b/lib/api/folder_auth.php
new file mode 100644
index 0000000..3304cbb
--- /dev/null
+++ b/lib/api/folder_auth.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab File API |
+ | |
+ | Copyright (C) 2012-2014, Kolab Systems AG |
+ | |
+ | 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/> |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak@kolabsys.com> |
+ +--------------------------------------------------------------------------+
+*/
+
+require_once __DIR__ . "/common.php";
+
+class file_api_folder_auth extends file_api_common
+{
+ /**
+ * Request handler
+ */
+ public function handle()
+ {
+ parent::handle();
+
+ if (!isset($this->args['folder']) || $this->args['folder'] === '') {
+ throw new Exception("Missing folder name", file_api::ERROR_CODE);
+ }
+
+ $drivers = $this->api->get_drivers();
+
+ foreach ($drivers as $driver_config) {
+ if ($driver_config['title'] === $this->args['folder']) {
+ $driver = $this->api->get_driver_object($driver_config);
+ $meta = $driver->driver_metadata();
+ }
+ }
+
+ if (empty($driver)) {
+ throw new Exception("Unknown folder", file_api::ERROR_CODE);
+ }
+
+ // check if authentication works
+ $data = array_fill_keys(array_keys($meta['form']), '');
+ $data = array_merge($data, $this->args);
+ $data = $driver->driver_validate($data);
+
+ // save changed data (except password)
+ unset($data['password']);
+ foreach (array_keys($meta['form']) as $key) {
+ if ($meta['form_values'][$key] != $data[$key]) {
+ // @TODO: save current driver config
+ break;
+ }
+ }
+
+ $result = array('folder' => $this->args['folder']);
+
+ // get list if 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;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/lib/api/folder_create.php b/lib/api/folder_create.php
index bf67b0e..1100f5b 100644
--- a/lib/api/folder_create.php
+++ b/lib/api/folder_create.php
@@ -37,8 +37,55 @@ class file_api_folder_create extends file_api_common
throw new Exception("Missing folder name", file_api::ERROR_CODE);
}
- list($driver, $path) = $this->api->get_driver($this->args['folder']);
+ // normal folder
+ if (empty($this->args['driver']) || $this->args['driver'] == 'default') {
+ list($driver, $path) = $this->api->get_driver($this->args['folder']);
- return $driver->folder_create($path);
+ return $driver->folder_create($path);
+ }
+
+ // external storage (mount point)
+ if (strpos($this->args['folder'], file_storage::SEPARATOR) !== false) {
+ throw new Exception("Unable to mount external storage into a sub-folder", file_api::ERROR_CODE);
+ }
+
+ // check if driver is enabled
+ $enabled = $this->rc->config->get('fileapi_drivers');
+
+ if (!in_array($this->args['driver'], $enabled)) {
+ throw new Exception("Unsupported storage driver", file_storage::ERROR_UNSUPPORTED);
+ }
+
+ // check if folder/mount point already exists
+ $drivers = $this->api->get_drivers();
+ foreach ($drivers as $driver) {
+ if ($driver['title'] === $this->args['folder']) {
+ throw new Exception("Specified folder already exists", file_storage::ERROR_FILE_EXISTS);
+ }
+ }
+
+ $backend = $this->api->get_backend();
+ $folders = $backend->folder_list();
+
+ if (in_array($this->args['folder'], $folders)) {
+ throw new Exception("Specified folder already exists", file_storage::ERROR_FILE_EXISTS);
+ }
+
+ // load driver
+ $driver = $this->api->load_driver_object($this->args['driver']);
+ $driver->configure($this->api->config, $this->args['folder']);
+
+ // check if authentication works
+ $data = $driver->driver_validate($this->args);
+
+ $data['title'] = $this->args['folder'];
+ $data['driver'] = $this->args['driver'];
+
+ // don't store password
+ // @TODO: store passwords encrypted?
+ unset($data['password']);
+
+ // save the mount point info in config
+ $backend->driver_create($data);
}
}
diff --git a/lib/api/folder_delete.php b/lib/api/folder_delete.php
index 5fe4b13..694c0d5 100644
--- a/lib/api/folder_delete.php
+++ b/lib/api/folder_delete.php
@@ -39,10 +39,14 @@ class file_api_folder_delete extends file_api_common
list($driver, $path) = $this->api->get_driver($this->args['folder']);
- if (!strlen($path)) {
- // @TODO: delete mount point
+ // delete mount point...
+ if ($driver->title() === $this->args['folder']) {
+ $backend = $this->api->get_backend();
+ $backend->driver_delete($this->args['folder']);
+ return;
}
- return $driver->folder_delete($path);
+ // delete folder...
+ $driver->folder_delete($path);
}
}
diff --git a/lib/api/folder_list.php b/lib/api/folder_list.php
index c9f8e5d..5659804 100644
--- a/lib/api/folder_list.php
+++ b/lib/api/folder_list.php
@@ -39,6 +39,7 @@ class file_api_folder_list extends file_api_common
// get folders from main driver
$folders = $backend->folder_list();
$has_more = false;
+ $errors = array();
// get folders from external sources
foreach ($drivers as $driver) {
@@ -64,7 +65,8 @@ class file_api_folder_list extends file_api_common
}
catch (Exception $e) {
if ($e->getCode() == file_storage::ERROR_NOAUTH) {
- // inform UI about it to ask user for credentials
+ // inform UI about to ask user for credentials
+ $errors[$title] = $this->parse_metadata($driver->driver_metadata());
}
}
}
@@ -75,7 +77,10 @@ class file_api_folder_list extends file_api_common
usort($folders, array($this, 'sort_folder_comparator'));
}
- return $folders;
+ return array(
+ 'list' => $folders,
+ 'auth_errors' => $errors,
+ );
}
/**
diff --git a/lib/api/folder_move.php b/lib/api/folder_move.php
index 39f757e..41828c6 100644
--- a/lib/api/folder_move.php
+++ b/lib/api/folder_move.php
@@ -48,11 +48,29 @@ class file_api_folder_move extends file_api_common
list($driver, $path) = $this->api->get_driver($this->args['folder']);
list($new_driver, $new_path) = $this->api->get_driver($this->args['new']);
- // @TODO: cross-driver move
+ // mount point (driver title) rename
+ if ($driver->title() === $this->args['folder'] && strpos($this->args['new'], file_storage::SEPARATOR) === false) {
+ // @TODO
+ throw new Exception("Unsupported operation", file_api::ERROR_CODE);
+ }
+
+ // cross-driver move
if ($driver != $new_driver) {
+ // @TODO
throw new Exception("Unsupported operation", file_api::ERROR_CODE);
}
+ // make sure destination folder is not an existing mount point
+ if (strpos($this->args['new'], file_storage::SEPARATOR) === false) {
+ $drivers = $this->api->get_drivers();
+
+ foreach ($drivers as $driver) {
+ if ($driver['title'] === $this->args['new']) {
+ throw new Exception("Destination folder exists", file_api::ERROR_CODE);
+ }
+ }
+ }
+
return $driver->folder_move($path, $new_path);
}
}
diff --git a/lib/api/folder_types.php b/lib/api/folder_types.php
new file mode 100644
index 0000000..fd10ea7
--- /dev/null
+++ b/lib/api/folder_types.php
@@ -0,0 +1,60 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab File API |
+ | |
+ | Copyright (C) 2012-2014, Kolab Systems AG |
+ | |
+ | 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/> |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak@kolabsys.com> |
+ +--------------------------------------------------------------------------+
+*/
+
+require_once __DIR__ . "/common.php";
+
+class file_api_folder_types extends file_api_common
+{
+ /**
+ * Request handler
+ */
+ public function handle()
+ {
+ parent::handle();
+
+ $drivers = $this->rc->config->get('fileapi_drivers');
+ $result = array();
+
+ if (!empty($drivers)) {
+ foreach ((array) $drivers as $driver_name) {
+ if ($driver_name != 'kolab' && !isset($result[$driver_name])) {
+ $driver = $this->api->load_driver_object($driver_name);
+ $meta = $driver->driver_metadata();
+
+ $result[$driver_name] = $this->parse_metadata($meta);
+ }
+ }
+ }
+/*
+ // add local storage to the list
+ if (!empty($result)) {
+ $backend = $this->api->get_backend();
+ $meta = $backend->driver_metadata();
+
+ $result = array_merge(array('default' => $this->parse_metadata($meta, true)), $result);
+ }
+*/
+ return $result;
+ }
+}
diff --git a/lib/client/file_ui_client_main.php b/lib/client/file_ui_client_main.php
index 82112e4..d6b8d4a 100644
--- a/lib/client/file_ui_client_main.php
+++ b/lib/client/file_ui_client_main.php
@@ -31,7 +31,7 @@ class file_ui_client_main extends file_ui
'collection.audio', 'collection.video', 'collection.image', 'collection.document',
'moving', 'copying', 'file.skip', 'file.skipall', 'file.overwrite', 'file.overwriteall',
'file.moveconfirm', 'file.progress', 'upload.size', 'upload.size.error', 'upload.progress',
- 'upload.eta', 'upload.rate'
+ 'upload.eta', 'upload.rate', 'folder.authenticate', 'form.submit', 'form.cancel'
);
$result = $this->api_get('mimetypes');
@@ -48,6 +48,7 @@ class file_ui_client_main extends file_ui
'type' => 'text',
'name' => 'name',
'value' => '',
+ 'id' => 'folder-name-input',
));
$input_parent = new html_checkbox(array(
'name' => 'parent',
@@ -65,15 +66,29 @@ class file_ui_client_main extends file_ui
'value' => $this->translate('form.cancel'),
));
+ $drivers_input = new html_checkbox(array(
+ 'name' => 'external',
+ 'value' => '1',
+ 'id' => 'folder-driver-checkbox',
+ ));
+ $drivers = html::div('drivers',
+ html::span('drivers-header', $drivers_input->show()
+ . html::label('folder-driver-checkbox', $this->translate('folder.driverselect')))
+ . html::div('drivers-list', '')
+ );
+
$table = new html_table;
- $table->add(null, $input_name->show() . $input_parent->show()
- . html::label('folder-parent-checkbox', $this->translate('folder.under')));
+ $table->add(null, html::label('folder-name-input', $this->translate('folder.name')) . $input_name->show());
$table->add('buttons', $submit->show() . $cancel->show());
$content = html::tag('fieldset', null,
- html::tag('legend', null,
- $this->translate('folder.createtitle')) . $table->show());
+ html::tag('legend', null, $this->translate('folder.createtitle'))
+ . $table->show()
+ . $input_parent->show()
+ . html::label('folder-parent-checkbox', $this->translate('folder.under'))
+ . $drivers
+ );
$form = html::tag('form', array(
'id' => 'folder-create-form',
diff --git a/lib/drivers/kolab/kolab.png b/lib/drivers/kolab/kolab.png
new file mode 100644
index 0000000..f7b36fd
--- /dev/null
+++ b/lib/drivers/kolab/kolab.png
Binary files differ
diff --git a/lib/drivers/kolab/kolab_file_storage.php b/lib/drivers/kolab/kolab_file_storage.php
index 4a39607..eef9a8e 100644
--- a/lib/drivers/kolab/kolab_file_storage.php
+++ b/lib/drivers/kolab/kolab_file_storage.php
@@ -396,6 +396,43 @@ class kolab_file_storage implements file_storage
}
/**
+ * Returns metadata of the driver
+ *
+ * @return array Driver meta data (image, name, form)
+ */
+ public function driver_metadata()
+ {
+ $image_content = file_get_contents(__DIR__ . '/kolab.png');
+
+ $metadata = array(
+ 'image' => 'data:image/png;base64,' . base64_encode($image_content),
+ 'name' => 'Kolab Groupware',
+ 'ref' => 'http://kolab.org',
+ 'description' => 'Kolab Groupware server',
+ 'form' => array(
+ 'host' => 'hostname',
+ 'username' => 'username',
+ 'password' => 'password',
+ ),
+ );
+
+ return $metadata;
+ }
+
+ /**
+ * Validate metadata (config) of the driver
+ *
+ * @param array $metadata Driver metadata
+ *
+ * @return array Driver meta data to be stored in configuration
+ * @throws Exception
+ */
+ public function driver_validate($metadata)
+ {
+ throw new Exception("Not implemented", file_storage::ERROR_UNSUPPORTED);
+ }
+
+ /**
* Create a file.
*
* @param string $file_name Name of a file (with folder path)
diff --git a/lib/drivers/seafile/seafile.png b/lib/drivers/seafile/seafile.png
new file mode 100644
index 0000000..484fde9
--- /dev/null
+++ b/lib/drivers/seafile/seafile.png
Binary files differ
diff --git a/lib/drivers/seafile/seafile_api.php b/lib/drivers/seafile/seafile_api.php
index 6fba80f..17168eb 100644
--- a/lib/drivers/seafile/seafile_api.php
+++ b/lib/drivers/seafile/seafile_api.php
@@ -187,9 +187,9 @@ class seafile_api
$this->request->setMethod($method ?: HTTP_Request2::METHOD_GET);
if (!empty($get)) {
- $url = $this->request->getUrl();
- $url->setQueryVariables($get);
- $this->request->setUrl($url);
+ $_url = $this->request->getUrl();
+ $_url->setQueryVariables($get);
+ $this->request->setUrl($_url);
}
if (!empty($post)) {
@@ -227,11 +227,11 @@ class seafile_api
rcube::write_log('console', "SeaFile Response [$this->status]: " . trim($body));
}
- // request throttled, try again?
+ // request throttled, try again
if ($this->status == self::TOO_MANY_REQUESTS) {
- if (preg_match('/([0-9]+) second/', $body['detail'], $m) && ($seconds = $m[1]) < self::WAIT_LIMIT) {
- sleep($seconds/2); // try to be smart and wait only a half of it
- return $this->request($url, $method, $get, $post, $upload);
+ if (preg_match('/([0-9]+) second/', $body, $m) && ($seconds = $m[1]) < self::WAIT_LIMIT) {
+ sleep($seconds);
+ return $this->request($method, $url, $get, $post, $upload);
}
}
diff --git a/lib/drivers/seafile/seafile_file_storage.php b/lib/drivers/seafile/seafile_file_storage.php
index 2b1a6e6..e8323f4 100644
--- a/lib/drivers/seafile/seafile_file_storage.php
+++ b/lib/drivers/seafile/seafile_file_storage.php
@@ -145,6 +145,9 @@ class seafile_file_storage implements file_storage
if (!$valid && empty($_SESSION[$this->title . 'seafile_user'])) {
throw new Exception("User credentials not provided", file_storage::ERROR_NOAUTH);
}
+ 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);
+ }
return $valid;
}
@@ -241,6 +244,73 @@ class seafile_file_storage implements file_storage
}
/**
+ * Returns metadata of the driver
+ *
+ * @return array Driver meta data (image, name, form)
+ */
+ public function driver_metadata()
+ {
+ $image_content = file_get_contents(__DIR__ . '/seafile.png');
+
+ $metadata = array(
+ 'image' => 'data:image/png;base64,' . base64_encode($image_content),
+ 'name' => 'SeaFile',
+ 'ref' => 'http://seafile.com',
+ 'description' => 'Storage implementing SeaFile API access',
+ 'form' => array(
+ 'host' => 'hostname',
+ 'username' => 'username',
+ 'password' => 'password',
+ ),
+ );
+
+ // these are returned when authentication on folders list fails
+ if ($this->config['username']) {
+ $metadata['form_values'] = array(
+ 'host' => $this->config['host'],
+ 'username' => $this->config['username'],
+ );
+ }
+
+ return $metadata;
+ }
+
+ /**
+ * Validate metadata (config) of the driver
+ *
+ * @param array $metadata Driver metadata
+ *
+ * @return array Driver meta data to be stored in configuration
+ * @throws Exception
+ */
+ public function driver_validate($metadata)
+ {
+ if (!is_string($metadata['username']) || !strlen($metadata['username'])) {
+ throw new Exception("Missing user name.", file_storage::ERROR);
+ }
+
+ if (!is_string($metadata['password']) || !strlen($metadata['password'])) {
+ throw new Exception("Missing user password.", file_storage::ERROR);
+ }
+
+ if (!is_string($metadata['host']) || !strlen($metadata['host'])) {
+ throw new Exception("Missing host name.", file_storage::ERROR);
+ }
+
+ $this->config['host'] = $metadata['host'];
+
+ if (!$this->authenticate($metadata['username'], $metadata['password'])) {
+ throw new Exception("Unable to authenticate user", file_storage::ERROR_NOAUTH);
+ }
+
+ return array(
+ 'host' => $metadata['host'],
+ 'username' => $metadata['username'],
+ 'password' => $metadata['password'],
+ );
+ }
+
+ /**
* Create a file.
*
* @param string $file_name Name of a file (with folder path)
diff --git a/lib/file_api.php b/lib/file_api.php
index 88302bb..10d2b44 100644
--- a/lib/file_api.php
+++ b/lib/file_api.php
@@ -22,7 +22,7 @@
+--------------------------------------------------------------------------+
*/
-class file_api
+class file_api extends file_locale
{
const ERROR_CODE = 500;
const OUTPUT_JSON = 'application/json';
@@ -46,12 +46,15 @@ class file_api
{
$rcube = rcube::get_instance();
$rcube->add_shutdown_function(array($this, 'shutdown'));
+
$this->conf = $rcube->config;
$this->session_init();
if ($_SESSION['config']) {
$this->config = $_SESSION['config'];
}
+
+ $this->locale_init();
}
/**
@@ -385,15 +388,7 @@ class file_api
$key = $config['title'];
if (empty($this->drivers[$key])) {
- $class = $config['driver'] . '_file_storage';
-
- if (!class_exists($class, false)) {
- $include_path = RCUBE_INSTALL_PATH . "/lib/drivers/" . $config['driver'] . PATH_SEPARATOR;
- $include_path .= ini_get('include_path');
- set_include_path($include_path);
- }
-
- $this->drivers[$key] = $driver = new $class;
+ $this->drivers[$key] = $driver = $this->load_driver_object($config['driver']);
if ($config['username'] == '%u') {
$rcube = rcube::get_instance();
@@ -409,6 +404,22 @@ class file_api
}
/**
+ * Loads a driver
+ */
+ public function load_driver_object($name)
+ {
+ $class = $name . '_file_storage';
+
+ if (!class_exists($class, false)) {
+ $include_path = RCUBE_INSTALL_PATH . "/lib/drivers/$name" . PATH_SEPARATOR;
+ $include_path .= ini_get('include_path');
+ set_include_path($include_path);
+ }
+
+ return new $class;
+ }
+
+ /**
* Returns storage(s) capabilities
*
* @return array Capabilities
diff --git a/lib/file_locale.php b/lib/file_locale.php
new file mode 100644
index 0000000..d924a54
--- /dev/null
+++ b/lib/file_locale.php
@@ -0,0 +1,122 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab File API |
+ | |
+ | Copyright (C) 2011-2014, Kolab Systems AG |
+ | |
+ | 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/> |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak@kolabsys.com> |
+ | Author: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> |
+ +--------------------------------------------------------------------------+
+*/
+
+class file_locale
+{
+ protected static $translation = array();
+
+
+ /**
+ * Localization initialization.
+ */
+ protected function locale_init()
+ {
+ $language = $this->get_language();
+ $LANG = array();
+
+ if (!$language) {
+ $language = 'en_US';
+ }
+
+ @include RCUBE_INSTALL_PATH . "/lib/locale/en_US.php";
+
+ if ($language != 'en_US') {
+ @include RCUBE_INSTALL_PATH . "/lib/locale/$language.php";
+ }
+
+ setlocale(LC_ALL, $language . '.utf8', $language . 'UTF-8', 'en_US.utf8', 'en_US.UTF-8');
+
+ self::$translation = $LANG;
+ }
+
+ /**
+ * Returns system language (locale) setting.
+ *
+ * @return string Language code
+ */
+ protected function get_language()
+ {
+ $aliases = array(
+ 'de' => 'de_DE',
+ 'en' => 'en_US',
+ 'pl' => 'pl_PL',
+ );
+
+ // UI language
+ $langs = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';
+ $langs = explode(',', $langs);
+
+ if (!empty($_SESSION['user']) && !empty($_SESSION['user']['language'])) {
+ array_unshift($langs, $_SESSION['user']['language']);
+ }
+
+ while ($lang = array_shift($langs)) {
+ $lang = explode(';', $lang);
+ $lang = $lang[0];
+ $lang = str_replace('-', '_', $lang);
+
+ if (file_exists(RCUBE_INSTALL_PATH . "/lib/locale/$lang.php")) {
+ return $lang;
+ }
+
+ if (isset($aliases[$lang]) && ($alias = $aliases[$lang])
+ && file_exists(RCUBE_INSTALL_PATH . "/lib/locale/$alias.php")
+ ) {
+ return $alias;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns translation of defined label/message.
+ *
+ * @return string Translated string.
+ */
+ public static function translate()
+ {
+ $args = func_get_args();
+
+ if (is_array($args[0])) {
+ $args = $args[0];
+ }
+
+ $label = $args[0];
+
+ if (isset(self::$translation[$label])) {
+ $content = trim(self::$translation[$label]);
+ }
+ else {
+ $content = $label;
+ }
+
+ for ($i = 1, $len = count($args); $i < $len; $i++) {
+ $content = str_replace('$'.$i, $args[$i], $content);
+ }
+
+ return $content;
+ }
+}
diff --git a/lib/file_storage.php b/lib/file_storage.php
index 809e8a4..7abb20f 100644
--- a/lib/file_storage.php
+++ b/lib/file_storage.php
@@ -107,6 +107,23 @@ interface file_storage
public function driver_list();
/**
+ * Returns metadata of the driver
+ *
+ * @return array Driver meta data (image, name, form)
+ */
+ public function driver_metadata();
+
+ /**
+ * Validate metadata (config) of the driver
+ *
+ * @param array $metadata Driver metadata
+ *
+ * @return array Driver meta data to be stored in configuration
+ * @throws Exception
+ */
+ public function driver_validate($metadata);
+
+ /**
* Update configuration of external driver (mount point)
*
* @param string $name Driver instance name
diff --git a/lib/file_ui.php b/lib/file_ui.php
index 071301b..858030a 100644
--- a/lib/file_ui.php
+++ b/lib/file_ui.php
@@ -23,7 +23,7 @@
+--------------------------------------------------------------------------+
*/
-class file_ui
+class file_ui extends file_locale
{
/**
* @var kolab_client_output
@@ -47,8 +47,6 @@ class file_ui
protected $devel_mode = false;
protected $object_types = array();
- protected static $translation = array();
-
/**
* Class constructor.
@@ -77,29 +75,6 @@ class file_ui
}
/**
- * Localization initialization.
- */
- protected function locale_init()
- {
- $language = $this->get_language();
- $LANG = array();
-
- if (!$language) {
- $language = 'en_US';
- }
-
- @include RCUBE_INSTALL_PATH . '/lib/locale/en_US.php';
-
- if ($language != 'en_US') {
- @include RCUBE_INSTALL_PATH . "/lib/locale/$language.php";
- }
-
- setlocale(LC_ALL, $language . '.utf8', $language . 'UTF-8', 'en_US.utf8', 'en_US.UTF-8');
-
- self::$translation = $LANG;
- }
-
- /**
* Configuration initialization.
*/
private function config_init()
@@ -169,46 +144,6 @@ class file_ui
}
/**
- * Returns system language (locale) setting.
- *
- * @return string Language code
- */
- private function get_language()
- {
- $aliases = array(
- 'de' => 'de_DE',
- 'en' => 'en_US',
- 'pl' => 'pl_PL',
- );
-
- // UI language
- $langs = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';
- $langs = explode(',', $langs);
-
- if (!empty($_SESSION['user']) && !empty($_SESSION['user']['language'])) {
- array_unshift($langs, $_SESSION['user']['language']);
- }
-
- while ($lang = array_shift($langs)) {
- $lang = explode(';', $lang);
- $lang = $lang[0];
- $lang = str_replace('-', '_', $lang);
-
- if (file_exists(RCUBE_INSTALL_PATH . "/lib/locale/$lang.php")) {
- return $lang;
- }
-
- if (isset($aliases[$lang]) && ($alias = $aliases[$lang])
- && file_exists(RCUBE_INSTALL_PATH . "/lib/locale/$alias.php")
- ) {
- return $alias;
- }
- }
-
- return null;
- }
-
- /**
* User authentication (and authorization).
*/
private function auth()
@@ -465,35 +400,6 @@ class file_ui
}
/**
- * Returns translation of defined label/message.
- *
- * @return string Translated string.
- */
- public static function translate()
- {
- $args = func_get_args();
-
- if (is_array($args[0])) {
- $args = $args[0];
- }
-
- $label = $args[0];
-
- if (isset(self::$translation[$label])) {
- $content = trim(self::$translation[$label]);
- }
- else {
- $content = $label;
- }
-
- for ($i = 1, $len = count($args); $i < $len; $i++) {
- $content = str_replace('$'.$i, $args[$i], $content);
- }
-
- return $content;
- }
-
- /**
* Returns input parameter value.
*
* @param string $name Parameter name
diff --git a/lib/file_ui_output.php b/lib/file_ui_output.php
index 1dad12a..efb91a4 100644
--- a/lib/file_ui_output.php
+++ b/lib/file_ui_output.php
@@ -145,6 +145,7 @@ class file_ui_output
$this->tpl->assign($name, $value);
}
+ $this->env['skin_path'] = 'skins/' . $this->skin . '/';
$script = '';
if (!empty($this->env)) {
@@ -170,7 +171,7 @@ class file_ui_output
$script[] = sprintf('ui.%s(%s);', $cname, implode(',', $args));
}
- $this->tpl->assign('skin_path', 'skins/' . $this->skin . '/');
+ $this->tpl->assign('skin_path', $this->env['skin_path']);
if ($script) {
$script = "<script type=\"text/javascript\">\n" . implode("\n", $script) . "\n</script>";
$this->tpl->assign('script', $script);
diff --git a/lib/locale/en_US.php b/lib/locale/en_US.php
index f002c59..192d3b0 100644
--- a/lib/locale/en_US.php
+++ b/lib/locale/en_US.php
@@ -35,10 +35,16 @@ $LANG['folder.createtitle'] = 'Create Folder';
$LANG['folder.delete'] = 'Delete';
$LANG['folder.edit'] = 'Edit';
$LANG['folder.edittitle'] = 'Edit Folder';
-$LANG['folder.under'] = 'under current folder';
+$LANG['folder.under'] = 'inside the current folder';
+$LANG['folder.driverselect'] = 'bind with the external storage';
+$LANG['folder.name'] = 'Name:';
+$LANG['folder.authenticate'] = 'Logon to $title';
$LANG['form.submit'] = 'Submit';
$LANG['form.cancel'] = 'Cancel';
+$LANG['form.hostname'] = 'Hostname:';
+$LANG['form.username'] = 'Username:';
+$LANG['form.password'] = 'Password:';
$LANG['login.username'] = 'Username';
$LANG['login.password'] = 'Password';
@@ -48,6 +54,7 @@ $LANG['reqtime'] = 'Request time: $1 sec.';
$LANG['maxupload'] = 'Maximum file size: $1';
$LANG['internalerror'] = 'Internal system error!';
$LANG['loginerror'] = 'Incorrect username or password!';
+$LANG['authenticating'] = 'Authenticating...';
$LANG['loading'] = 'Loading...';
$LANG['saving'] = 'Saving...';
$LANG['deleting'] = 'Deleting...';
@@ -57,6 +64,7 @@ $LANG['logout'] = 'Logout';
$LANG['close'] = 'Close';
$LANG['servererror'] = 'Server Error!';
$LANG['session.expired'] = 'Session has expired. Login again, please';
+$LANG['localstorage'] = 'local storage';
$LANG['search'] = 'Search';
$LANG['search.loading'] = 'Searching...';