From 33bb2238aeb0fddd3ddd3fe18307c5e7548e00bc Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 16 Aug 2013 08:06:25 +0200 Subject: updating 3rdparty repo commit --- 3rdparty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty b/3rdparty index 2f3ae9f56a9..8d68fa1eabe 160000 --- a/3rdparty +++ b/3rdparty @@ -1 +1 @@ -Subproject commit 2f3ae9f56a9838b45254393e13c14f8a8c380d6b +Subproject commit 8d68fa1eabe8c1d033cb89676b31f0eaaf99335b -- cgit v1.2.3 From fde9cabe9774b67e88ee8aa8fa39fe044fe2da2f Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 17 Aug 2013 11:16:48 +0200 Subject: initial import of appframework --- lib/appframework/app.php | 97 ++++ lib/appframework/controller/controller.php | 154 ++++++ lib/appframework/core/api.php | 524 +++++++++++++++++++++ .../dependencyinjection/dicontainer.php | 125 +++++ lib/appframework/http/dispatcher.php | 98 ++++ lib/appframework/http/downloadresponse.php | 51 ++ lib/appframework/http/http.php | 208 ++++++++ lib/appframework/http/jsonresponse.php | 74 +++ lib/appframework/http/redirectresponse.php | 54 +++ lib/appframework/http/request.php | 217 +++++++++ lib/appframework/http/response.php | 169 +++++++ lib/appframework/http/templateresponse.php | 126 +++++ lib/appframework/middleware/middleware.php | 100 ++++ .../middleware/middlewaredispatcher.php | 159 +++++++ .../middleware/security/securityexception.php | 41 ++ .../middleware/security/securitymiddleware.php | 141 ++++++ lib/appframework/routing/routeactionhandler.php | 42 ++ lib/appframework/routing/routeconfig.php | 186 ++++++++ .../utility/methodannotationreader.php | 61 +++ lib/appframework/utility/timefactory.php | 42 ++ tests/lib/appframework/AppTest.php | 107 +++++ tests/lib/appframework/classloader.php | 45 ++ .../lib/appframework/controller/ControllerTest.php | 161 +++++++ .../dependencyinjection/DIContainerTest.php | 98 ++++ tests/lib/appframework/http/DispatcherTest.php | 218 +++++++++ .../lib/appframework/http/DownloadResponseTest.php | 51 ++ tests/lib/appframework/http/HttpTest.php | 87 ++++ tests/lib/appframework/http/JSONResponseTest.php | 96 ++++ .../lib/appframework/http/RedirectResponseTest.php | 55 +++ tests/lib/appframework/http/RequestTest.php | 78 +++ tests/lib/appframework/http/ResponseTest.php | 119 +++++ .../lib/appframework/http/TemplateResponseTest.php | 157 ++++++ .../middleware/MiddlewareDispatcherTest.php | 280 +++++++++++ .../lib/appframework/middleware/MiddlewareTest.php | 82 ++++ .../middleware/security/SecurityMiddlewareTest.php | 388 +++++++++++++++ tests/lib/appframework/routing/RoutingTest.php | 214 +++++++++ .../utility/MethodAnnotationReaderTest.php | 58 +++ 37 files changed, 4963 insertions(+) create mode 100644 lib/appframework/app.php create mode 100644 lib/appframework/controller/controller.php create mode 100644 lib/appframework/core/api.php create mode 100644 lib/appframework/dependencyinjection/dicontainer.php create mode 100644 lib/appframework/http/dispatcher.php create mode 100644 lib/appframework/http/downloadresponse.php create mode 100644 lib/appframework/http/http.php create mode 100644 lib/appframework/http/jsonresponse.php create mode 100644 lib/appframework/http/redirectresponse.php create mode 100644 lib/appframework/http/request.php create mode 100644 lib/appframework/http/response.php create mode 100644 lib/appframework/http/templateresponse.php create mode 100644 lib/appframework/middleware/middleware.php create mode 100644 lib/appframework/middleware/middlewaredispatcher.php create mode 100644 lib/appframework/middleware/security/securityexception.php create mode 100644 lib/appframework/middleware/security/securitymiddleware.php create mode 100644 lib/appframework/routing/routeactionhandler.php create mode 100644 lib/appframework/routing/routeconfig.php create mode 100644 lib/appframework/utility/methodannotationreader.php create mode 100644 lib/appframework/utility/timefactory.php create mode 100644 tests/lib/appframework/AppTest.php create mode 100644 tests/lib/appframework/classloader.php create mode 100644 tests/lib/appframework/controller/ControllerTest.php create mode 100644 tests/lib/appframework/dependencyinjection/DIContainerTest.php create mode 100644 tests/lib/appframework/http/DispatcherTest.php create mode 100644 tests/lib/appframework/http/DownloadResponseTest.php create mode 100644 tests/lib/appframework/http/HttpTest.php create mode 100644 tests/lib/appframework/http/JSONResponseTest.php create mode 100644 tests/lib/appframework/http/RedirectResponseTest.php create mode 100644 tests/lib/appframework/http/RequestTest.php create mode 100644 tests/lib/appframework/http/ResponseTest.php create mode 100644 tests/lib/appframework/http/TemplateResponseTest.php create mode 100644 tests/lib/appframework/middleware/MiddlewareDispatcherTest.php create mode 100644 tests/lib/appframework/middleware/MiddlewareTest.php create mode 100644 tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php create mode 100644 tests/lib/appframework/routing/RoutingTest.php create mode 100644 tests/lib/appframework/utility/MethodAnnotationReaderTest.php diff --git a/lib/appframework/app.php b/lib/appframework/app.php new file mode 100644 index 00000000000..6224b858bbf --- /dev/null +++ b/lib/appframework/app.php @@ -0,0 +1,97 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\DependencyInjection\DIContainer; + + +/** + * Entry point for every request in your app. You can consider this as your + * public static void main() method + * + * Handles all the dependency injection, controllers and output flow + */ +class App { + + + /** + * Shortcut for calling a controller method and printing the result + * @param string $controllerName the name of the controller under which it is + * stored in the DI container + * @param string $methodName the method that you want to call + * @param array $urlParams an array with variables extracted from the routes + * @param DIContainer $container an instance of a pimple container. + */ + public static function main($controllerName, $methodName, array $urlParams, + DIContainer $container) { + $container['urlParams'] = $urlParams; + $controller = $container[$controllerName]; + + // initialize the dispatcher and run all the middleware before the controller + $dispatcher = $container['Dispatcher']; + + list($httpHeaders, $responseHeaders, $output) = + $dispatcher->dispatch($controller, $methodName); + + if(!is_null($httpHeaders)) { + header($httpHeaders); + } + + foreach($responseHeaders as $name => $value) { + header($name . ': ' . $value); + } + + if(!is_null($output)) { + header('Content-Length: ' . strlen($output)); + print($output); + } + + } + + /** + * Shortcut for calling a controller method and printing the result. + * Similar to App:main except that no headers will be sent. + * This should be used for example when registering sections via + * \OC\AppFramework\Core\API::registerAdmin() + * + * @param string $controllerName the name of the controller under which it is + * stored in the DI container + * @param string $methodName the method that you want to call + * @param array $urlParams an array with variables extracted from the routes + * @param DIContainer $container an instance of a pimple container. + */ + public static function part($controllerName, $methodName, array $urlParams, + DIContainer $container){ + + $container['urlParams'] = $urlParams; + $controller = $container[$controllerName]; + + $dispatcher = $container['Dispatcher']; + + list(, , $output) = $dispatcher->dispatch($controller, $methodName); + return $output; + } + +} diff --git a/lib/appframework/controller/controller.php b/lib/appframework/controller/controller.php new file mode 100644 index 00000000000..3e8166050d7 --- /dev/null +++ b/lib/appframework/controller/controller.php @@ -0,0 +1,154 @@ +. + * + */ + + +namespace OC\AppFramework\Controller; + +use OC\AppFramework\Http\TemplateResponse; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Core\API; + + +/** + * Base class to inherit your controllers from + */ +abstract class Controller { + + /** + * @var API instance of the api layer + */ + protected $api; + + protected $request; + + /** + * @param API $api an api wrapper instance + * @param Request $request an instance of the request + */ + public function __construct(API $api, Request $request){ + $this->api = $api; + $this->request = $request; + } + + + /** + * Lets you access post and get parameters by the index + * @param string $key the key which you want to access in the URL Parameter + * placeholder, $_POST or $_GET array. + * The priority how they're returned is the following: + * 1. URL parameters + * 2. POST parameters + * 3. GET parameters + * @param mixed $default If the key is not found, this value will be returned + * @return mixed the content of the array + */ + public function params($key, $default=null){ + return isset($this->request->parameters[$key]) + ? $this->request->parameters[$key] + : $default; + } + + + /** + * Returns all params that were received, be it from the request + * (as GET or POST) or throuh the URL by the route + * @return array the array with all parameters + */ + public function getParams() { + return $this->request->parameters; + } + + + /** + * Returns the method of the request + * @return string the method of the request (POST, GET, etc) + */ + public function method() { + return $this->request->method; + } + + + /** + * Shortcut for accessing an uploaded file through the $_FILES array + * @param string $key the key that will be taken from the $_FILES array + * @return array the file in the $_FILES element + */ + public function getUploadedFile($key) { + return isset($this->request->files[$key]) ? $this->request->files[$key] : null; + } + + + /** + * Shortcut for getting env variables + * @param string $key the key that will be taken from the $_ENV array + * @return array the value in the $_ENV element + */ + public function env($key) { + return isset($this->request->env[$key]) ? $this->request->env[$key] : null; + } + + + /** + * Shortcut for getting session variables + * @param string $key the key that will be taken from the $_SESSION array + * @return array the value in the $_SESSION element + */ + public function session($key) { + return isset($this->request->session[$key]) ? $this->request->session[$key] : null; + } + + + /** + * Shortcut for getting cookie variables + * @param string $key the key that will be taken from the $_COOKIE array + * @return array the value in the $_COOKIE element + */ + public function cookie($key) { + return isset($this->request->cookies[$key]) ? $this->request->cookies[$key] : null; + } + + + /** + * Shortcut for rendering a template + * @param string $templateName the name of the template + * @param array $params the template parameters in key => value structure + * @param string $renderAs user renders a full page, blank only your template + * admin an entry in the admin settings + * @param array $headers set additional headers in name/value pairs + * @return \OC\AppFramework\Http\TemplateResponse containing the page + */ + public function render($templateName, array $params=array(), + $renderAs='user', array $headers=array()){ + $response = new TemplateResponse($this->api, $templateName); + $response->setParams($params); + $response->renderAs($renderAs); + + foreach($headers as $name => $value){ + $response->addHeader($name, $value); + } + + return $response; + } + + +} diff --git a/lib/appframework/core/api.php b/lib/appframework/core/api.php new file mode 100644 index 00000000000..eb8ee01e5db --- /dev/null +++ b/lib/appframework/core/api.php @@ -0,0 +1,524 @@ +. + * + */ + + +namespace OC\AppFramework\Core; + + +/** + * This is used to wrap the owncloud static api calls into an object to make the + * code better abstractable for use in the dependency injection container + * + * Should you find yourself in need for more methods, simply inherit from this + * class and add your methods + */ +class API { + + private $appName; + + /** + * constructor + * @param string $appName the name of your application + */ + public function __construct($appName){ + $this->appName = $appName; + } + + + /** + * used to return the appname of the set application + * @return string the name of your application + */ + public function getAppName(){ + return $this->appName; + } + + + /** + * Creates a new navigation entry + * @param array $entry containing: id, name, order, icon and href key + */ + public function addNavigationEntry(array $entry){ + \OCP\App::addNavigationEntry($entry); + } + + + /** + * Gets the userid of the current user + * @return string the user id of the current user + */ + public function getUserId(){ + return \OCP\User::getUser(); + } + + + /** + * Sets the current navigation entry to the currently running app + */ + public function activateNavigationEntry(){ + \OCP\App::setActiveNavigationEntry($this->appName); + } + + + /** + * Adds a new javascript file + * @param string $scriptName the name of the javascript in js/ without the suffix + * @param string $appName the name of the app, defaults to the current one + */ + public function addScript($scriptName, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + \OCP\Util::addScript($appName, $scriptName); + } + + + /** + * Adds a new css file + * @param string $styleName the name of the css file in css/without the suffix + * @param string $appName the name of the app, defaults to the current one + */ + public function addStyle($styleName, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + \OCP\Util::addStyle($appName, $styleName); + } + + + /** + * shorthand for addScript for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + */ + public function add3rdPartyScript($name){ + \OCP\Util::addScript($this->appName . '/3rdparty', $name); + } + + + /** + * shorthand for addStyle for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + */ + public function add3rdPartyStyle($name){ + \OCP\Util::addStyle($this->appName . '/3rdparty', $name); + } + + /** + * Looks up a systemwide defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getSystemValue($key){ + return \OCP\Config::getSystemValue($key, ''); + } + + + /** + * Sets a new systemwide value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + */ + public function setSystemValue($key, $value){ + return \OCP\Config::setSystemValue($key, $value); + } + + + /** + * Looks up an appwide defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getAppValue($key, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Config::getAppValue($appName, $key, ''); + } + + + /** + * Writes a new appwide value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + */ + public function setAppValue($key, $value, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Config::setAppValue($appName, $key, $value); + } + + + + /** + * Shortcut for setting a user defined value + * @param string $key the key under which the value is being stored + * @param string $value the value that you want to store + * @param string $userId the userId of the user that we want to store the value under, defaults to the current one + */ + public function setUserValue($key, $value, $userId=null){ + if($userId === null){ + $userId = $this->getUserId(); + } + \OCP\Config::setUserValue($userId, $this->appName, $key, $value); + } + + + /** + * Shortcut for getting a user defined value + * @param string $key the key under which the value is being stored + * @param string $userId the userId of the user that we want to store the value under, defaults to the current one + */ + public function getUserValue($key, $userId=null){ + if($userId === null){ + $userId = $this->getUserId(); + } + return \OCP\Config::getUserValue($userId, $this->appName, $key); + } + + + /** + * Returns the translation object + * @return \OC_L10N the translation object + */ + public function getTrans(){ + # TODO: use public api + return \OC_L10N::get($this->appName); + } + + + /** + * Used to abstract the owncloud database access away + * @param string $sql the sql query with ? placeholder for params + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @return \OCP\DB a query object + */ + public function prepareQuery($sql, $limit=null, $offset=null){ + return \OCP\DB::prepare($sql, $limit, $offset); + } + + + /** + * Used to get the id of the just inserted element + * @param string $tableName the name of the table where we inserted the item + * @return int the id of the inserted element + */ + public function getInsertId($tableName){ + return \OCP\DB::insertid($tableName); + } + + + /** + * Returns the URL for a route + * @param string $routeName the name of the route + * @param array $arguments an array with arguments which will be filled into the url + * @return string the url + */ + public function linkToRoute($routeName, $arguments=array()){ + return \OCP\Util::linkToRoute($routeName, $arguments); + } + + + /** + * Returns an URL for an image or file + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + */ + public function linkTo($file, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Util::linkTo($appName, $file); + } + + + /** + * Returns the link to an image, like link to but only with prepending img/ + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + */ + public function imagePath($file, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Util::imagePath($appName, $file); + } + + + /** + * Makes an URL absolute + * @param string $url the url + * @return string the absolute url + */ + public function getAbsoluteURL($url){ + # TODO: use public api + return \OC_Helper::makeURLAbsolute($url); + } + + + /** + * links to a file + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + * @deprecated replaced with linkToRoute() + * @return string the url + */ + public function linkToAbsolute($file, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Util::linkToAbsolute($appName, $file); + } + + + /** + * Checks if the current user is logged in + * @return bool true if logged in + */ + public function isLoggedIn(){ + return \OCP\User::isLoggedIn(); + } + + + /** + * Checks if a user is an admin + * @param string $userId the id of the user + * @return bool true if admin + */ + public function isAdminUser($userId){ + # TODO: use public api + return \OC_User::isAdminUser($userId); + } + + + /** + * Checks if a user is an subadmin + * @param string $userId the id of the user + * @return bool true if subadmin + */ + public function isSubAdminUser($userId){ + # TODO: use public api + return \OC_SubAdmin::isSubAdmin($userId); + } + + + /** + * Checks if the CSRF check was correct + * @return bool true if CSRF check passed + */ + public function passesCSRFCheck(){ + # TODO: use public api + return \OC_Util::isCallRegistered(); + } + + + /** + * Checks if an app is enabled + * @param string $appName the name of an app + * @return bool true if app is enabled + */ + public function isAppEnabled($appName){ + return \OCP\App::isEnabled($appName); + } + + + /** + * Writes a function into the error log + * @param string $msg the error message to be logged + * @param int $level the error level + */ + public function log($msg, $level=null){ + switch($level){ + case 'debug': + $level = \OCP\Util::DEBUG; + break; + case 'info': + $level = \OCP\Util::INFO; + break; + case 'warn': + $level = \OCP\Util::WARN; + break; + case 'fatal': + $level = \OCP\Util::FATAL; + break; + default: + $level = \OCP\Util::ERROR; + break; + } + \OCP\Util::writeLog($this->appName, $msg, $level); + } + + + /** + * Returns a template + * @param string $templateName the name of the template + * @param string $renderAs how it should be rendered + * @param string $appName the name of the app + * @return \OCP\Template a new template + */ + public function getTemplate($templateName, $renderAs='user', $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + + if($renderAs === 'blank'){ + return new \OCP\Template($appName, $templateName); + } else { + return new \OCP\Template($appName, $templateName, $renderAs); + } + } + + + /** + * turns an owncloud path into a path on the filesystem + * @param string path the path to the file on the oc filesystem + * @return string the filepath in the filesystem + */ + public function getLocalFilePath($path){ + # TODO: use public api + return \OC_Filesystem::getLocalFile($path); + } + + + /** + * used to return and open a new eventsource + * @return \OC_EventSource a new open EventSource class + */ + public function openEventSource(){ + # TODO: use public api + return new \OC_EventSource(); + } + + /** + * @brief connects a function to a hook + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param string $slotClass class name of slot + * @param string $slotName name of slot, in another word, this is the + * name of the method that will be called when registered + * signal is emitted. + * @return bool, always true + */ + public function connectHook($signalClass, $signalName, $slotClass, $slotName) { + return \OCP\Util::connectHook($signalClass, $signalName, $slotClass, $slotName); + } + + /** + * @brief Emits a signal. To get data from the slot use references! + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param array $params defautl: array() array with additional data + * @return bool, true if slots exists or false if not + */ + public function emitHook($signalClass, $signalName, $params = array()) { + return \OCP\Util::emitHook($signalClass, $signalName, $params); + } + + /** + * @brief clear hooks + * @param string $signalClass + * @param string $signalName + */ + public function clearHook($signalClass=false, $signalName=false) { + if ($signalClass) { + \OC_Hook::clear($signalClass, $signalName); + } + } + + /** + * Gets the content of an URL by using CURL or a fallback if it is not + * installed + * @param string $url the url that should be fetched + * @return string the content of the webpage + */ + public function getUrlContent($url) { + return \OC_Util::getUrlContent($url); + } + + /** + * Register a backgroundjob task + * @param string $className full namespace and class name of the class + * @param string $methodName the name of the static method that should be + * called + */ + public function addRegularTask($className, $methodName) { + \OCP\Backgroundjob::addRegularTask($className, $methodName); + } + + /** + * Tells ownCloud to include a template in the admin overview + * @param string $mainPath the path to the main php file without the php + * suffix, relative to your apps directory! not the template directory + * @param string $appName the name of the app, defaults to the current one + */ + public function registerAdmin($mainPath, $appName=null) { + if($appName === null){ + $appName = $this->appName; + } + + \OCP\App::registerAdmin($appName, $mainPath); + } + + /** + * Do a user login + * @param string $user the username + * @param string $password the password + * @return bool true if successful + */ + public function login($user, $password) { + return \OC_User::login($user, $password); + } + + /** + * @brief Loggs the user out including all the session data + * Logout, destroys session + */ + public function logout() { + return \OCP\User::logout(); + } + + /** + * get the filesystem info + * + * @param string $path + * @return array with the following keys: + * - size + * - mtime + * - mimetype + * - encrypted + * - versioned + */ + public function getFileInfo($path) { + return \OC\Files\Filesystem::getFileInfo($path); + } + + /** + * get the view + * + * @return OC\Files\View instance + */ + public function getView() { + return \OC\Files\Filesystem::getView(); + } +} diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php new file mode 100644 index 00000000000..34f64e72cb9 --- /dev/null +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -0,0 +1,125 @@ +. + * + */ + + +namespace OC\AppFramework\DependencyInjection; + +use OC\AppFramework\Http\Http; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\Dispatcher; +use OC\AppFramework\Core\API; +use OC\AppFramework\Middleware\MiddlewareDispatcher; +use OC\AppFramework\Middleware\Http\HttpMiddleware; +use OC\AppFramework\Middleware\Security\SecurityMiddleware; +use OC\AppFramework\Utility\TimeFactory; + +// register 3rdparty autoloaders +require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; + + +/** + * This class extends Pimple (http://pimple.sensiolabs.org/) for reusability + * To use this class, extend your own container from this. Should you require it + * you can overwrite the dependencies with your own classes by simply redefining + * a dependency + */ +class DIContainer extends \Pimple { + + + /** + * Put your class dependencies in here + * @param string $appName the name of the app + */ + public function __construct($appName){ + + $this['AppName'] = $appName; + + $this['API'] = $this->share(function($c){ + return new API($c['AppName']); + }); + + /** + * Http + */ + $this['Request'] = $this->share(function($c) { + $params = json_decode(file_get_contents('php://input'), true); + $params = is_array($params) ? $params: array(); + + return new Request( + array( + 'get' => $_GET, + 'post' => $_POST, + 'files' => $_FILES, + 'server' => $_SERVER, + 'env' => $_ENV, + 'session' => $_SESSION, + 'cookies' => $_COOKIE, + 'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) + ? $_SERVER['REQUEST_METHOD'] + : null, + 'params' => $params, + 'urlParams' => $c['urlParams'] + ) + ); + }); + + $this['Protocol'] = $this->share(function($c){ + if(isset($_SERVER['SERVER_PROTOCOL'])) { + return new Http($_SERVER, $_SERVER['SERVER_PROTOCOL']); + } else { + return new Http($_SERVER); + } + }); + + $this['Dispatcher'] = $this->share(function($c) { + return new Dispatcher($c['Protocol'], $c['MiddlewareDispatcher']); + }); + + + /** + * Middleware + */ + $this['SecurityMiddleware'] = $this->share(function($c){ + return new SecurityMiddleware($c['API'], $c['Request']); + }); + + $this['MiddlewareDispatcher'] = $this->share(function($c){ + $dispatcher = new MiddlewareDispatcher(); + $dispatcher->registerMiddleware($c['SecurityMiddleware']); + + return $dispatcher; + }); + + + /** + * Utilities + */ + $this['TimeFactory'] = $this->share(function($c){ + return new TimeFactory(); + }); + + + } + + +} diff --git a/lib/appframework/http/dispatcher.php b/lib/appframework/http/dispatcher.php new file mode 100644 index 00000000000..ab5644274fa --- /dev/null +++ b/lib/appframework/http/dispatcher.php @@ -0,0 +1,98 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use \OC\AppFramework\Controller\Controller; +use \OC\AppFramework\Middleware\MiddlewareDispatcher; + + +/** + * Class to dispatch the request to the middleware disptacher + */ +class Dispatcher { + + private $middlewareDispatcher; + private $protocol; + + + /** + * @param Http $protocol the http protocol with contains all status headers + * @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which + * runs the middleware + */ + public function __construct(Http $protocol, + MiddlewareDispatcher $middlewareDispatcher) { + $this->protocol = $protocol; + $this->middlewareDispatcher = $middlewareDispatcher; + } + + + /** + * Handles a request and calls the dispatcher on the controller + * @param Controller $controller the controller which will be called + * @param string $methodName the method name which will be called on + * the controller + * @return array $array[0] contains a string with the http main header, + * $array[1] contains headers in the form: $key => value, $array[2] contains + * the response output + */ + public function dispatch(Controller $controller, $methodName) { + $out = array(null, array(), null); + + try { + + $this->middlewareDispatcher->beforeController($controller, + $methodName); + $response = $controller->$methodName(); + + + // if an exception appears, the middleware checks if it can handle the + // exception and creates a response. If no response is created, it is + // assumed that theres no middleware who can handle it and the error is + // thrown again + } catch(\Exception $exception){ + $response = $this->middlewareDispatcher->afterException( + $controller, $methodName, $exception); + } + + $response = $this->middlewareDispatcher->afterController( + $controller, $methodName, $response); + + // get the output which should be printed and run the after output + // middleware to modify the response + $output = $response->render(); + $out[2] = $this->middlewareDispatcher->beforeOutput( + $controller, $methodName, $output); + + // depending on the cache object the headers need to be changed + $out[0] = $this->protocol->getStatusHeader($response->getStatus(), + $response->getLastModified(), $response->getETag()); + $out[1] = $response->getHeaders(); + + return $out; + } + + +} diff --git a/lib/appframework/http/downloadresponse.php b/lib/appframework/http/downloadresponse.php new file mode 100644 index 00000000000..5a0db325fe6 --- /dev/null +++ b/lib/appframework/http/downloadresponse.php @@ -0,0 +1,51 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +/** + * Prompts the user to download the a file + */ +abstract class DownloadResponse extends Response { + + private $content; + private $filename; + private $contentType; + + /** + * Creates a response that prompts the user to download the file + * @param string $filename the name that the downloaded file should have + * @param string $contentType the mimetype that the downloaded file should have + */ + public function __construct($filename, $contentType) { + $this->filename = $filename; + $this->contentType = $contentType; + + $this->addHeader('Content-Disposition', 'attachment; filename="' . $filename . '"'); + $this->addHeader('Content-Type', $contentType); + } + + +} diff --git a/lib/appframework/http/http.php b/lib/appframework/http/http.php new file mode 100644 index 00000000000..73f32d13b38 --- /dev/null +++ b/lib/appframework/http/http.php @@ -0,0 +1,208 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +class Http { + + const STATUS_CONTINUE = 100; + const STATUS_SWITCHING_PROTOCOLS = 101; + const STATUS_PROCESSING = 102; + const STATUS_OK = 200; + const STATUS_CREATED = 201; + const STATUS_ACCEPTED = 202; + const STATUS_NON_AUTHORATIVE_INFORMATION = 203; + const STATUS_NO_CONTENT = 204; + const STATUS_RESET_CONTENT = 205; + const STATUS_PARTIAL_CONTENT = 206; + const STATUS_MULTI_STATUS = 207; + const STATUS_ALREADY_REPORTED = 208; + const STATUS_IM_USED = 226; + const STATUS_MULTIPLE_CHOICES = 300; + const STATUS_MOVED_PERMANENTLY = 301; + const STATUS_FOUND = 302; + const STATUS_SEE_OTHER = 303; + const STATUS_NOT_MODIFIED = 304; + const STATUS_USE_PROXY = 305; + const STATUS_RESERVED = 306; + const STATUS_TEMPORARY_REDIRECT = 307; + const STATUS_BAD_REQUEST = 400; + const STATUS_UNAUTHORIZED = 401; + const STATUS_PAYMENT_REQUIRED = 402; + const STATUS_FORBIDDEN = 403; + const STATUS_NOT_FOUND = 404; + const STATUS_METHOD_NOT_ALLOWED = 405; + const STATUS_NOT_ACCEPTABLE = 406; + const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; + const STATUS_REQUEST_TIMEOUT = 408; + const STATUS_CONFLICT = 409; + const STATUS_GONE = 410; + const STATUS_LENGTH_REQUIRED = 411; + const STATUS_PRECONDITION_FAILED = 412; + const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; + const STATUS_REQUEST_URI_TOO_LONG = 414; + const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; + const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416; + const STATUS_EXPECTATION_FAILED = 417; + const STATUS_IM_A_TEAPOT = 418; + const STATUS_UNPROCESSABLE_ENTITY = 422; + const STATUS_LOCKED = 423; + const STATUS_FAILED_DEPENDENCY = 424; + const STATUS_UPGRADE_REQUIRED = 426; + const STATUS_PRECONDITION_REQUIRED = 428; + const STATUS_TOO_MANY_REQUESTS = 429; + const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; + const STATUS_INTERNAL_SERVER_ERROR = 500; + const STATUS_NOT_IMPLEMENTED = 501; + const STATUS_BAD_GATEWAY = 502; + const STATUS_SERVICE_UNAVAILABLE = 503; + const STATUS_GATEWAY_TIMEOUT = 504; + const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505; + const STATUS_VARIANT_ALSO_NEGOTIATES = 506; + const STATUS_INSUFFICIENT_STORAGE = 507; + const STATUS_LOOP_DETECTED = 508; + const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509; + const STATUS_NOT_EXTENDED = 510; + const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; + + private $server; + private $protocolVersion; + protected $headers; + + /** + * @param $_SERVER $server + * @param string $protocolVersion the http version to use defaults to HTTP/1.1 + */ + public function __construct($server, $protocolVersion='HTTP/1.1') { + $this->server = $server; + $this->protocolVersion = $protocolVersion; + + $this->headers = array( + self::STATUS_CONTINUE => 'Continue', + self::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols', + self::STATUS_PROCESSING => 'Processing', + self::STATUS_OK => 'OK', + self::STATUS_CREATED => 'Created', + self::STATUS_ACCEPTED => 'Accepted', + self::STATUS_NON_AUTHORATIVE_INFORMATION => 'Non-Authorative Information', + self::STATUS_NO_CONTENT => 'No Content', + self::STATUS_RESET_CONTENT => 'Reset Content', + self::STATUS_PARTIAL_CONTENT => 'Partial Content', + self::STATUS_MULTI_STATUS => 'Multi-Status', // RFC 4918 + self::STATUS_ALREADY_REPORTED => 'Already Reported', // RFC 5842 + self::STATUS_IM_USED => 'IM Used', // RFC 3229 + self::STATUS_MULTIPLE_CHOICES => 'Multiple Choices', + self::STATUS_MOVED_PERMANENTLY => 'Moved Permanently', + self::STATUS_FOUND => 'Found', + self::STATUS_SEE_OTHER => 'See Other', + self::STATUS_NOT_MODIFIED => 'Not Modified', + self::STATUS_USE_PROXY => 'Use Proxy', + self::STATUS_RESERVED => 'Reserved', + self::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect', + self::STATUS_BAD_REQUEST => 'Bad request', + self::STATUS_UNAUTHORIZED => 'Unauthorized', + self::STATUS_PAYMENT_REQUIRED => 'Payment Required', + self::STATUS_FORBIDDEN => 'Forbidden', + self::STATUS_NOT_FOUND => 'Not Found', + self::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed', + self::STATUS_NOT_ACCEPTABLE => 'Not Acceptable', + self::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required', + self::STATUS_REQUEST_TIMEOUT => 'Request Timeout', + self::STATUS_CONFLICT => 'Conflict', + self::STATUS_GONE => 'Gone', + self::STATUS_LENGTH_REQUIRED => 'Length Required', + self::STATUS_PRECONDITION_FAILED => 'Precondition failed', + self::STATUS_REQUEST_ENTITY_TOO_LARGE => 'Request Entity Too Large', + self::STATUS_REQUEST_URI_TOO_LONG => 'Request-URI Too Long', + self::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type', + self::STATUS_REQUEST_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable', + self::STATUS_EXPECTATION_FAILED => 'Expectation Failed', + self::STATUS_IM_A_TEAPOT => 'I\'m a teapot', // RFC 2324 + self::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', // RFC 4918 + self::STATUS_LOCKED => 'Locked', // RFC 4918 + self::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', // RFC 4918 + self::STATUS_UPGRADE_REQUIRED => 'Upgrade required', + self::STATUS_PRECONDITION_REQUIRED => 'Precondition required', // draft-nottingham-http-new-status + self::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', // draft-nottingham-http-new-status + self::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', // draft-nottingham-http-new-status + self::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error', + self::STATUS_NOT_IMPLEMENTED => 'Not Implemented', + self::STATUS_BAD_GATEWAY => 'Bad Gateway', + self::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable', + self::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout', + self::STATUS_HTTP_VERSION_NOT_SUPPORTED => 'HTTP Version not supported', + self::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates', + self::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', // RFC 4918 + self::STATUS_LOOP_DETECTED => 'Loop Detected', // RFC 5842 + self::STATUS_BANDWIDTH_LIMIT_EXCEEDED => 'Bandwidth Limit Exceeded', // non-standard + self::STATUS_NOT_EXTENDED => 'Not extended', + self::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', // draft-nottingham-http-new-status + ); + } + + + /** + * Gets the correct header + * @param Http::CONSTANT $status the constant from the Http class + * @param \DateTime $lastModified formatted last modified date + * @param string $Etag the etag + */ + public function getStatusHeader($status, \DateTime $lastModified=null, + $ETag=null) { + + if(!is_null($lastModified)) { + $lastModified = $lastModified->format(\DateTime::RFC2822); + } + + // if etag or lastmodified have not changed, return a not modified + if ((isset($this->server['HTTP_IF_NONE_MATCH']) + && trim($this->server['HTTP_IF_NONE_MATCH']) === $ETag) + + || + + (isset($this->server['HTTP_IF_MODIFIED_SINCE']) + && trim($this->server['HTTP_IF_MODIFIED_SINCE']) === + $lastModified)) { + + $status = self::STATUS_NOT_MODIFIED; + } + + // we have one change currently for the http 1.0 header that differs + // from 1.1: STATUS_TEMPORARY_REDIRECT should be STATUS_FOUND + // if this differs any more, we want to create childclasses for this + if($status === self::STATUS_TEMPORARY_REDIRECT + && $this->protocolVersion === 'HTTP/1.0') { + + $status = self::STATUS_FOUND; + } + + return $this->protocolVersion . ' ' . $status . ' ' . + $this->headers[$status]; + } + + +} + + diff --git a/lib/appframework/http/jsonresponse.php b/lib/appframework/http/jsonresponse.php new file mode 100644 index 00000000000..750f8a2ad15 --- /dev/null +++ b/lib/appframework/http/jsonresponse.php @@ -0,0 +1,74 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +/** + * A renderer for JSON calls + */ +class JSONResponse extends Response { + + protected $data; + + + /** + * @param array|object $data the object or array that should be transformed + * @param int $statusCode the Http status code, defaults to 200 + */ + public function __construct($data=array(), $statusCode=Http::STATUS_OK) { + $this->data = $data; + $this->setStatus($statusCode); + $this->addHeader('X-Content-Type-Options', 'nosniff'); + $this->addHeader('Content-type', 'application/json; charset=utf-8'); + } + + + /** + * Returns the rendered json + * @return string the rendered json + */ + public function render(){ + return json_encode($this->data); + } + + /** + * Sets values in the data json array + * @param array|object $params an array or object which will be transformed + * to JSON + */ + public function setData($data){ + $this->data = $data; + } + + + /** + * Used to get the set parameters + * @return array the data + */ + public function getData(){ + return $this->data; + } + +} diff --git a/lib/appframework/http/redirectresponse.php b/lib/appframework/http/redirectresponse.php new file mode 100644 index 00000000000..727e0fb642e --- /dev/null +++ b/lib/appframework/http/redirectresponse.php @@ -0,0 +1,54 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +/** + * Redirects to a different URL + */ +class RedirectResponse extends Response { + + private $redirectURL; + + /** + * Creates a response that redirects to a url + * @param string $redirectURL the url to redirect to + */ + public function __construct($redirectURL) { + $this->redirectURL = $redirectURL; + $this->setStatus(Http::STATUS_TEMPORARY_REDIRECT); + $this->addHeader('Location', $redirectURL); + } + + + /** + * @return string the url to redirect + */ + public function getRedirectURL() { + return $this->redirectURL; + } + + +} diff --git a/lib/appframework/http/request.php b/lib/appframework/http/request.php new file mode 100644 index 00000000000..7d024c8605f --- /dev/null +++ b/lib/appframework/http/request.php @@ -0,0 +1,217 @@ +. + * + */ + +namespace OC\AppFramework\Http; + +/** + * Class for accessing variables in the request. + * This class provides an immutable object with request variables. + */ + +class Request implements \ArrayAccess, \Countable { + + protected $items = array(); + protected $allowedKeys = array( + 'get', + 'post', + 'files', + 'server', + 'env', + 'session', + 'cookies', + 'urlParams', + 'params', + 'parameters', + 'method' + ); + + /** + * @param array $vars An associative array with the following optional values: + * @param array 'params' the parsed json array + * @param array 'urlParams' the parameters which were matched from the URL + * @param array 'get' the $_GET array + * @param array 'post' the $_POST array + * @param array 'files' the $_FILES array + * @param array 'server' the $_SERVER array + * @param array 'env' the $_ENV array + * @param array 'session' the $_SESSION array + * @param array 'cookies' the $_COOKIE array + * @param string 'method' the request method (GET, POST etc) + * @see http://www.php.net/manual/en/reserved.variables.php + */ + public function __construct(array $vars=array()) { + + foreach($this->allowedKeys as $name) { + $this->items[$name] = isset($vars[$name]) + ? $vars[$name] + : array(); + } + + $this->items['parameters'] = array_merge( + $this->items['params'], + $this->items['get'], + $this->items['post'], + $this->items['urlParams'] + ); + + } + + // Countable method. + public function count() { + return count(array_keys($this->items['parameters'])); + } + + /** + * ArrayAccess methods + * + * Gives access to the combined GET, POST and urlParams arrays + * + * Examples: + * + * $var = $request['myvar']; + * + * or + * + * if(!isset($request['myvar']) { + * // Do something + * } + * + * $request['myvar'] = 'something'; // This throws an exception. + * + * @param string $offset The key to lookup + * @return string|null + */ + public function offsetExists($offset) { + return isset($this->items['parameters'][$offset]); + } + + /** + * @see offsetExists + */ + public function offsetGet($offset) { + return isset($this->items['parameters'][$offset]) + ? $this->items['parameters'][$offset] + : null; + } + + /** + * @see offsetExists + */ + public function offsetSet($offset, $value) { + throw new \RuntimeException('You cannot change the contents of the request object'); + } + + /** + * @see offsetExists + */ + public function offsetUnset($offset) { + throw new \RuntimeException('You cannot change the contents of the request object'); + } + + // Magic property accessors + public function __set($name, $value) { + throw new \RuntimeException('You cannot change the contents of the request object'); + } + + /** + * Access request variables by method and name. + * Examples: + * + * $request->post['myvar']; // Only look for POST variables + * $request->myvar; or $request->{'myvar'}; or $request->{$myvar} + * Looks in the combined GET, POST and urlParams array. + * + * if($request->method !== 'POST') { + * throw new Exception('This function can only be invoked using POST'); + * } + * + * @param string $name The key to look for. + * @return mixed|null + */ + public function __get($name) { + switch($name) { + case 'get': + case 'post': + case 'files': + case 'server': + case 'env': + case 'session': + case 'cookies': + case 'parameters': + case 'params': + case 'urlParams': + return isset($this->items[$name]) + ? $this->items[$name] + : null; + break; + case 'method': + return $this->items['method']; + break; + default; + return isset($this[$name]) + ? $this[$name] + : null; + break; + } + } + + + public function __isset($name) { + return isset($this->items['parameters'][$name]); + } + + + public function __unset($id) { + throw new \RunTimeException('You cannot change the contents of the request object'); + } + + /** + * Returns the value for a specific http header. + * + * This method returns null if the header did not exist. + * + * @param string $name + * @return string + */ + public function getHeader($name) { + + $name = strtoupper(str_replace(array('-'),array('_'),$name)); + if (isset($this->server['HTTP_' . $name])) { + return $this->server['HTTP_' . $name]; + } + + // There's a few headers that seem to end up in the top-level + // server array. + switch($name) { + case 'CONTENT_TYPE' : + case 'CONTENT_LENGTH' : + if (isset($this->server[$name])) { + return $this->server[$name]; + } + break; + + } + + return null; + } + +} diff --git a/lib/appframework/http/response.php b/lib/appframework/http/response.php new file mode 100644 index 00000000000..50778105f24 --- /dev/null +++ b/lib/appframework/http/response.php @@ -0,0 +1,169 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +/** + * Base class for responses. Also used to just send headers + */ +class Response { + + /** + * @var array default headers + */ + private $headers = array( + 'Cache-Control' => 'no-cache, must-revalidate' + ); + + + /** + * @var string + */ + private $status = Http::STATUS_OK; + + + /** + * @var \DateTime + */ + private $lastModified; + + + /** + * @var string + */ + private $ETag; + + + /** + * Caches the response + * @param int $cacheSeconds the amount of seconds that should be cached + * if 0 then caching will be disabled + */ + public function cacheFor($cacheSeconds) { + + if($cacheSeconds > 0) { + $this->addHeader('Cache-Control', 'max-age=' . $cacheSeconds . + ', must-revalidate'); + } else { + $this->addHeader('Cache-Control', 'no-cache, must-revalidate'); + } + + } + + + /** + * Adds a new header to the response that will be called before the render + * function + * @param string $name The name of the HTTP header + * @param string $value The value, null will delete it + */ + public function addHeader($name, $value) { + if(is_null($value)) { + unset($this->headers[$name]); + } else { + $this->headers[$name] = $value; + } + } + + + /** + * Returns the set headers + * @return array the headers + */ + public function getHeaders() { + $mergeWith = array(); + + if($this->lastModified) { + $mergeWith['Last-Modified'] = + $this->lastModified->format(\DateTime::RFC2822); + } + + if($this->ETag) { + $mergeWith['ETag'] = '"' . $this->ETag . '"'; + } + + return array_merge($mergeWith, $this->headers); + } + + + /** + * By default renders no output + * @return null + */ + public function render() { + return null; + } + + + /** + * Set response status + * @param int $status a HTTP status code, see also the STATUS constants + */ + public function setStatus($status) { + $this->status = $status; + } + + + /** + * Get response status + */ + public function getStatus() { + return $this->status; + } + + + /** + * @return string the etag + */ + public function getETag() { + return $this->ETag; + } + + + /** + * @return string RFC2822 formatted last modified date + */ + public function getLastModified() { + return $this->lastModified; + } + + + /** + * @param string $ETag + */ + public function setETag($ETag) { + $this->ETag = $ETag; + } + + + /** + * @param \DateTime $lastModified + */ + public function setLastModified($lastModified) { + $this->lastModified = $lastModified; + } + + +} diff --git a/lib/appframework/http/templateresponse.php b/lib/appframework/http/templateresponse.php new file mode 100644 index 00000000000..0a32da4b1b4 --- /dev/null +++ b/lib/appframework/http/templateresponse.php @@ -0,0 +1,126 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use OC\AppFramework\Core\API; + + +/** + * Response for a normal template + */ +class TemplateResponse extends Response { + + protected $templateName; + protected $params; + protected $api; + protected $renderAs; + protected $appName; + + /** + * @param API $api an API instance + * @param string $templateName the name of the template + * @param string $appName optional if you want to include a template from + * a different app + */ + public function __construct(API $api, $templateName, $appName=null) { + $this->templateName = $templateName; + $this->appName = $appName; + $this->api = $api; + $this->params = array(); + $this->renderAs = 'user'; + } + + + /** + * Sets template parameters + * @param array $params an array with key => value structure which sets template + * variables + */ + public function setParams(array $params){ + $this->params = $params; + } + + + /** + * Used for accessing the set parameters + * @return array the params + */ + public function getParams(){ + return $this->params; + } + + + /** + * Used for accessing the name of the set template + * @return string the name of the used template + */ + public function getTemplateName(){ + return $this->templateName; + } + + + /** + * Sets the template page + * @param string $renderAs admin, user or blank. Admin also prints the admin + * settings header and footer, user renders the normal + * normal page including footer and header and blank + * just renders the plain template + */ + public function renderAs($renderAs){ + $this->renderAs = $renderAs; + } + + + /** + * Returns the set renderAs + * @return string the renderAs value + */ + public function getRenderAs(){ + return $this->renderAs; + } + + + /** + * Returns the rendered html + * @return string the rendered html + */ + public function render(){ + + if($this->appName !== null){ + $appName = $this->appName; + } else { + $appName = $this->api->getAppName(); + } + + $template = $this->api->getTemplate($this->templateName, $this->renderAs, $appName); + + foreach($this->params as $key => $value){ + $template->assign($key, $value); + } + + return $template->fetchPage(); + } + +} diff --git a/lib/appframework/middleware/middleware.php b/lib/appframework/middleware/middleware.php new file mode 100644 index 00000000000..4df88490468 --- /dev/null +++ b/lib/appframework/middleware/middleware.php @@ -0,0 +1,100 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware; + +use OC\AppFramework\Http\Response; + + +/** + * Middleware is used to provide hooks before or after controller methods and + * deal with possible exceptions raised in the controller methods. + * They're modeled after Django's middleware system: + * https://docs.djangoproject.com/en/dev/topics/http/middleware/ + */ +abstract class Middleware { + + + /** + * This is being run in normal order before the controller is being + * called which allows several modifications and checks + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + */ + public function beforeController($controller, $methodName){ + + } + + + /** + * This is being run when either the beforeController method or the + * controller method itself is throwing an exception. The middleware is + * asked in reverse order to handle the exception and to return a response. + * If the response is null, it is assumed that the exception could not be + * handled and the error will be thrown again + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param \Exception $exception the thrown exception + * @throws \Exception the passed in exception if it cant handle it + * @return Response a Response object in case that the exception was handled + */ + public function afterException($controller, $methodName, \Exception $exception){ + throw $exception; + } + + + /** + * This is being run after a successful controllermethod call and allows + * the manipulation of a Response object. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param Response $response the generated response from the controller + * @return Response a Response object + */ + public function afterController($controller, $methodName, Response $response){ + return $response; + } + + + /** + * This is being run after the response object has been rendered and + * allows the manipulation of the output. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param string $output the generated output from a response + * @return string the output that should be printed + */ + public function beforeOutput($controller, $methodName, $output){ + return $output; + } + +} diff --git a/lib/appframework/middleware/middlewaredispatcher.php b/lib/appframework/middleware/middlewaredispatcher.php new file mode 100644 index 00000000000..c2d16134dc5 --- /dev/null +++ b/lib/appframework/middleware/middlewaredispatcher.php @@ -0,0 +1,159 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware; + +use OC\AppFramework\Controller\Controller; +use OC\AppFramework\Http\Response; + + +/** + * This class is used to store and run all the middleware in correct order + */ +class MiddlewareDispatcher { + + /** + * @var array array containing all the middlewares + */ + private $middlewares; + + /** + * @var int counter which tells us what middlware was executed once an + * exception occurs + */ + private $middlewareCounter; + + + /** + * Constructor + */ + public function __construct(){ + $this->middlewares = array(); + $this->middlewareCounter = 0; + } + + + /** + * Adds a new middleware + * @param Middleware $middleware the middleware which will be added + */ + public function registerMiddleware(Middleware $middleWare){ + array_push($this->middlewares, $middleWare); + } + + + /** + * returns an array with all middleware elements + * @return array the middlewares + */ + public function getMiddlewares(){ + return $this->middlewares; + } + + + /** + * This is being run in normal order before the controller is being + * called which allows several modifications and checks + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + */ + public function beforeController(Controller $controller, $methodName){ + // we need to count so that we know which middlewares we have to ask in + // case theres an exception + for($i=0; $imiddlewares); $i++){ + $this->middlewareCounter++; + $middleware = $this->middlewares[$i]; + $middleware->beforeController($controller, $methodName); + } + } + + + /** + * This is being run when either the beforeController method or the + * controller method itself is throwing an exception. The middleware is asked + * in reverse order to handle the exception and to return a response. + * If the response is null, it is assumed that the exception could not be + * handled and the error will be thrown again + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param \Exception $exception the thrown exception + * @return Response a Response object if the middleware can handle the + * exception + * @throws \Exception the passed in exception if it cant handle it + */ + public function afterException(Controller $controller, $methodName, \Exception $exception){ + for($i=$this->middlewareCounter-1; $i>=0; $i--){ + $middleware = $this->middlewares[$i]; + try { + return $middleware->afterException($controller, $methodName, $exception); + } catch(\Exception $exception){ + continue; + } + } + throw $exception; + } + + + /** + * This is being run after a successful controllermethod call and allows + * the manipulation of a Response object. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param Response $response the generated response from the controller + * @return Response a Response object + */ + public function afterController(Controller $controller, $methodName, Response $response){ + for($i=count($this->middlewares)-1; $i>=0; $i--){ + $middleware = $this->middlewares[$i]; + $response = $middleware->afterController($controller, $methodName, $response); + } + return $response; + } + + + /** + * This is being run after the response object has been rendered and + * allows the manipulation of the output. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param string $output the generated output from a response + * @return string the output that should be printed + */ + public function beforeOutput(Controller $controller, $methodName, $output){ + for($i=count($this->middlewares)-1; $i>=0; $i--){ + $middleware = $this->middlewares[$i]; + $output = $middleware->beforeOutput($controller, $methodName, $output); + } + return $output; + } + +} diff --git a/lib/appframework/middleware/security/securityexception.php b/lib/appframework/middleware/security/securityexception.php new file mode 100644 index 00000000000..b32a2769ff5 --- /dev/null +++ b/lib/appframework/middleware/security/securityexception.php @@ -0,0 +1,41 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware\Security; + + +/** + * Thrown when the security middleware encounters a security problem + */ +class SecurityException extends \Exception { + + /** + * @param string $msg the security error message + * @param bool $ajax true if it resulted because of an ajax request + */ + public function __construct($msg, $code = 0) { + parent::__construct($msg, $code); + } + +} diff --git a/lib/appframework/middleware/security/securitymiddleware.php b/lib/appframework/middleware/security/securitymiddleware.php new file mode 100644 index 00000000000..7a715f309a0 --- /dev/null +++ b/lib/appframework/middleware/security/securitymiddleware.php @@ -0,0 +1,141 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware\Security; + +use OC\AppFramework\Controller\Controller; +use OC\AppFramework\Http\Http; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\Response; +use OC\AppFramework\Http\JSONResponse; +use OC\AppFramework\Http\RedirectResponse; +use OC\AppFramework\Utility\MethodAnnotationReader; +use OC\AppFramework\Middleware\Middleware; +use OC\AppFramework\Core\API; + + +/** + * Used to do all the authentication and checking stuff for a controller method + * It reads out the annotations of a controller method and checks which if + * security things should be checked and also handles errors in case a security + * check fails + */ +class SecurityMiddleware extends Middleware { + + private $api; + + /** + * @var \OC\AppFramework\Http\Request + */ + private $request; + + /** + * @param API $api an instance of the api + */ + public function __construct(API $api, Request $request){ + $this->api = $api; + $this->request = $request; + } + + + /** + * This runs all the security checks before a method call. The + * security checks are determined by inspecting the controller method + * annotations + * @param string/Controller $controller the controllername or string + * @param string $methodName the name of the method + * @throws SecurityException when a security check fails + */ + public function beforeController($controller, $methodName){ + + // get annotations from comments + $annotationReader = new MethodAnnotationReader($controller, $methodName); + + // this will set the current navigation entry of the app, use this only + // for normal HTML requests and not for AJAX requests + $this->api->activateNavigationEntry(); + + // security checks + if(!$annotationReader->hasAnnotation('IsLoggedInExemption')) { + if(!$this->api->isLoggedIn()) { + throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); + } + } + + if(!$annotationReader->hasAnnotation('IsAdminExemption')) { + if(!$this->api->isAdminUser($this->api->getUserId())) { + throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); + } + } + + if(!$annotationReader->hasAnnotation('IsSubAdminExemption')) { + if(!$this->api->isSubAdminUser($this->api->getUserId())) { + throw new SecurityException('Logged in user must be a subadmin', Http::STATUS_FORBIDDEN); + } + } + + if(!$annotationReader->hasAnnotation('CSRFExemption')) { + if(!$this->api->passesCSRFCheck()) { + throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); + } + } + + } + + + /** + * If an SecurityException is being caught, ajax requests return a JSON error + * response and non ajax requests redirect to the index + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param \Exception $exception the thrown exception + * @throws \Exception the passed in exception if it cant handle it + * @return Response a Response object or null in case that the exception could not be handled + */ + public function afterException($controller, $methodName, \Exception $exception){ + if($exception instanceof SecurityException){ + + if (stripos($this->request->getHeader('Accept'),'html')===false) { + + $response = new JSONResponse( + array('message' => $exception->getMessage()), + $exception->getCode() + ); + $this->api->log($exception->getMessage(), 'debug'); + } else { + + $url = $this->api->linkToAbsolute('index.php', ''); // TODO: replace with link to route + $response = new RedirectResponse($url); + $this->api->log($exception->getMessage(), 'debug'); + } + + return $response; + + } + + throw $exception; + } + +} diff --git a/lib/appframework/routing/routeactionhandler.php b/lib/appframework/routing/routeactionhandler.php new file mode 100644 index 00000000000..7fb56f14eab --- /dev/null +++ b/lib/appframework/routing/routeactionhandler.php @@ -0,0 +1,42 @@ +. + * + */ + +namespace OC\AppFramework\routing; + +use \OC\AppFramework\App; +use \OC\AppFramework\DependencyInjection\DIContainer; + +class RouteActionHandler { + private $controllerName; + private $actionName; + private $container; + + public function __construct(DIContainer $container, $controllerName, $actionName) { + $this->controllerName = $controllerName; + $this->actionName = $actionName; + $this->container = $container; + } + + public function __invoke($params) { + App::main($this->controllerName, $this->actionName, $params, $this->container); + } +} diff --git a/lib/appframework/routing/routeconfig.php b/lib/appframework/routing/routeconfig.php new file mode 100644 index 00000000000..53ab11bf2f5 --- /dev/null +++ b/lib/appframework/routing/routeconfig.php @@ -0,0 +1,186 @@ +. + * + */ + +namespace OC\AppFramework\routing; + +use OC\AppFramework\DependencyInjection\DIContainer; + +/** + * Class RouteConfig + * @package OC\AppFramework\routing + */ +class RouteConfig { + private $container; + private $router; + private $routes; + private $appName; + + /** + * @param \OC\AppFramework\DependencyInjection\DIContainer $container + * @param \OC_Router $router + * @param string $pathToYml + * @internal param $appName + */ + public function __construct(DIContainer $container, \OC_Router $router, $routes) { + $this->routes = $routes; + $this->container = $container; + $this->router = $router; + $this->appName = $container['AppName']; + } + + /** + * The routes and resource will be registered to the \OC_Router + */ + public function register() { + + // parse simple + $this->processSimpleRoutes($this->routes); + + // parse resources + $this->processResources($this->routes); + } + + /** + * Creates one route base on the give configuration + * @param $routes + * @throws \UnexpectedValueException + */ + private function processSimpleRoutes($routes) + { + $simpleRoutes = isset($routes['routes']) ? $routes['routes'] : array(); + foreach ($simpleRoutes as $simpleRoute) { + $name = $simpleRoute['name']; + $url = $simpleRoute['url']; + $verb = isset($simpleRoute['verb']) ? strtoupper($simpleRoute['verb']) : 'GET'; + + $split = explode('#', $name, 2); + if (count($split) != 2) { + throw new \UnexpectedValueException('Invalid route name'); + } + $controller = $split[0]; + $action = $split[1]; + + $controllerName = $this->buildControllerName($controller); + $actionName = $this->buildActionName($action); + + // register the route + $handler = new RouteActionHandler($this->container, $controllerName, $actionName); + $this->router->create($this->appName.'.'.$controller.'.'.$action, $url)->method($verb)->action($handler); + } + } + + /** + * For a given name and url restful routes are created: + * - index + * - show + * - new + * - create + * - update + * - destroy + * + * @param $routes + */ + private function processResources($routes) + { + // declaration of all restful actions + $actions = array( + array('name' => 'index', 'verb' => 'GET', 'on-collection' => true), + array('name' => 'show', 'verb' => 'GET'), + array('name' => 'create', 'verb' => 'POST', 'on-collection' => true), + array('name' => 'update', 'verb' => 'PUT'), + array('name' => 'destroy', 'verb' => 'DELETE'), + ); + + $resources = isset($routes['resources']) ? $routes['resources'] : array(); + foreach ($resources as $resource => $config) { + + // the url parameter used as id to the resource + $resourceId = $this->buildResourceId($resource); + foreach($actions as $action) { + $url = $config['url']; + $method = $action['name']; + $verb = isset($action['verb']) ? strtoupper($action['verb']) : 'GET'; + $collectionAction = isset($action['on-collection']) ? $action['on-collection'] : false; + if (!$collectionAction) { + $url = $url . '/' . $resourceId; + } + if (isset($action['url-postfix'])) { + $url = $url . '/' . $action['url-postfix']; + } + + $controller = $resource; + + $controllerName = $this->buildControllerName($controller); + $actionName = $this->buildActionName($method); + + $routeName = $this->appName . '.' . strtolower($resource) . '.' . strtolower($method); + + $this->router->create($routeName, $url)->method($verb)->action( + new RouteActionHandler($this->container, $controllerName, $actionName) + ); + } + } + } + + /** + * Based on a given route name the controller name is generated + * @param $controller + * @return string + */ + private function buildControllerName($controller) + { + return $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller'; + } + + /** + * Based on the action part of the route name the controller method name is generated + * @param $action + * @return string + */ + private function buildActionName($action) { + return $this->underScoreToCamelCase($action); + } + + /** + * Generates the id used in the url part o the route url + * @param $resource + * @return string + */ + private function buildResourceId($resource) { + return '{'.$this->underScoreToCamelCase(rtrim($resource, 's')).'Id}'; + } + + /** + * Underscored strings are converted to camel case strings + * @param $str string + * @return string + */ + private function underScoreToCamelCase($str) { + $pattern = "/_[a-z]?/"; + return preg_replace_callback( + $pattern, + function ($matches) { + return strtoupper(ltrim($matches[0], "_")); + }, + $str); + } +} diff --git a/lib/appframework/utility/methodannotationreader.php b/lib/appframework/utility/methodannotationreader.php new file mode 100644 index 00000000000..42060a08529 --- /dev/null +++ b/lib/appframework/utility/methodannotationreader.php @@ -0,0 +1,61 @@ +. + * + */ + + +namespace OC\AppFramework\Utility; + + +/** + * Reads and parses annotations from doc comments + */ +class MethodAnnotationReader { + + private $annotations; + + /** + * @param object $object an object or classname + * @param string $method the method which we want to inspect for annotations + */ + public function __construct($object, $method){ + $this->annotations = array(); + + $reflection = new \ReflectionMethod($object, $method); + $docs = $reflection->getDocComment(); + + // extract everything prefixed by @ and first letter uppercase + preg_match_all('/@([A-Z]\w+)/', $docs, $matches); + $this->annotations = $matches[1]; + } + + + /** + * Check if a method contains an annotation + * @param string $name the name of the annotation + * @return bool true if the annotation is found + */ + public function hasAnnotation($name){ + return in_array($name, $this->annotations); + } + + +} diff --git a/lib/appframework/utility/timefactory.php b/lib/appframework/utility/timefactory.php new file mode 100644 index 00000000000..2c3dd6cf5e3 --- /dev/null +++ b/lib/appframework/utility/timefactory.php @@ -0,0 +1,42 @@ +. + * + */ + + +namespace OC\AppFramework\Utility; + + +/** + * Needed to mock calls to time() + */ +class TimeFactory { + + + /** + * @return int the result of a call to time() + */ + public function getTime() { + return time(); + } + + +} diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php new file mode 100644 index 00000000000..000094d07c8 --- /dev/null +++ b/tests/lib/appframework/AppTest.php @@ -0,0 +1,107 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Core\API; +use OC\AppFramework\Middleware\MiddlewareDispatcher; + +// FIXME: loading pimpl correctly from 3rdparty repo +require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; +require_once __DIR__ . "/classloader.php"; + + +class AppTest extends \PHPUnit_Framework_TestCase { + + private $container; + private $api; + private $controller; + private $dispatcher; + private $params; + private $headers; + private $output; + private $controllerName; + private $controllerMethod; + + protected function setUp() { + $this->container = new \Pimple(); + $this->controller = $this->getMockBuilder( + 'OC\AppFramework\Controller\Controller') + ->disableOriginalConstructor() + ->getMock(); + $this->dispatcher = $this->getMockBuilder( + 'OC\AppFramework\Http\Dispatcher') + ->disableOriginalConstructor() + ->getMock(); + + + $this->headers = array('key' => 'value'); + $this->output = 'hi'; + $this->controllerName = 'Controller'; + $this->controllerMethod = 'method'; + + $this->container[$this->controllerName] = $this->controller; + $this->container['Dispatcher'] = $this->dispatcher; + } + + + public function testControllerNameAndMethodAreBeingPassed(){ + $return = array(null, array(), null); + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->will($this->returnValue($return)); + + $this->expectOutputString(''); + + App::main($this->controllerName, $this->controllerMethod, array(), + $this->container); + } + + + /* + FIXME: this complains about shit headers which are already sent because + of the content length. Would be cool if someone could fix this + + public function testOutputIsPrinted(){ + $return = array(null, array(), $this->output); + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->will($this->returnValue($return)); + + $this->expectOutputString($this->output); + + App::main($this->controllerName, $this->controllerMethod, array(), + $this->container); + } + */ + + // FIXME: if someone manages to test the headers output, I'd be grateful + + +} diff --git a/tests/lib/appframework/classloader.php b/tests/lib/appframework/classloader.php new file mode 100644 index 00000000000..ae485e67b2c --- /dev/null +++ b/tests/lib/appframework/classloader.php @@ -0,0 +1,45 @@ +. + * + */ + +// to execute without ownCloud, we need to create our own class loader +spl_autoload_register(function ($className){ + if (strpos($className, 'OC\\AppFramework') === 0) { + $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $relPath = __DIR__ . '/../../../lib/' . $path; + + if(file_exists($relPath)){ + require_once $relPath; + } + } + + // FIXME: this will most probably not work anymore + if (strpos($className, 'OCA\\') === 0) { + + $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $relPath = __DIR__ . '/../..' . $path; + + if(file_exists($relPath)){ + require_once $relPath; + } + } +}); diff --git a/tests/lib/appframework/controller/ControllerTest.php b/tests/lib/appframework/controller/ControllerTest.php new file mode 100644 index 00000000000..d8357c2a685 --- /dev/null +++ b/tests/lib/appframework/controller/ControllerTest.php @@ -0,0 +1,161 @@ +. + * + */ + + +namespace Test\AppFramework\Controller; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\JSONResponse; +use OC\AppFramework\Http\TemplateResponse; +use OC\AppFramework\Controller\Controller; + + +require_once(__DIR__ . "/../classloader.php"); + + +class ChildController extends Controller {}; + +class ControllerTest extends \PHPUnit_Framework_TestCase { + + /** + * @var Controller + */ + private $controller; + private $api; + + protected function setUp(){ + $request = new Request( + array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + 'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'), + 'urlParams' => array('name' => 'Johnny Weissmüller'), + 'files' => array('file' => 'filevalue'), + 'env' => array('PATH' => 'daheim'), + 'session' => array('sezession' => 'kein'), + 'method' => 'hi', + ) + ); + + $this->api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName'), array('test')); + $this->api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('apptemplate_advanced')); + + $this->controller = new ChildController($this->api, $request); + } + + + public function testParamsGet(){ + $this->assertEquals('Johnny Weissmüller', $this->controller->params('name', 'Tarzan')); + } + + + public function testParamsGetDefault(){ + $this->assertEquals('Tarzan', $this->controller->params('Ape Man', 'Tarzan')); + } + + + public function testParamsFile(){ + $this->assertEquals('filevalue', $this->controller->params('file', 'filevalue')); + } + + + public function testGetUploadedFile(){ + $this->assertEquals('filevalue', $this->controller->getUploadedFile('file')); + } + + + + public function testGetUploadedFileDefault(){ + $this->assertEquals('default', $this->controller->params('files', 'default')); + } + + + public function testGetParams(){ + $params = array( + 'name' => 'Johnny Weissmüller', + 'nickname' => 'Janey', + ); + + $this->assertEquals($params, $this->controller->getParams()); + } + + + public function testRender(){ + $this->assertTrue($this->controller->render('') instanceof TemplateResponse); + } + + + public function testSetParams(){ + $params = array('john' => 'foo'); + $response = $this->controller->render('home', $params); + + $this->assertEquals($params, $response->getParams()); + } + + + public function testRenderRenderAs(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('admin'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $this->controller = new ChildController($api, new Request()); + $this->controller->render('home', array(), 'admin')->render(); + } + + + public function testRenderHeaders(){ + $headers = array('one', 'two'); + $response = $this->controller->render('', array(), '', $headers); + + $this->assertTrue(in_array($headers[0], $response->getHeaders())); + $this->assertTrue(in_array($headers[1], $response->getHeaders())); + } + + + public function testGetRequestMethod(){ + $this->assertEquals('hi', $this->controller->method()); + } + + + public function testGetEnvVariable(){ + $this->assertEquals('daheim', $this->controller->env('PATH')); + } + + public function testGetSessionVariable(){ + $this->assertEquals('kein', $this->controller->session('sezession')); + } + + +} diff --git a/tests/lib/appframework/dependencyinjection/DIContainerTest.php b/tests/lib/appframework/dependencyinjection/DIContainerTest.php new file mode 100644 index 00000000000..ce346f0a763 --- /dev/null +++ b/tests/lib/appframework/dependencyinjection/DIContainerTest.php @@ -0,0 +1,98 @@ +. + * + */ + + +namespace OC\AppFramework\DependencyInjection; + +use \OC\AppFramework\Http\Request; + + +require_once(__DIR__ . "/../classloader.php"); + + +class DIContainerTest extends \PHPUnit_Framework_TestCase { + + private $container; + + protected function setUp(){ + $this->container = new DIContainer('name'); + $this->api = $this->getMock('OC\AppFramework\Core\API', array('getTrans'), array('hi')); + } + + private function exchangeAPI(){ + $this->api->expects($this->any()) + ->method('getTrans') + ->will($this->returnValue('yo')); + $this->container['API'] = $this->api; + } + + public function testProvidesAPI(){ + $this->assertTrue(isset($this->container['API'])); + } + + + public function testProvidesRequest(){ + $this->assertTrue(isset($this->container['Request'])); + } + + + public function testProvidesSecurityMiddleware(){ + $this->assertTrue(isset($this->container['SecurityMiddleware'])); + } + + + public function testProvidesMiddlewareDispatcher(){ + $this->assertTrue(isset($this->container['MiddlewareDispatcher'])); + } + + + public function testProvidesAppName(){ + $this->assertTrue(isset($this->container['AppName'])); + } + + + public function testAppNameIsSetCorrectly(){ + $this->assertEquals('name', $this->container['AppName']); + } + + + public function testMiddlewareDispatcherIncludesSecurityMiddleware(){ + $this->container['Request'] = new Request(); + $security = $this->container['SecurityMiddleware']; + $dispatcher = $this->container['MiddlewareDispatcher']; + + $this->assertContains($security, $dispatcher->getMiddlewares()); + } + + + public function testMiddlewareDispatcherDoesNotIncludeTwigWhenTplDirectoryNotSet(){ + $this->container['Request'] = new Request(); + $this->exchangeAPI(); + $dispatcher = $this->container['MiddlewareDispatcher']; + + $this->assertEquals(1, count($dispatcher->getMiddlewares())); + } + +} diff --git a/tests/lib/appframework/http/DispatcherTest.php b/tests/lib/appframework/http/DispatcherTest.php new file mode 100644 index 00000000000..2e3db110504 --- /dev/null +++ b/tests/lib/appframework/http/DispatcherTest.php @@ -0,0 +1,218 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use OC\AppFramework\Core\API; +use OC\AppFramework\Middleware\MiddlewareDispatcher; + +require_once(__DIR__ . "/../classloader.php"); + + +class DispatcherTest extends \PHPUnit_Framework_TestCase { + + + private $middlewareDispatcher; + private $dispatcher; + private $controllerMethod; + private $response; + private $lastModified; + private $etag; + private $http; + + protected function setUp() { + $this->controllerMethod = 'test'; + + $api = $this->getMockBuilder( + '\OC\AppFramework\Core\API') + ->disableOriginalConstructor() + ->getMock(); + $request = $this->getMockBuilder( + '\OC\AppFramework\Http\Request') + ->disableOriginalConstructor() + ->getMock(); + $this->http = $this->getMockBuilder( + '\OC\AppFramework\Http\Http') + ->disableOriginalConstructor() + ->getMock(); + + $this->middlewareDispatcher = $this->getMockBuilder( + '\OC\AppFramework\Middleware\MiddlewareDispatcher') + ->disableOriginalConstructor() + ->getMock(); + $this->controller = $this->getMock( + '\OC\AppFramework\Controller\Controller', + array($this->controllerMethod), array($api, $request)); + + $this->dispatcher = new Dispatcher( + $this->http, $this->middlewareDispatcher); + + $this->response = $this->getMockBuilder( + '\OC\AppFramework\Http\Response') + ->disableOriginalConstructor() + ->getMock(); + + $this->lastModified = new \DateTime(null, new \DateTimeZone('GMT')); + $this->etag = 'hi'; + } + + + private function setMiddlewareExpections($out=null, + $httpHeaders=null, $responseHeaders=array(), + $ex=false, $catchEx=true) { + + if($ex) { + $exception = new \Exception(); + $this->middlewareDispatcher->expects($this->once()) + ->method('beforeController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->will($this->throwException($exception)); + if($catchEx) { + $this->middlewareDispatcher->expects($this->once()) + ->method('afterException') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($exception)) + ->will($this->returnValue($this->response)); + } else { + $this->middlewareDispatcher->expects($this->once()) + ->method('afterException') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($exception)) + ->will($this->returnValue(null)); + return; + } + } else { + $this->middlewareDispatcher->expects($this->once()) + ->method('beforeController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)); + $this->controller->expects($this->once()) + ->method($this->controllerMethod) + ->will($this->returnValue($this->response)); + } + + $this->response->expects($this->once()) + ->method('render') + ->will($this->returnValue($out)); + $this->response->expects($this->once()) + ->method('getStatus') + ->will($this->returnValue(Http::STATUS_OK)); + $this->response->expects($this->once()) + ->method('getLastModified') + ->will($this->returnValue($this->lastModified)); + $this->response->expects($this->once()) + ->method('getETag') + ->will($this->returnValue($this->etag)); + $this->response->expects($this->once()) + ->method('getHeaders') + ->will($this->returnValue($responseHeaders)); + $this->http->expects($this->once()) + ->method('getStatusHeader') + ->with($this->equalTo(Http::STATUS_OK), + $this->equalTo($this->lastModified), + $this->equalTo($this->etag)) + ->will($this->returnValue($httpHeaders)); + + $this->middlewareDispatcher->expects($this->once()) + ->method('afterController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($this->response)) + ->will($this->returnValue($this->response)); + + $this->middlewareDispatcher->expects($this->once()) + ->method('afterController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($this->response)) + ->will($this->returnValue($this->response)); + + $this->middlewareDispatcher->expects($this->once()) + ->method('beforeOutput') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($out)) + ->will($this->returnValue($out)); + + + } + + + public function testDispatcherReturnsArrayWith2Entries() { + $this->setMiddlewareExpections(); + + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + $this->assertNull($response[0]); + $this->assertEquals(array(), $response[1]); + $this->assertNull($response[2]); + } + + + public function testHeadersAndOutputAreReturned(){ + $out = 'yo'; + $httpHeaders = 'Http'; + $responseHeaders = array('hell' => 'yeah'); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders); + + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + + $this->assertEquals($httpHeaders, $response[0]); + $this->assertEquals($responseHeaders, $response[1]); + $this->assertEquals($out, $response[2]); + } + + + public function testExceptionCallsAfterException() { + $out = 'yo'; + $httpHeaders = 'Http'; + $responseHeaders = array('hell' => 'yeah'); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true); + + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + + $this->assertEquals($httpHeaders, $response[0]); + $this->assertEquals($responseHeaders, $response[1]); + $this->assertEquals($out, $response[2]); + } + + + public function testExceptionThrowsIfCanNotBeHandledByAfterException() { + $out = 'yo'; + $httpHeaders = 'Http'; + $responseHeaders = array('hell' => 'yeah'); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); + + $this->setExpectedException('\Exception'); + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + + } + +} diff --git a/tests/lib/appframework/http/DownloadResponseTest.php b/tests/lib/appframework/http/DownloadResponseTest.php new file mode 100644 index 00000000000..103cfe7588c --- /dev/null +++ b/tests/lib/appframework/http/DownloadResponseTest.php @@ -0,0 +1,51 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + +class ChildDownloadResponse extends DownloadResponse {}; + + +class DownloadResponseTest extends \PHPUnit_Framework_TestCase { + + protected $response; + + protected function setUp(){ + $this->response = new ChildDownloadResponse('file', 'content'); + } + + + public function testHeaders() { + $headers = $this->response->getHeaders(); + + $this->assertContains('attachment; filename="file"', $headers['Content-Disposition']); + $this->assertContains('content', $headers['Content-Type']); + } + + +} diff --git a/tests/lib/appframework/http/HttpTest.php b/tests/lib/appframework/http/HttpTest.php new file mode 100644 index 00000000000..306bc3caf42 --- /dev/null +++ b/tests/lib/appframework/http/HttpTest.php @@ -0,0 +1,87 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class HttpTest extends \PHPUnit_Framework_TestCase { + + private $server; + private $http; + + protected function setUp(){ + $this->server = array(); + $this->http = new Http($this->server); + } + + + public function testProtocol() { + $header = $this->http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); + $this->assertEquals('HTTP/1.1 307 Temporary Redirect', $header); + } + + + public function testProtocol10() { + $this->http = new Http($this->server, 'HTTP/1.0'); + $header = $this->http->getStatusHeader(Http::STATUS_OK); + $this->assertEquals('HTTP/1.0 200 OK', $header); + } + + + public function testEtagMatchReturnsNotModified() { + $http = new Http(array('HTTP_IF_NONE_MATCH' => 'hi')); + + $header = $http->getStatusHeader(Http::STATUS_OK, null, 'hi'); + $this->assertEquals('HTTP/1.1 304 Not Modified', $header); + } + + + public function testLastModifiedMatchReturnsNotModified() { + $dateTime = new \DateTime(null, new \DateTimeZone('GMT')); + $dateTime->setTimestamp('12'); + + $http = new Http( + array( + 'HTTP_IF_MODIFIED_SINCE' => 'Thu, 01 Jan 1970 00:00:12 +0000') + ); + + $header = $http->getStatusHeader(Http::STATUS_OK, $dateTime); + $this->assertEquals('HTTP/1.1 304 Not Modified', $header); + } + + + + public function testTempRedirectBecomesFoundInHttp10() { + $http = new Http(array(), 'HTTP/1.0'); + + $header = $http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); + $this->assertEquals('HTTP/1.0 302 Found', $header); + } + // TODO: write unittests for http codes + +} diff --git a/tests/lib/appframework/http/JSONResponseTest.php b/tests/lib/appframework/http/JSONResponseTest.php new file mode 100644 index 00000000000..d15e08f6ce1 --- /dev/null +++ b/tests/lib/appframework/http/JSONResponseTest.php @@ -0,0 +1,96 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class JSONResponseTest extends \PHPUnit_Framework_TestCase { + + /** + * @var JSONResponse + */ + private $json; + + protected function setUp() { + $this->json = new JSONResponse(); + } + + + public function testHeader() { + $headers = $this->json->getHeaders(); + $this->assertEquals('application/json; charset=utf-8', $headers['Content-type']); + } + + + public function testSetData() { + $params = array('hi', 'yo'); + $this->json->setData($params); + + $this->assertEquals(array('hi', 'yo'), $this->json->getData()); + } + + + public function testSetRender() { + $params = array('test' => 'hi'); + $this->json->setData($params); + + $expected = '{"test":"hi"}'; + + $this->assertEquals($expected, $this->json->render()); + } + + + public function testRender() { + $params = array('test' => 'hi'); + $this->json->setData($params); + + $expected = '{"test":"hi"}'; + + $this->assertEquals($expected, $this->json->render()); + } + + + public function testShouldHaveXContentHeaderByDefault() { + $headers = $this->json->getHeaders(); + $this->assertEquals('nosniff', $headers['X-Content-Type-Options']); + } + + + public function testConstructorAllowsToSetData() { + $data = array('hi'); + $code = 300; + $response = new JSONResponse($data, $code); + + $expected = '["hi"]'; + $this->assertEquals($expected, $response->render()); + $this->assertEquals($code, $response->getStatus()); + } + +} diff --git a/tests/lib/appframework/http/RedirectResponseTest.php b/tests/lib/appframework/http/RedirectResponseTest.php new file mode 100644 index 00000000000..a8577feed29 --- /dev/null +++ b/tests/lib/appframework/http/RedirectResponseTest.php @@ -0,0 +1,55 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class RedirectResponseTest extends \PHPUnit_Framework_TestCase { + + + protected $response; + + protected function setUp(){ + $this->response = new RedirectResponse('/url'); + } + + + public function testHeaders() { + $headers = $this->response->getHeaders(); + $this->assertEquals('/url', $headers['Location']); + $this->assertEquals(Http::STATUS_TEMPORARY_REDIRECT, + $this->response->getStatus()); + } + + + public function testGetRedirectUrl(){ + $this->assertEquals('/url', $this->response->getRedirectUrl()); + } + + +} diff --git a/tests/lib/appframework/http/RequestTest.php b/tests/lib/appframework/http/RequestTest.php new file mode 100644 index 00000000000..c1f56c01636 --- /dev/null +++ b/tests/lib/appframework/http/RequestTest.php @@ -0,0 +1,78 @@ + array('name' => 'John Q. Public', 'nickname' => 'Joey'), + ); + + $request = new Request($vars); + + // Countable + $this->assertEquals(2, count($request)); + // Array access + $this->assertEquals('Joey', $request['nickname']); + // "Magic" accessors + $this->assertEquals('Joey', $request->{'nickname'}); + $this->assertTrue(isset($request['nickname'])); + $this->assertTrue(isset($request->{'nickname'})); + $this->assertEquals(false, isset($request->{'flickname'})); + // Only testing 'get', but same approach for post, files etc. + $this->assertEquals('Joey', $request->get['nickname']); + // Always returns null if variable not set. + $this->assertEquals(null, $request->{'flickname'}); + } + + // urlParams has precedence over POST which has precedence over GET + public function testPrecedence() { + $vars = array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + 'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'), + 'urlParams' => array('user' => 'jw', 'name' => 'Johnny Weissmüller'), + ); + + $request = new Request($vars); + + $this->assertEquals(3, count($request)); + $this->assertEquals('Janey', $request->{'nickname'}); + $this->assertEquals('Johnny Weissmüller', $request->{'name'}); + } + + + /** + * @expectedException RuntimeException + */ + public function testImmutableArrayAccess() { + $vars = array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + ); + + $request = new Request($vars); + $request['nickname'] = 'Janey'; + } + + /** + * @expectedException RuntimeException + */ + public function testImmutableMagicAccess() { + $vars = array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + ); + + $request = new Request($vars); + $request->{'nickname'} = 'Janey'; + } + +} diff --git a/tests/lib/appframework/http/ResponseTest.php b/tests/lib/appframework/http/ResponseTest.php new file mode 100644 index 00000000000..621ba66545f --- /dev/null +++ b/tests/lib/appframework/http/ResponseTest.php @@ -0,0 +1,119 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class ResponseTest extends \PHPUnit_Framework_TestCase { + + + private $childResponse; + + protected function setUp(){ + $this->childResponse = new Response(); + } + + + public function testAddHeader(){ + $this->childResponse->addHeader('hello', 'world'); + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('world', $headers['hello']); + } + + + public function testAddHeaderValueNullDeletesIt(){ + $this->childResponse->addHeader('hello', 'world'); + $this->childResponse->addHeader('hello', null); + $this->assertEquals(1, count($this->childResponse->getHeaders())); + } + + + public function testCacheHeadersAreDisabledByDefault(){ + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('no-cache, must-revalidate', $headers['Cache-Control']); + } + + + public function testRenderReturnNullByDefault(){ + $this->assertEquals(null, $this->childResponse->render()); + } + + + public function testGetStatus() { + $default = $this->childResponse->getStatus(); + + $this->childResponse->setStatus(Http::STATUS_NOT_FOUND); + + $this->assertEquals(Http::STATUS_OK, $default); + $this->assertEquals(Http::STATUS_NOT_FOUND, $this->childResponse->getStatus()); + } + + + public function testGetEtag() { + $this->childResponse->setEtag('hi'); + $this->assertEquals('hi', $this->childResponse->getEtag()); + } + + + public function testGetLastModified() { + $lastModified = new \DateTime(null, new \DateTimeZone('GMT')); + $lastModified->setTimestamp(1); + $this->childResponse->setLastModified($lastModified); + $this->assertEquals($lastModified, $this->childResponse->getLastModified()); + } + + + + public function testCacheSecondsZero() { + $this->childResponse->cacheFor(0); + + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('no-cache, must-revalidate', $headers['Cache-Control']); + } + + + public function testCacheSeconds() { + $this->childResponse->cacheFor(33); + + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('max-age=33, must-revalidate', + $headers['Cache-Control']); + } + + + + public function testEtagLastModifiedHeaders() { + $lastModified = new \DateTime(null, new \DateTimeZone('GMT')); + $lastModified->setTimestamp(1); + $this->childResponse->setLastModified($lastModified); + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('Thu, 01 Jan 1970 00:00:01 +0000', $headers['Last-Modified']); + } + + +} diff --git a/tests/lib/appframework/http/TemplateResponseTest.php b/tests/lib/appframework/http/TemplateResponseTest.php new file mode 100644 index 00000000000..30684725b72 --- /dev/null +++ b/tests/lib/appframework/http/TemplateResponseTest.php @@ -0,0 +1,157 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use OC\AppFramework\Core\API; + + +require_once(__DIR__ . "/../classloader.php"); + + +class TemplateResponseTest extends \PHPUnit_Framework_TestCase { + + private $tpl; + private $api; + + protected function setUp() { + $this->api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName'), array('test')); + $this->api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + + $this->tpl = new TemplateResponse($this->api, 'home'); + } + + + public function testSetParams(){ + $params = array('hi' => 'yo'); + $this->tpl->setParams($params); + + $this->assertEquals(array('hi' => 'yo'), $this->tpl->getParams()); + } + + + public function testGetTemplateName(){ + $this->assertEquals('home', $this->tpl->getTemplateName()); + } + + + public function testRender(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home'); + + $tpl->render(); + } + + + public function testRenderAssignsParams(){ + $params = array('john' => 'doe'); + + $ocTpl = $this->getMock('Template', array('assign', 'fetchPage')); + $ocTpl->expects($this->once()) + ->method('assign') + ->with($this->equalTo('john'), $this->equalTo('doe')); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home'); + $tpl->setParams($params); + + $tpl->render(); + } + + + public function testRenderDifferentApp(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app2')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home', 'app2'); + + $tpl->render(); + } + + + public function testRenderDifferentRenderAs(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('admin'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home'); + $tpl->renderAs('admin'); + + $tpl->render(); + } + + + public function testGetRenderAs(){ + $render = 'myrender'; + $this->tpl->renderAs($render); + $this->assertEquals($render, $this->tpl->getRenderAs()); + } + +} diff --git a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php new file mode 100644 index 00000000000..bfa54a48ea3 --- /dev/null +++ b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php @@ -0,0 +1,280 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\Controller\Controller; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\Response; +use OC\AppFramework\Middleware\Middleware; +use OC\AppFramework\Middleware\MiddlewareDispatcher; + + +require_once(__DIR__ . "/../classloader.php"); + + +// needed to test ordering +class TestMiddleware extends Middleware { + public static $beforeControllerCalled = 0; + public static $afterControllerCalled = 0; + public static $afterExceptionCalled = 0; + public static $beforeOutputCalled = 0; + + public $beforeControllerOrder = 0; + public $afterControllerOrder = 0; + public $afterExceptionOrder = 0; + public $beforeOutputOrder = 0; + + public $controller; + public $methodName; + public $exception; + public $response; + public $output; + + private $beforeControllerThrowsEx; + + public function __construct($beforeControllerThrowsEx) { + self::$beforeControllerCalled = 0; + self::$afterControllerCalled = 0; + self::$afterExceptionCalled = 0; + self::$beforeOutputCalled = 0; + $this->beforeControllerThrowsEx = $beforeControllerThrowsEx; + } + + public function beforeController($controller, $methodName){ + self::$beforeControllerCalled++; + $this->beforeControllerOrder = self::$beforeControllerCalled; + $this->controller = $controller; + $this->methodName = $methodName; + if($this->beforeControllerThrowsEx){ + throw new \Exception(); + } + } + + public function afterException($controller, $methodName, \Exception $exception){ + self::$afterExceptionCalled++; + $this->afterExceptionOrder = self::$afterExceptionCalled; + $this->controller = $controller; + $this->methodName = $methodName; + $this->exception = $exception; + parent::afterException($controller, $methodName, $exception); + } + + public function afterController($controller, $methodName, Response $response){ + self::$afterControllerCalled++; + $this->afterControllerOrder = self::$afterControllerCalled; + $this->controller = $controller; + $this->methodName = $methodName; + $this->response = $response; + return parent::afterController($controller, $methodName, $response); + } + + public function beforeOutput($controller, $methodName, $output){ + self::$beforeOutputCalled++; + $this->beforeOutputOrder = self::$beforeOutputCalled; + $this->controller = $controller; + $this->methodName = $methodName; + $this->output = $output; + return parent::beforeOutput($controller, $methodName, $output); + } +} + + +class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { + + private $dispatcher; + + + public function setUp() { + $this->dispatcher = new MiddlewareDispatcher(); + $this->controller = $this->getControllerMock(); + $this->method = 'method'; + $this->response = new Response(); + $this->output = 'hi'; + $this->exception = new \Exception(); + } + + + private function getAPIMock(){ + return $this->getMock('OC\AppFramework\Core\API', + array('getAppName'), array('app')); + } + + + private function getControllerMock(){ + return $this->getMock('OC\AppFramework\Controller\Controller', array('method'), + array($this->getAPIMock(), new Request())); + } + + + private function getMiddleware($beforeControllerThrowsEx=false){ + $m1 = new TestMiddleware($beforeControllerThrowsEx); + $this->dispatcher->registerMiddleware($m1); + return $m1; + } + + + public function testAfterExceptionShouldReturnResponseOfMiddleware(){ + $response = new Response(); + $m1 = $this->getMock('\OC\AppFramework\Middleware\Middleware', + array('afterException', 'beforeController')); + $m1->expects($this->never()) + ->method('afterException'); + + $m2 = $this->getMock('OC\AppFramework\Middleware\Middleware', + array('afterException', 'beforeController')); + $m2->expects($this->once()) + ->method('afterException') + ->will($this->returnValue($response)); + + $this->dispatcher->registerMiddleware($m1); + $this->dispatcher->registerMiddleware($m2); + + $this->dispatcher->beforeController($this->controller, $this->method); + $this->assertEquals($response, $this->dispatcher->afterException($this->controller, $this->method, $this->exception)); + } + + + public function testAfterExceptionShouldThrowAgainWhenNotHandled(){ + $m1 = new TestMiddleware(false); + $m2 = new TestMiddleware(true); + + $this->dispatcher->registerMiddleware($m1); + $this->dispatcher->registerMiddleware($m2); + + $this->setExpectedException('\Exception'); + $this->dispatcher->beforeController($this->controller, $this->method); + $this->dispatcher->afterException($this->controller, $this->method, $this->exception); + } + + + public function testBeforeControllerCorrectArguments(){ + $m1 = $this->getMiddleware(); + $this->dispatcher->beforeController($this->controller, $this->method); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + } + + + public function testAfterControllerCorrectArguments(){ + $m1 = $this->getMiddleware(); + + $this->dispatcher->afterController($this->controller, $this->method, $this->response); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + $this->assertEquals($this->response, $m1->response); + } + + + public function testAfterExceptionCorrectArguments(){ + $m1 = $this->getMiddleware(); + + $this->setExpectedException('\Exception'); + + $this->dispatcher->beforeController($this->controller, $this->method); + $this->dispatcher->afterException($this->controller, $this->method, $this->exception); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + $this->assertEquals($this->exception, $m1->exception); + } + + + public function testBeforeOutputCorrectArguments(){ + $m1 = $this->getMiddleware(); + + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + $this->assertEquals($this->output, $m1->output); + } + + + public function testBeforeControllerOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->dispatcher->beforeController($this->controller, $this->method); + + $this->assertEquals(1, $m1->beforeControllerOrder); + $this->assertEquals(2, $m2->beforeControllerOrder); + } + + public function testAfterControllerOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->dispatcher->afterController($this->controller, $this->method, $this->response); + + $this->assertEquals(2, $m1->afterControllerOrder); + $this->assertEquals(1, $m2->afterControllerOrder); + } + + + public function testAfterExceptionOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->setExpectedException('\Exception'); + $this->dispatcher->beforeController($this->controller, $this->method); + $this->dispatcher->afterException($this->controller, $this->method, $this->exception); + + $this->assertEquals(1, $m1->afterExceptionOrder); + $this->assertEquals(1, $m2->afterExceptionOrder); + } + + + public function testBeforeOutputOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + + $this->assertEquals(2, $m1->beforeOutputOrder); + $this->assertEquals(1, $m2->beforeOutputOrder); + } + + + public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(true); + $m3 = $this->getMock('\OC\AppFramework\Middleware\Middleware'); + $m3->expects($this->never()) + ->method('afterException'); + $m3->expects($this->never()) + ->method('beforeController'); + $m3->expects($this->never()) + ->method('afterController'); + + $this->dispatcher->registerMiddleware($m3); + + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + + $this->assertEquals(2, $m1->beforeOutputOrder); + $this->assertEquals(1, $m2->beforeOutputOrder); + } +} diff --git a/tests/lib/appframework/middleware/MiddlewareTest.php b/tests/lib/appframework/middleware/MiddlewareTest.php new file mode 100644 index 00000000000..1adce6b3d4f --- /dev/null +++ b/tests/lib/appframework/middleware/MiddlewareTest.php @@ -0,0 +1,82 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Middleware\Middleware; + + +require_once(__DIR__ . "/../classloader.php"); + + +class ChildMiddleware extends Middleware {}; + + +class MiddlewareTest extends \PHPUnit_Framework_TestCase { + + private $middleware; + private $controller; + private $exception; + private $api; + + protected function setUp(){ + $this->middleware = new ChildMiddleware(); + + $this->api = $this->getMock('OC\AppFramework\Core\API', + array(), array('test')); + + $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', + array(), array($this->api, new Request())); + $this->exception = new \Exception(); + $this->response = $this->getMock('OC\AppFramework\Http\Response'); + } + + + public function testBeforeController() { + $this->middleware->beforeController($this->controller, null, $this->exception); + } + + + public function testAfterExceptionRaiseAgainWhenUnhandled() { + $this->setExpectedException('Exception'); + $afterEx = $this->middleware->afterException($this->controller, null, $this->exception); + } + + + public function testAfterControllerReturnResponseWhenUnhandled() { + $response = $this->middleware->afterController($this->controller, null, $this->response); + + $this->assertEquals($this->response, $response); + } + + + public function testBeforeOutputReturnOutputhenUnhandled() { + $output = $this->middleware->beforeOutput($this->controller, null, 'test'); + + $this->assertEquals('test', $output); + } + + +} diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php new file mode 100644 index 00000000000..0b2103564e4 --- /dev/null +++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php @@ -0,0 +1,388 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware\Security; + +use OC\AppFramework\Http\Http; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\RedirectResponse; +use OC\AppFramework\Http\JSONResponse; +use OC\AppFramework\Middleware\Middleware; + + +require_once(__DIR__ . "/../../classloader.php"); + + +class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { + + private $middleware; + private $controller; + private $secException; + private $secAjaxException; + private $request; + + public function setUp() { + $api = $this->getMock('OC\AppFramework\Core\API', array(), array('test')); + $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', + array(), array($api, new Request())); + + $this->request = new Request(); + $this->middleware = new SecurityMiddleware($api, $this->request); + $this->secException = new SecurityException('hey', false); + $this->secAjaxException = new SecurityException('hey', true); + } + + + private function getAPI(){ + return $this->getMock('OC\AppFramework\Core\API', + array('isLoggedIn', 'passesCSRFCheck', 'isAdminUser', + 'isSubAdminUser', 'activateNavigationEntry', + 'getUserId'), + array('app')); + } + + + private function checkNavEntry($method, $shouldBeActivated=false){ + $api = $this->getAPI(); + + if($shouldBeActivated){ + $api->expects($this->once()) + ->method('activateNavigationEntry'); + } else { + $api->expects($this->never()) + ->method('activateNavigationEntry'); + } + + $sec = new SecurityMiddleware($api, $this->request); + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testSetNavigationEntry(){ + $this->checkNavEntry('testSetNavigationEntry', true); + } + + + private function ajaxExceptionCheck($method, $shouldBeAjax=false){ + $api = $this->getAPI(); + $api->expects($this->any()) + ->method('passesCSRFCheck') + ->will($this->returnValue(false)); + + $sec = new SecurityMiddleware($api, $this->request); + + try { + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', + $method); + } catch (SecurityException $ex){ + if($shouldBeAjax){ + $this->assertTrue($ex->isAjax()); + } else { + $this->assertFalse($ex->isAjax()); + } + + } + } + + + /** + * @Ajax + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testAjaxException(){ + $this->ajaxExceptionCheck('testAjaxException'); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testNoAjaxException(){ + $this->ajaxExceptionCheck('testNoAjaxException'); + } + + + private function ajaxExceptionStatus($method, $test, $status) { + $api = $this->getAPI(); + $api->expects($this->any()) + ->method($test) + ->will($this->returnValue(false)); + + $sec = new SecurityMiddleware($api, $this->request); + + try { + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', + $method); + } catch (SecurityException $ex){ + $this->assertEquals($status, $ex->getCode()); + } + } + + /** + * @Ajax + */ + public function testAjaxStatusLoggedInCheck() { + $this->ajaxExceptionStatus( + 'testAjaxStatusLoggedInCheck', + 'isLoggedIn', + Http::STATUS_UNAUTHORIZED + ); + } + + /** + * @Ajax + * @IsLoggedInExemption + */ + public function testAjaxNotAdminCheck() { + $this->ajaxExceptionStatus( + 'testAjaxNotAdminCheck', + 'isAdminUser', + Http::STATUS_FORBIDDEN + ); + } + + /** + * @Ajax + * @IsLoggedInExemption + * @IsAdminExemption + */ + public function testAjaxNotSubAdminCheck() { + $this->ajaxExceptionStatus( + 'testAjaxNotSubAdminCheck', + 'isSubAdminUser', + Http::STATUS_FORBIDDEN + ); + } + + /** + * @Ajax + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testAjaxStatusCSRFCheck() { + $this->ajaxExceptionStatus( + 'testAjaxStatusCSRFCheck', + 'passesCSRFCheck', + Http::STATUS_PRECONDITION_FAILED + ); + } + + /** + * @Ajax + * @CSRFExemption + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testAjaxStatusAllGood() { + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'isLoggedIn', + 0 + ); + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'isAdminUser', + 0 + ); + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'isSubAdminUser', + 0 + ); + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'passesCSRFCheck', + 0 + ); + } + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testNoChecks(){ + $api = $this->getAPI(); + $api->expects($this->never()) + ->method('passesCSRFCheck') + ->will($this->returnValue(true)); + $api->expects($this->never()) + ->method('isAdminUser') + ->will($this->returnValue(true)); + $api->expects($this->never()) + ->method('isSubAdminUser') + ->will($this->returnValue(true)); + $api->expects($this->never()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + + $sec = new SecurityMiddleware($api, $this->request); + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', + 'testNoChecks'); + } + + + private function securityCheck($method, $expects, $shouldFail=false){ + $api = $this->getAPI(); + $api->expects($this->once()) + ->method($expects) + ->will($this->returnValue(!$shouldFail)); + + $sec = new SecurityMiddleware($api, $this->request); + + if($shouldFail){ + $this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException'); + } + + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); + } + + + /** + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testCsrfCheck(){ + $this->securityCheck('testCsrfCheck', 'passesCSRFCheck'); + } + + + /** + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testFailCsrfCheck(){ + $this->securityCheck('testFailCsrfCheck', 'passesCSRFCheck', true); + } + + + /** + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testLoggedInCheck(){ + $this->securityCheck('testLoggedInCheck', 'isLoggedIn'); + } + + + /** + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testFailLoggedInCheck(){ + $this->securityCheck('testFailLoggedInCheck', 'isLoggedIn', true); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsSubAdminExemption + */ + public function testIsAdminCheck(){ + $this->securityCheck('testIsAdminCheck', 'isAdminUser'); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsSubAdminExemption + */ + public function testFailIsAdminCheck(){ + $this->securityCheck('testFailIsAdminCheck', 'isAdminUser', true); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + */ + public function testIsSubAdminCheck(){ + $this->securityCheck('testIsSubAdminCheck', 'isSubAdminUser'); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + */ + public function testFailIsSubAdminCheck(){ + $this->securityCheck('testFailIsSubAdminCheck', 'isSubAdminUser', true); + } + + + + public function testAfterExceptionNotCaughtThrowsItAgain(){ + $ex = new \Exception(); + $this->setExpectedException('\Exception'); + $this->middleware->afterException($this->controller, 'test', $ex); + } + + + public function testAfterExceptionReturnsRedirect(){ + $api = $this->getMock('OC\AppFramework\Core\API', array(), array('test')); + $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', + array(), array($api, new Request())); + + $this->request = new Request( + array('server' => array('HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'))); + $this->middleware = new SecurityMiddleware($api, $this->request); + $response = $this->middleware->afterException($this->controller, 'test', + $this->secException); + + $this->assertTrue($response instanceof RedirectResponse); + } + + + public function testAfterAjaxExceptionReturnsJSONError(){ + $response = $this->middleware->afterException($this->controller, 'test', + $this->secAjaxException); + + $this->assertTrue($response instanceof JSONResponse); + } + + +} diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php new file mode 100644 index 00000000000..92ad461471d --- /dev/null +++ b/tests/lib/appframework/routing/RoutingTest.php @@ -0,0 +1,214 @@ + array( + array('name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'GET') + )); + + $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + + public function testSimpleRouteWithMissingVerb() + { + $routes = array('routes' => array( + array('name' => 'folders#open', 'url' => '/folders/{folderId}/open') + )); + + $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + + public function testSimpleRouteWithLowercaseVerb() + { + $routes = array('routes' => array( + array('name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') + )); + + $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + + /** + * @expectedException \UnexpectedValueException + */ + public function testSimpleRouteWithBrokenName() + { + $routes = array('routes' => array( + array('name' => 'folders_open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') + )); + + // router mock + $router = $this->getMock("\OC_Router", array('create')); + + // load route configuration + $container = new DIContainer('app1'); + $config = new RouteConfig($container, $router, $routes); + + $config->register(); + } + + public function testSimpleRouteWithUnderScoreNames() + { + $routes = array('routes' => array( + array('name' => 'admin_folders#open_current', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') + )); + + $this->assertSimpleRoute($routes, 'admin_folders.open_current', 'DELETE', '/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent'); + } + + public function testResource() + { + $routes = array('resources' => array('accounts' => array('url' => '/accounts'))); + + $this->assertResource($routes, 'accounts', '/accounts', 'AccountsController', 'accountId'); + } + + public function testResourceWithUnderScoreName() + { + $routes = array('resources' => array('admin_accounts' => array('url' => '/admin/accounts'))); + + $this->assertResource($routes, 'admin_accounts', '/admin/accounts', 'AdminAccountsController', 'adminAccountId'); + } + + private function assertSimpleRoute($routes, $name, $verb, $url, $controllerName, $actionName) + { + // route mocks + $route = $this->mockRoute($verb, $controllerName, $actionName); + + // router mock + $router = $this->getMock("\OC_Router", array('create')); + + // we expect create to be called once: + $router + ->expects($this->once()) + ->method('create') + ->with($this->equalTo('app1.' . $name), $this->equalTo($url)) + ->will($this->returnValue($route)); + + // load route configuration + $container = new DIContainer('app1'); + $config = new RouteConfig($container, $router, $routes); + + $config->register(); + } + + private function assertResource($yaml, $resourceName, $url, $controllerName, $paramName) + { + // router mock + $router = $this->getMock("\OC_Router", array('create')); + + // route mocks + $indexRoute = $this->mockRoute('GET', $controllerName, 'index'); + $showRoute = $this->mockRoute('GET', $controllerName, 'show'); + $createRoute = $this->mockRoute('POST', $controllerName, 'create'); + $updateRoute = $this->mockRoute('PUT', $controllerName, 'update'); + $destroyRoute = $this->mockRoute('DELETE', $controllerName, 'destroy'); + + $urlWithParam = $url . '/{' . $paramName . '}'; + + // we expect create to be called once: + $router + ->expects($this->at(0)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.index'), $this->equalTo($url)) + ->will($this->returnValue($indexRoute)); + + $router + ->expects($this->at(1)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam)) + ->will($this->returnValue($showRoute)); + + $router + ->expects($this->at(2)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.create'), $this->equalTo($url)) + ->will($this->returnValue($createRoute)); + + $router + ->expects($this->at(3)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam)) + ->will($this->returnValue($updateRoute)); + + $router + ->expects($this->at(4)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam)) + ->will($this->returnValue($destroyRoute)); + + // load route configuration + $container = new DIContainer('app1'); + $config = new RouteConfig($container, $router, $yaml); + + $config->register(); + } + + /** + * @param $verb + * @param $controllerName + * @param $actionName + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function mockRoute($verb, $controllerName, $actionName) + { + $container = new DIContainer('app1'); + $route = $this->getMock("\OC_Route", array('method', 'action'), array(), '', false); + $route + ->expects($this->exactly(1)) + ->method('method') + ->with($this->equalTo($verb)) + ->will($this->returnValue($route)); + + $route + ->expects($this->exactly(1)) + ->method('action') + ->with($this->equalTo(new RouteActionHandler($container, $controllerName, $actionName))) + ->will($this->returnValue($route)); + return $route; + } + +} + +/* +# +# sample routes.yaml for ownCloud +# +# the section simple describes one route + +routes: + - name: folders#open + url: /folders/{folderId}/open + verb: GET + # controller: name.split()[0] + # action: name.split()[1] + +# for a resource following actions will be generated: +# - index +# - create +# - show +# - update +# - destroy +# - new +resources: + accounts: + url: /accounts + + folders: + url: /accounts/{accountId}/folders + # actions can be used to define additional actions on the resource + actions: + - name: validate + verb: GET + on-collection: false + + * */ diff --git a/tests/lib/appframework/utility/MethodAnnotationReaderTest.php b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php new file mode 100644 index 00000000000..bcdcf3de37b --- /dev/null +++ b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php @@ -0,0 +1,58 @@ +. + * + */ + + +namespace OC\AppFramework\Utility; + + +require_once __DIR__ . "/../classloader.php"; + + +class MethodAnnotationReaderTest extends \PHPUnit_Framework_TestCase { + + + /** + * @Annotation + */ + public function testReadAnnotation(){ + $reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', + 'testReadAnnotation'); + + $this->assertTrue($reader->hasAnnotation('Annotation')); + } + + + /** + * @Annotation + * @param test + */ + public function testReadAnnotationNoLowercase(){ + $reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', + 'testReadAnnotationNoLowercase'); + + $this->assertTrue($reader->hasAnnotation('Annotation')); + $this->assertFalse($reader->hasAnnotation('param')); + } + + +} -- cgit v1.2.3 From 3324495a7882cb7957c5ffd498b1b6275a192b32 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 17 Aug 2013 18:26:53 +0200 Subject: pulling in 3rdparty submodule --- 3rdparty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty b/3rdparty index 8d68fa1eabe..75a05d76ab8 160000 --- a/3rdparty +++ b/3rdparty @@ -1 +1 @@ -Subproject commit 8d68fa1eabe8c1d033cb89676b31f0eaaf99335b +Subproject commit 75a05d76ab86ba7454b4312fd0ff2ca5bd5828cf -- cgit v1.2.3 From 72e1a8d83b3a21875cac6948879471661d120c52 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 12:47:23 +0200 Subject: fixing require to Pimple --- lib/appframework/dependencyinjection/dicontainer.php | 2 +- tests/lib/appframework/AppTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 34f64e72cb9..d6cf4d55020 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -34,7 +34,7 @@ use OC\AppFramework\Middleware\Security\SecurityMiddleware; use OC\AppFramework\Utility\TimeFactory; // register 3rdparty autoloaders -require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; +require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; /** diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index 000094d07c8..6e647f68e6f 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -29,7 +29,7 @@ use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; // FIXME: loading pimpl correctly from 3rdparty repo -require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; +require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; require_once __DIR__ . "/classloader.php"; -- cgit v1.2.3 From 0fa2e1b3d91d243452ffdfd36dbd0bed3f27e387 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 12:48:45 +0200 Subject: there is no HttpMiddleware --- lib/appframework/dependencyinjection/dicontainer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index d6cf4d55020..69c645b1be3 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -29,7 +29,6 @@ use OC\AppFramework\Http\Request; use OC\AppFramework\Http\Dispatcher; use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; -use OC\AppFramework\Middleware\Http\HttpMiddleware; use OC\AppFramework\Middleware\Security\SecurityMiddleware; use OC\AppFramework\Utility\TimeFactory; -- cgit v1.2.3 From 0fa8f380767369b4aa85f5944a8e921009b1ed27 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 16:51:12 +0200 Subject: fixing broken test --- tests/lib/appframework/AppTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index 6e647f68e6f..dcf0e6f77e3 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -46,7 +46,7 @@ class AppTest extends \PHPUnit_Framework_TestCase { private $controllerMethod; protected function setUp() { - $this->container = new \Pimple(); + $this->container = new \OC\AppFramework\DependencyInjection\DIContainer('test'); $this->controller = $this->getMockBuilder( 'OC\AppFramework\Controller\Controller') ->disableOriginalConstructor() -- cgit v1.2.3 From cdada78aa4acd2880e0344a476d3c1d838645ae5 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 17:20:36 +0200 Subject: typos & unused var fixed --- lib/appframework/http/dispatcher.php | 11 +++++------ lib/appframework/http/downloadresponse.php | 1 - 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/appframework/http/dispatcher.php b/lib/appframework/http/dispatcher.php index ab5644274fa..183854650fb 100644 --- a/lib/appframework/http/dispatcher.php +++ b/lib/appframework/http/dispatcher.php @@ -29,7 +29,7 @@ use \OC\AppFramework\Middleware\MiddlewareDispatcher; /** - * Class to dispatch the request to the middleware disptacher + * Class to dispatch the request to the middleware dispatcher */ class Dispatcher { @@ -67,11 +67,10 @@ class Dispatcher { $methodName); $response = $controller->$methodName(); - - // if an exception appears, the middleware checks if it can handle the - // exception and creates a response. If no response is created, it is - // assumed that theres no middleware who can handle it and the error is - // thrown again + // if an exception appears, the middleware checks if it can handle the + // exception and creates a response. If no response is created, it is + // assumed that theres no middleware who can handle it and the error is + // thrown again } catch(\Exception $exception){ $response = $this->middlewareDispatcher->afterException( $controller, $methodName, $exception); diff --git a/lib/appframework/http/downloadresponse.php b/lib/appframework/http/downloadresponse.php index 5a0db325fe6..096e4fc8331 100644 --- a/lib/appframework/http/downloadresponse.php +++ b/lib/appframework/http/downloadresponse.php @@ -30,7 +30,6 @@ namespace OC\AppFramework\Http; */ abstract class DownloadResponse extends Response { - private $content; private $filename; private $contentType; -- cgit v1.2.3 From 93194bb39617d4b11a0a84b8cd4caf0491155961 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 17:21:14 +0200 Subject: Introducing IContainer into public api --- .../dependencyinjection/dicontainer.php | 22 +++++------ lib/appframework/utility/simplecontainer.php | 44 ++++++++++++++++++++++ tests/lib/appframework/classloader.php | 9 +++++ 3 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 lib/appframework/utility/simplecontainer.php diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 69c645b1be3..88ad2cd414a 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -30,19 +30,11 @@ use OC\AppFramework\Http\Dispatcher; use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; use OC\AppFramework\Middleware\Security\SecurityMiddleware; +use OC\AppFramework\Utility\SimpleContainer; use OC\AppFramework\Utility\TimeFactory; -// register 3rdparty autoloaders -require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; - -/** - * This class extends Pimple (http://pimple.sensiolabs.org/) for reusability - * To use this class, extend your own container from this. Should you require it - * you can overwrite the dependencies with your own classes by simply redefining - * a dependency - */ -class DIContainer extends \Pimple { +class DIContainer extends SimpleContainer { /** @@ -61,8 +53,14 @@ class DIContainer extends \Pimple { * Http */ $this['Request'] = $this->share(function($c) { - $params = json_decode(file_get_contents('php://input'), true); - $params = is_array($params) ? $params: array(); + + $params = array(); + + // we json decode the body only in case of content type json + if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') === true ) { + $params = json_decode(file_get_contents('php://input'), true); + $params = is_array($params) ? $params: array(); + } return new Request( array( diff --git a/lib/appframework/utility/simplecontainer.php b/lib/appframework/utility/simplecontainer.php new file mode 100644 index 00000000000..04b6cd727b8 --- /dev/null +++ b/lib/appframework/utility/simplecontainer.php @@ -0,0 +1,44 @@ +offsetGet($name); + } + + function registerParameter($name, $value) + { + $this[$name] = $value; + } + + /** + * The given closure is call the first time the given service is queried. + * The closure has to return the instance for the given service. + * Created instance will be cached in case $shared is true. + * + * @param string $name name of the service to register another backend for + * @param callable $closure the closure to be called on service creation + */ + function registerService($name, \Closure $closure, $shared = true) + { + if ($shared) { + $this[$name] = \Pimple::share($closure); + } else { + $this[$name] = $closure; + } + } +} diff --git a/tests/lib/appframework/classloader.php b/tests/lib/appframework/classloader.php index ae485e67b2c..cd9f893df30 100644 --- a/tests/lib/appframework/classloader.php +++ b/tests/lib/appframework/classloader.php @@ -32,6 +32,15 @@ spl_autoload_register(function ($className){ } } + if (strpos($className, 'OCP\\') === 0) { + $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $relPath = __DIR__ . '/../../../lib/public' . $path; + + if(file_exists($relPath)){ + require_once $relPath; + } + } + // FIXME: this will most probably not work anymore if (strpos($className, 'OCA\\') === 0) { -- cgit v1.2.3 From 6e1946ab00cca760d555222df008ba92b0185eca Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 17:22:33 +0200 Subject: Introducing IContainer into public api --- lib/public/core/icontainer.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 lib/public/core/icontainer.php diff --git a/lib/public/core/icontainer.php b/lib/public/core/icontainer.php new file mode 100644 index 00000000000..a6c93abec67 --- /dev/null +++ b/lib/public/core/icontainer.php @@ -0,0 +1,19 @@ + Date: Tue, 20 Aug 2013 17:53:58 +0200 Subject: Introducing IRequest --- lib/appframework/http/request.php | 111 +++++++++++++++++++++++++++++++++++++- lib/public/core/irequest.php | 88 ++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 lib/public/core/irequest.php diff --git a/lib/appframework/http/request.php b/lib/appframework/http/request.php index 7d024c8605f..ab72a8db697 100644 --- a/lib/appframework/http/request.php +++ b/lib/appframework/http/request.php @@ -22,12 +22,14 @@ namespace OC\AppFramework\Http; +use OCP\Core\IRequest; + /** * Class for accessing variables in the request. * This class provides an immutable object with request variables. */ -class Request implements \ArrayAccess, \Countable { +class Request implements \ArrayAccess, \Countable, IRequest { protected $items = array(); protected $allowedKeys = array( @@ -214,4 +216,111 @@ class Request implements \ArrayAccess, \Countable { return null; } + /** + * Lets you access post and get parameters by the index + * In case of json requests the encoded json body is accessed + * + * @param string $key the key which you want to access in the URL Parameter + * placeholder, $_POST or $_GET array. + * The priority how they're returned is the following: + * 1. URL parameters + * 2. POST parameters + * 3. GET parameters + * @param mixed $default If the key is not found, this value will be returned + * @return mixed the content of the array + */ + public function getParam($key, $default = null) + { + return isset($this->parameters[$key]) + ? $this->parameters[$key] + : $default; + } + + /** + * Returns all params that were received, be it from the request + * (as GET or POST) or throuh the URL by the route + * @return array the array with all parameters + */ + public function getParams() + { + return $this->parameters; + } + + /** + * Returns the method of the request + * @return string the method of the request (POST, GET, etc) + */ + public function getMethod() + { + return $this->method; + } + + /** + * Shortcut for accessing an uploaded file through the $_FILES array + * @param string $key the key that will be taken from the $_FILES array + * @return array the file in the $_FILES element + */ + public function getUploadedFile($key) + { + return isset($this->files[$key]) ? $this->files[$key] : null; + } + + /** + * Shortcut for getting env variables + * @param string $key the key that will be taken from the $_ENV array + * @return array the value in the $_ENV element + */ + public function getEnv($key) + { + return isset($this->env[$key]) ? $this->env[$key] : null; + } + + /** + * Shortcut for getting session variables + * @param string $key the key that will be taken from the $_SESSION array + * @return array the value in the $_SESSION element + */ + function getSession($key) + { + return isset($this->session[$key]) ? $this->session[$key] : null; + } + + /** + * Shortcut for getting cookie variables + * @param string $key the key that will be taken from the $_COOKIE array + * @return array the value in the $_COOKIE element + */ + function getCookie($key) + { + return isset($this->cookies[$key]) ? $this->cookies[$key] : null; + } + + /** + * Returns the request body content. + * + * @param Boolean $asResource If true, a resource will be returned + * + * @return string|resource The request body content or a resource to read the body stream. + * + * @throws \LogicException + */ + function getContent($asResource = false) + { + return null; +// if (false === $this->content || (true === $asResource && null !== $this->content)) { +// throw new \LogicException('getContent() can only be called once when using the resource return type.'); +// } +// +// if (true === $asResource) { +// $this->content = false; +// +// return fopen('php://input', 'rb'); +// } +// +// if (null === $this->content) { +// $this->content = file_get_contents('php://input'); +// } +// +// return $this->content; + } } diff --git a/lib/public/core/irequest.php b/lib/public/core/irequest.php new file mode 100644 index 00000000000..f283e9cb25c --- /dev/null +++ b/lib/public/core/irequest.php @@ -0,0 +1,88 @@ + Date: Tue, 20 Aug 2013 21:05:55 +0200 Subject: controller reuses IRequest methods --- lib/appframework/controller/controller.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/appframework/controller/controller.php b/lib/appframework/controller/controller.php index 3e8166050d7..f6f34618ec6 100644 --- a/lib/appframework/controller/controller.php +++ b/lib/appframework/controller/controller.php @@ -63,9 +63,7 @@ abstract class Controller { * @return mixed the content of the array */ public function params($key, $default=null){ - return isset($this->request->parameters[$key]) - ? $this->request->parameters[$key] - : $default; + return $this->request->getParam($key, $default); } @@ -75,7 +73,7 @@ abstract class Controller { * @return array the array with all parameters */ public function getParams() { - return $this->request->parameters; + return $this->request->getParams(); } @@ -84,7 +82,7 @@ abstract class Controller { * @return string the method of the request (POST, GET, etc) */ public function method() { - return $this->request->method; + return $this->request->getMethod(); } @@ -94,7 +92,7 @@ abstract class Controller { * @return array the file in the $_FILES element */ public function getUploadedFile($key) { - return isset($this->request->files[$key]) ? $this->request->files[$key] : null; + return $this->request->getUploadedFile($key); } @@ -104,7 +102,7 @@ abstract class Controller { * @return array the value in the $_ENV element */ public function env($key) { - return isset($this->request->env[$key]) ? $this->request->env[$key] : null; + return $this->request->getEnv($key); } @@ -114,7 +112,7 @@ abstract class Controller { * @return array the value in the $_SESSION element */ public function session($key) { - return isset($this->request->session[$key]) ? $this->request->session[$key] : null; + return $this->request->getSession($key); } @@ -124,7 +122,7 @@ abstract class Controller { * @return array the value in the $_COOKIE element */ public function cookie($key) { - return isset($this->request->cookies[$key]) ? $this->request->cookies[$key] : null; + return $this->request->getCookie($key); } -- cgit v1.2.3 From 395deacc6760564544a76338023d9b0bf39e0bfe Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 21:21:21 +0200 Subject: reducing controller annotations to: @PublicPage - No user logon is expected @NoAdminRequired - the login user requires no admin rights @NoCSRFRequired - the incoming request will not check for CSRF token --- .../middleware/security/securitymiddleware.php | 19 +-- .../middleware/security/SecurityMiddlewareTest.php | 156 +++++---------------- 2 files changed, 41 insertions(+), 134 deletions(-) diff --git a/lib/appframework/middleware/security/securitymiddleware.php b/lib/appframework/middleware/security/securitymiddleware.php index 7a715f309a0..52818b1b53e 100644 --- a/lib/appframework/middleware/security/securitymiddleware.php +++ b/lib/appframework/middleware/security/securitymiddleware.php @@ -77,25 +77,20 @@ class SecurityMiddleware extends Middleware { $this->api->activateNavigationEntry(); // security checks - if(!$annotationReader->hasAnnotation('IsLoggedInExemption')) { + $isPublicPage = $annotationReader->hasAnnotation('PublicPage'); + if(!$isPublicPage) { if(!$this->api->isLoggedIn()) { throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); } - } - - if(!$annotationReader->hasAnnotation('IsAdminExemption')) { - if(!$this->api->isAdminUser($this->api->getUserId())) { - throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); - } - } - if(!$annotationReader->hasAnnotation('IsSubAdminExemption')) { - if(!$this->api->isSubAdminUser($this->api->getUserId())) { - throw new SecurityException('Logged in user must be a subadmin', Http::STATUS_FORBIDDEN); + if(!$annotationReader->hasAnnotation('NoAdminRequired')) { + if(!$this->api->isAdminUser($this->api->getUserId())) { + throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); + } } } - if(!$annotationReader->hasAnnotation('CSRFExemption')) { + if(!$annotationReader->hasAnnotation('NoCSRFRequired')) { if(!$this->api->passesCSRFCheck()) { throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); } diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php index 0b2103564e4..90a19c9999d 100644 --- a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php +++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php @@ -80,67 +80,27 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage + * @NoCSRFRequired */ public function testSetNavigationEntry(){ $this->checkNavEntry('testSetNavigationEntry', true); } - private function ajaxExceptionCheck($method, $shouldBeAjax=false){ - $api = $this->getAPI(); - $api->expects($this->any()) - ->method('passesCSRFCheck') - ->will($this->returnValue(false)); - - $sec = new SecurityMiddleware($api, $this->request); - - try { - $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', - $method); - } catch (SecurityException $ex){ - if($shouldBeAjax){ - $this->assertTrue($ex->isAjax()); - } else { - $this->assertFalse($ex->isAjax()); - } - - } - } - - - /** - * @Ajax - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption - */ - public function testAjaxException(){ - $this->ajaxExceptionCheck('testAjaxException'); - } - - - /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption - */ - public function testNoAjaxException(){ - $this->ajaxExceptionCheck('testNoAjaxException'); - } - - private function ajaxExceptionStatus($method, $test, $status) { $api = $this->getAPI(); $api->expects($this->any()) ->method($test) ->will($this->returnValue(false)); + // isAdminUser requires isLoggedIn call to return true + if ($test === 'isAdminUser') { + $api->expects($this->any()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + } + $sec = new SecurityMiddleware($api, $this->request); try { @@ -151,9 +111,6 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } } - /** - * @Ajax - */ public function testAjaxStatusLoggedInCheck() { $this->ajaxExceptionStatus( 'testAjaxStatusLoggedInCheck', @@ -163,8 +120,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } /** - * @Ajax - * @IsLoggedInExemption + * @NoCSRFRequired + * @NoAdminRequired */ public function testAjaxNotAdminCheck() { $this->ajaxExceptionStatus( @@ -175,23 +132,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } /** - * @Ajax - * @IsLoggedInExemption - * @IsAdminExemption - */ - public function testAjaxNotSubAdminCheck() { - $this->ajaxExceptionStatus( - 'testAjaxNotSubAdminCheck', - 'isSubAdminUser', - Http::STATUS_FORBIDDEN - ); - } - - /** - * @Ajax - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage */ public function testAjaxStatusCSRFCheck() { $this->ajaxExceptionStatus( @@ -202,11 +143,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } /** - * @Ajax - * @CSRFExemption - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage + * @NoCSRFRequired */ public function testAjaxStatusAllGood() { $this->ajaxExceptionStatus( @@ -231,11 +169,10 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { ); } + /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage + * @NoCSRFRequired */ public function testNoChecks(){ $api = $this->getAPI(); @@ -245,9 +182,6 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { $api->expects($this->never()) ->method('isAdminUser') ->will($this->returnValue(true)); - $api->expects($this->never()) - ->method('isSubAdminUser') - ->will($this->returnValue(true)); $api->expects($this->never()) ->method('isLoggedIn') ->will($this->returnValue(true)); @@ -264,10 +198,19 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { ->method($expects) ->will($this->returnValue(!$shouldFail)); + // admin check requires login + if ($expects === 'isAdminUser') { + $api->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + } + $sec = new SecurityMiddleware($api, $this->request); if($shouldFail){ $this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException'); + } else { + $this->setExpectedException(null); } $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); @@ -275,9 +218,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage */ public function testCsrfCheck(){ $this->securityCheck('testCsrfCheck', 'passesCSRFCheck'); @@ -285,9 +226,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage */ public function testFailCsrfCheck(){ $this->securityCheck('testFailCsrfCheck', 'passesCSRFCheck', true); @@ -295,9 +234,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @NoCSRFRequired + * @NoAdminRequired */ public function testLoggedInCheck(){ $this->securityCheck('testLoggedInCheck', 'isLoggedIn'); @@ -305,9 +243,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @NoCSRFRequired + * @NoAdminRequired */ public function testFailLoggedInCheck(){ $this->securityCheck('testFailLoggedInCheck', 'isLoggedIn', true); @@ -315,9 +252,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsSubAdminExemption + * @NoCSRFRequired */ public function testIsAdminCheck(){ $this->securityCheck('testIsAdminCheck', 'isAdminUser'); @@ -325,36 +260,13 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsSubAdminExemption + * @NoCSRFRequired */ public function testFailIsAdminCheck(){ $this->securityCheck('testFailIsAdminCheck', 'isAdminUser', true); } - /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - */ - public function testIsSubAdminCheck(){ - $this->securityCheck('testIsSubAdminCheck', 'isSubAdminUser'); - } - - - /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - */ - public function testFailIsSubAdminCheck(){ - $this->securityCheck('testFailIsSubAdminCheck', 'isSubAdminUser', true); - } - - - public function testAfterExceptionNotCaughtThrowsItAgain(){ $ex = new \Exception(); $this->setExpectedException('\Exception'); -- cgit v1.2.3 From 33db8a3089760947eec93149a2029164b676eae8 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 21 Aug 2013 00:41:20 +0200 Subject: kill superfluent classloader from tests - this approach might be of interest within the apps --- tests/lib/appframework/AppTest.php | 2 +- tests/lib/appframework/classloader.php | 54 ---------------------- .../lib/appframework/controller/ControllerTest.php | 5 +- .../dependencyinjection/DIContainerTest.php | 2 +- tests/lib/appframework/http/DispatcherTest.php | 6 +-- .../lib/appframework/http/DownloadResponseTest.php | 2 +- tests/lib/appframework/http/HttpTest.php | 2 +- tests/lib/appframework/http/JSONResponseTest.php | 4 +- .../lib/appframework/http/RedirectResponseTest.php | 2 +- tests/lib/appframework/http/RequestTest.php | 2 - tests/lib/appframework/http/ResponseTest.php | 7 +-- .../lib/appframework/http/TemplateResponseTest.php | 12 +++-- .../middleware/MiddlewareDispatcherTest.php | 6 +-- .../lib/appframework/middleware/MiddlewareTest.php | 11 +++-- .../middleware/security/SecurityMiddlewareTest.php | 6 +-- tests/lib/appframework/routing/RoutingTest.php | 1 - .../utility/MethodAnnotationReaderTest.php | 3 -- 17 files changed, 33 insertions(+), 94 deletions(-) delete mode 100644 tests/lib/appframework/classloader.php diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index dcf0e6f77e3..e8ae8c8f673 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -30,7 +30,7 @@ use OC\AppFramework\Middleware\MiddlewareDispatcher; // FIXME: loading pimpl correctly from 3rdparty repo require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; -require_once __DIR__ . "/classloader.php"; +//require_once __DIR__ . "/classloader.php"; class AppTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/classloader.php b/tests/lib/appframework/classloader.php deleted file mode 100644 index cd9f893df30..00000000000 --- a/tests/lib/appframework/classloader.php +++ /dev/null @@ -1,54 +0,0 @@ -. - * - */ - -// to execute without ownCloud, we need to create our own class loader -spl_autoload_register(function ($className){ - if (strpos($className, 'OC\\AppFramework') === 0) { - $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - $relPath = __DIR__ . '/../../../lib/' . $path; - - if(file_exists($relPath)){ - require_once $relPath; - } - } - - if (strpos($className, 'OCP\\') === 0) { - $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - $relPath = __DIR__ . '/../../../lib/public' . $path; - - if(file_exists($relPath)){ - require_once $relPath; - } - } - - // FIXME: this will most probably not work anymore - if (strpos($className, 'OCA\\') === 0) { - - $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - $relPath = __DIR__ . '/../..' . $path; - - if(file_exists($relPath)){ - require_once $relPath; - } - } -}); diff --git a/tests/lib/appframework/controller/ControllerTest.php b/tests/lib/appframework/controller/ControllerTest.php index d8357c2a685..246371d249c 100644 --- a/tests/lib/appframework/controller/ControllerTest.php +++ b/tests/lib/appframework/controller/ControllerTest.php @@ -25,12 +25,11 @@ namespace Test\AppFramework\Controller; use OC\AppFramework\Http\Request; -use OC\AppFramework\Http\JSONResponse; -use OC\AppFramework\Http\TemplateResponse; use OC\AppFramework\Controller\Controller; +use OCP\AppFramework\Http\TemplateResponse; -require_once(__DIR__ . "/../classloader.php"); +//require_once __DIR__ . "/../classloader.php"; class ChildController extends Controller {}; diff --git a/tests/lib/appframework/dependencyinjection/DIContainerTest.php b/tests/lib/appframework/dependencyinjection/DIContainerTest.php index ce346f0a763..25fdd202839 100644 --- a/tests/lib/appframework/dependencyinjection/DIContainerTest.php +++ b/tests/lib/appframework/dependencyinjection/DIContainerTest.php @@ -29,7 +29,7 @@ namespace OC\AppFramework\DependencyInjection; use \OC\AppFramework\Http\Request; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); class DIContainerTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/http/DispatcherTest.php b/tests/lib/appframework/http/DispatcherTest.php index 2e3db110504..849b0ca97a6 100644 --- a/tests/lib/appframework/http/DispatcherTest.php +++ b/tests/lib/appframework/http/DispatcherTest.php @@ -27,7 +27,7 @@ namespace OC\AppFramework\Http; use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); class DispatcherTest extends \PHPUnit_Framework_TestCase { @@ -69,7 +69,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { $this->http, $this->middlewareDispatcher); $this->response = $this->getMockBuilder( - '\OC\AppFramework\Http\Response') + '\OCP\AppFramework\Http\Response') ->disableOriginalConstructor() ->getMock(); @@ -207,7 +207,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { $out = 'yo'; $httpHeaders = 'Http'; $responseHeaders = array('hell' => 'yeah'); - $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); $this->setExpectedException('\Exception'); $response = $this->dispatcher->dispatch($this->controller, diff --git a/tests/lib/appframework/http/DownloadResponseTest.php b/tests/lib/appframework/http/DownloadResponseTest.php index 103cfe7588c..64fe7992b6a 100644 --- a/tests/lib/appframework/http/DownloadResponseTest.php +++ b/tests/lib/appframework/http/DownloadResponseTest.php @@ -25,7 +25,7 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); class ChildDownloadResponse extends DownloadResponse {}; diff --git a/tests/lib/appframework/http/HttpTest.php b/tests/lib/appframework/http/HttpTest.php index 306bc3caf42..382d511b116 100644 --- a/tests/lib/appframework/http/HttpTest.php +++ b/tests/lib/appframework/http/HttpTest.php @@ -25,7 +25,7 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); diff --git a/tests/lib/appframework/http/JSONResponseTest.php b/tests/lib/appframework/http/JSONResponseTest.php index d15e08f6ce1..534c54cbcee 100644 --- a/tests/lib/appframework/http/JSONResponseTest.php +++ b/tests/lib/appframework/http/JSONResponseTest.php @@ -27,7 +27,9 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +use OCP\AppFramework\Http\JSONResponse; + +//require_once(__DIR__ . "/../classloader.php"); diff --git a/tests/lib/appframework/http/RedirectResponseTest.php b/tests/lib/appframework/http/RedirectResponseTest.php index a8577feed29..1946655b0fa 100644 --- a/tests/lib/appframework/http/RedirectResponseTest.php +++ b/tests/lib/appframework/http/RedirectResponseTest.php @@ -25,7 +25,7 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); diff --git a/tests/lib/appframework/http/RequestTest.php b/tests/lib/appframework/http/RequestTest.php index c1f56c01636..0371c870cf2 100644 --- a/tests/lib/appframework/http/RequestTest.php +++ b/tests/lib/appframework/http/RequestTest.php @@ -9,8 +9,6 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); - class RequestTest extends \PHPUnit_Framework_TestCase { public function testRequestAccessors() { diff --git a/tests/lib/appframework/http/ResponseTest.php b/tests/lib/appframework/http/ResponseTest.php index 621ba66545f..7e09086f801 100644 --- a/tests/lib/appframework/http/ResponseTest.php +++ b/tests/lib/appframework/http/ResponseTest.php @@ -25,13 +25,14 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); - +use OCP\AppFramework\Http\Response; class ResponseTest extends \PHPUnit_Framework_TestCase { - + /** + * @var \OCP\AppFramework\Http\Response + */ private $childResponse; protected function setUp(){ diff --git a/tests/lib/appframework/http/TemplateResponseTest.php b/tests/lib/appframework/http/TemplateResponseTest.php index 30684725b72..3c6d29cd339 100644 --- a/tests/lib/appframework/http/TemplateResponseTest.php +++ b/tests/lib/appframework/http/TemplateResponseTest.php @@ -24,15 +24,19 @@ namespace OC\AppFramework\Http; -use OC\AppFramework\Core\API; - - -require_once(__DIR__ . "/../classloader.php"); +use OCP\AppFramework\Http\TemplateResponse; class TemplateResponseTest extends \PHPUnit_Framework_TestCase { + /** + * @var \OCP\AppFramework\Http\TemplateResponse + */ private $tpl; + + /** + * @var \OCP\AppFramework\IApi + */ private $api; protected function setUp() { diff --git a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php index bfa54a48ea3..d1b2fedee58 100644 --- a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php +++ b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php @@ -24,14 +24,10 @@ namespace OC\AppFramework; -use OC\AppFramework\Controller\Controller; use OC\AppFramework\Http\Request; -use OC\AppFramework\Http\Response; use OC\AppFramework\Middleware\Middleware; use OC\AppFramework\Middleware\MiddlewareDispatcher; - - -require_once(__DIR__ . "/../classloader.php"); +use OCP\AppFramework\Http\Response; // needed to test ordering diff --git a/tests/lib/appframework/middleware/MiddlewareTest.php b/tests/lib/appframework/middleware/MiddlewareTest.php index 1adce6b3d4f..5e2930ac6a3 100644 --- a/tests/lib/appframework/middleware/MiddlewareTest.php +++ b/tests/lib/appframework/middleware/MiddlewareTest.php @@ -28,14 +28,14 @@ use OC\AppFramework\Http\Request; use OC\AppFramework\Middleware\Middleware; -require_once(__DIR__ . "/../classloader.php"); - - class ChildMiddleware extends Middleware {}; class MiddlewareTest extends \PHPUnit_Framework_TestCase { + /** + * @var Middleware + */ private $middleware; private $controller; private $exception; @@ -50,12 +50,13 @@ class MiddlewareTest extends \PHPUnit_Framework_TestCase { $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', array(), array($this->api, new Request())); $this->exception = new \Exception(); - $this->response = $this->getMock('OC\AppFramework\Http\Response'); + $this->response = $this->getMock('OCP\AppFramework\Http\Response'); } public function testBeforeController() { - $this->middleware->beforeController($this->controller, null, $this->exception); + $this->middleware->beforeController($this->controller, null); + $this->assertNull(null); } diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php index 90a19c9999d..3ed44282a7b 100644 --- a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php +++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php @@ -27,11 +27,7 @@ namespace OC\AppFramework\Middleware\Security; use OC\AppFramework\Http\Http; use OC\AppFramework\Http\Request; use OC\AppFramework\Http\RedirectResponse; -use OC\AppFramework\Http\JSONResponse; -use OC\AppFramework\Middleware\Middleware; - - -require_once(__DIR__ . "/../../classloader.php"); +use OCP\AppFramework\Http\JSONResponse; class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php index 92ad461471d..a7aa922db12 100644 --- a/tests/lib/appframework/routing/RoutingTest.php +++ b/tests/lib/appframework/routing/RoutingTest.php @@ -5,7 +5,6 @@ namespace OC\AppFramework\Routing; use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\routing\RouteConfig; -require_once(__DIR__ . "/../classloader.php"); class RouteConfigTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/utility/MethodAnnotationReaderTest.php b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php index bcdcf3de37b..c68812aa5c7 100644 --- a/tests/lib/appframework/utility/MethodAnnotationReaderTest.php +++ b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php @@ -25,9 +25,6 @@ namespace OC\AppFramework\Utility; -require_once __DIR__ . "/../classloader.php"; - - class MethodAnnotationReaderTest extends \PHPUnit_Framework_TestCase { -- cgit v1.2.3 From aa979f5dff4234a3db9e6fb1ddc50335c04c194b Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 21 Aug 2013 00:44:39 +0200 Subject: cleanup of tests --- tests/lib/appframework/AppTest.php | 8 -------- .../middleware/MiddlewareDispatcherTest.php | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index e8ae8c8f673..80abaefc43b 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -24,14 +24,6 @@ namespace OC\AppFramework; -use OC\AppFramework\Http\Request; -use OC\AppFramework\Core\API; -use OC\AppFramework\Middleware\MiddlewareDispatcher; - -// FIXME: loading pimpl correctly from 3rdparty repo -require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; -//require_once __DIR__ . "/classloader.php"; - class AppTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php index d1b2fedee58..43727846dcf 100644 --- a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php +++ b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php @@ -99,6 +99,15 @@ class TestMiddleware extends Middleware { class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { + public $exception; + public $response; + private $out; + private $method; + private $controller; + + /** + * @var MiddlewareDispatcher + */ private $dispatcher; @@ -107,7 +116,7 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { $this->controller = $this->getControllerMock(); $this->method = 'method'; $this->response = new Response(); - $this->output = 'hi'; + $this->out = 'hi'; $this->exception = new \Exception(); } @@ -202,11 +211,11 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { public function testBeforeOutputCorrectArguments(){ $m1 = $this->getMiddleware(); - $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals($this->controller, $m1->controller); $this->assertEquals($this->method, $m1->methodName); - $this->assertEquals($this->output, $m1->output); + $this->assertEquals($this->out, $m1->output); } @@ -248,7 +257,7 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); - $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals(2, $m1->beforeOutputOrder); $this->assertEquals(1, $m2->beforeOutputOrder); @@ -268,7 +277,7 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { $this->dispatcher->registerMiddleware($m3); - $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals(2, $m1->beforeOutputOrder); $this->assertEquals(1, $m2->beforeOutputOrder); -- cgit v1.2.3 From ba029ef4b27cfeabbc67523131fa473397b77f01 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 21 Aug 2013 00:58:15 +0200 Subject: initial setup of the server container --- lib/base.php | 8 ++++++++ lib/public/core/iservercontainer.php | 14 ++++++++++++++ lib/server.php | 15 +++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 lib/public/core/iservercontainer.php create mode 100644 lib/server.php diff --git a/lib/base.php b/lib/base.php index eaee8424651..a81f1a59b8a 100644 --- a/lib/base.php +++ b/lib/base.php @@ -84,6 +84,11 @@ class OC { */ public static $loader = null; + /** + * @var \OC\Server + */ + public static $server = null; + public static function initPaths() { // calculate the root directories OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4)); @@ -361,6 +366,9 @@ class OC { self::$loader->registerPrefix('Patchwork', '3rdparty'); spl_autoload_register(array(self::$loader, 'load')); + // setup the basic server + self::$server = new \OC\Server(); + // set some stuff //ob_start(); error_reporting(E_ALL | E_STRICT); diff --git a/lib/public/core/iservercontainer.php b/lib/public/core/iservercontainer.php new file mode 100644 index 00000000000..df744ab6fdf --- /dev/null +++ b/lib/public/core/iservercontainer.php @@ -0,0 +1,14 @@ + Date: Wed, 21 Aug 2013 00:58:33 +0200 Subject: typo --- lib/public/core/irequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/core/irequest.php b/lib/public/core/irequest.php index f283e9cb25c..fc2004d1835 100644 --- a/lib/public/core/irequest.php +++ b/lib/public/core/irequest.php @@ -32,7 +32,7 @@ interface IRequest { /** * Returns all params that were received, be it from the request - * (as GET or POST) or throuh the URL by the route + * (as GET or POST) or through the URL by the route * @return array the array with all parameters */ public function getParams(); -- cgit v1.2.3 From 911bd3c16f508eb8f3cb9b03a5a21e2aa72ebf79 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 21 Aug 2013 01:00:26 +0200 Subject: moving response classes over to OCP --- lib/appframework/controller/controller.php | 4 +- lib/appframework/http/dispatcher.php | 3 + lib/appframework/http/downloadresponse.php | 2 +- lib/appframework/http/http.php | 62 +------- lib/appframework/http/jsonresponse.php | 74 --------- lib/appframework/http/redirectresponse.php | 2 + lib/appframework/http/response.php | 169 --------------------- lib/appframework/http/templateresponse.php | 126 --------------- lib/appframework/middleware/middleware.php | 2 +- .../middleware/middlewaredispatcher.php | 2 +- .../middleware/security/securitymiddleware.php | 4 +- lib/public/appframework/http/http.php | 89 +++++++++++ lib/public/appframework/http/jsonresponse.php | 74 +++++++++ lib/public/appframework/http/response.php | 169 +++++++++++++++++++++ lib/public/appframework/http/templateresponse.php | 126 +++++++++++++++ 15 files changed, 471 insertions(+), 437 deletions(-) delete mode 100644 lib/appframework/http/jsonresponse.php delete mode 100644 lib/appframework/http/response.php delete mode 100644 lib/appframework/http/templateresponse.php create mode 100644 lib/public/appframework/http/http.php create mode 100644 lib/public/appframework/http/jsonresponse.php create mode 100644 lib/public/appframework/http/response.php create mode 100644 lib/public/appframework/http/templateresponse.php diff --git a/lib/appframework/controller/controller.php b/lib/appframework/controller/controller.php index f6f34618ec6..a7498ba0e1e 100644 --- a/lib/appframework/controller/controller.php +++ b/lib/appframework/controller/controller.php @@ -24,9 +24,9 @@ namespace OC\AppFramework\Controller; -use OC\AppFramework\Http\TemplateResponse; use OC\AppFramework\Http\Request; use OC\AppFramework\Core\API; +use OCP\AppFramework\Http\TemplateResponse; /** @@ -133,7 +133,7 @@ abstract class Controller { * @param string $renderAs user renders a full page, blank only your template * admin an entry in the admin settings * @param array $headers set additional headers in name/value pairs - * @return \OC\AppFramework\Http\TemplateResponse containing the page + * @return \OCP\AppFramework\Http\TemplateResponse containing the page */ public function render($templateName, array $params=array(), $renderAs='user', array $headers=array()){ diff --git a/lib/appframework/http/dispatcher.php b/lib/appframework/http/dispatcher.php index 183854650fb..ea57a6860cc 100644 --- a/lib/appframework/http/dispatcher.php +++ b/lib/appframework/http/dispatcher.php @@ -74,6 +74,9 @@ class Dispatcher { } catch(\Exception $exception){ $response = $this->middlewareDispatcher->afterException( $controller, $methodName, $exception); + if (is_null($response)) { + throw $exception; + } } $response = $this->middlewareDispatcher->afterController( diff --git a/lib/appframework/http/downloadresponse.php b/lib/appframework/http/downloadresponse.php index 096e4fc8331..67b9542dba6 100644 --- a/lib/appframework/http/downloadresponse.php +++ b/lib/appframework/http/downloadresponse.php @@ -28,7 +28,7 @@ namespace OC\AppFramework\Http; /** * Prompts the user to download the a file */ -abstract class DownloadResponse extends Response { +class DownloadResponse extends \OCP\AppFramework\Http\Response { private $filename; private $contentType; diff --git a/lib/appframework/http/http.php b/lib/appframework/http/http.php index 73f32d13b38..e00dc9cdc4a 100644 --- a/lib/appframework/http/http.php +++ b/lib/appframework/http/http.php @@ -25,67 +25,7 @@ namespace OC\AppFramework\Http; -class Http { - - const STATUS_CONTINUE = 100; - const STATUS_SWITCHING_PROTOCOLS = 101; - const STATUS_PROCESSING = 102; - const STATUS_OK = 200; - const STATUS_CREATED = 201; - const STATUS_ACCEPTED = 202; - const STATUS_NON_AUTHORATIVE_INFORMATION = 203; - const STATUS_NO_CONTENT = 204; - const STATUS_RESET_CONTENT = 205; - const STATUS_PARTIAL_CONTENT = 206; - const STATUS_MULTI_STATUS = 207; - const STATUS_ALREADY_REPORTED = 208; - const STATUS_IM_USED = 226; - const STATUS_MULTIPLE_CHOICES = 300; - const STATUS_MOVED_PERMANENTLY = 301; - const STATUS_FOUND = 302; - const STATUS_SEE_OTHER = 303; - const STATUS_NOT_MODIFIED = 304; - const STATUS_USE_PROXY = 305; - const STATUS_RESERVED = 306; - const STATUS_TEMPORARY_REDIRECT = 307; - const STATUS_BAD_REQUEST = 400; - const STATUS_UNAUTHORIZED = 401; - const STATUS_PAYMENT_REQUIRED = 402; - const STATUS_FORBIDDEN = 403; - const STATUS_NOT_FOUND = 404; - const STATUS_METHOD_NOT_ALLOWED = 405; - const STATUS_NOT_ACCEPTABLE = 406; - const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; - const STATUS_REQUEST_TIMEOUT = 408; - const STATUS_CONFLICT = 409; - const STATUS_GONE = 410; - const STATUS_LENGTH_REQUIRED = 411; - const STATUS_PRECONDITION_FAILED = 412; - const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; - const STATUS_REQUEST_URI_TOO_LONG = 414; - const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; - const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416; - const STATUS_EXPECTATION_FAILED = 417; - const STATUS_IM_A_TEAPOT = 418; - const STATUS_UNPROCESSABLE_ENTITY = 422; - const STATUS_LOCKED = 423; - const STATUS_FAILED_DEPENDENCY = 424; - const STATUS_UPGRADE_REQUIRED = 426; - const STATUS_PRECONDITION_REQUIRED = 428; - const STATUS_TOO_MANY_REQUESTS = 429; - const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; - const STATUS_INTERNAL_SERVER_ERROR = 500; - const STATUS_NOT_IMPLEMENTED = 501; - const STATUS_BAD_GATEWAY = 502; - const STATUS_SERVICE_UNAVAILABLE = 503; - const STATUS_GATEWAY_TIMEOUT = 504; - const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505; - const STATUS_VARIANT_ALSO_NEGOTIATES = 506; - const STATUS_INSUFFICIENT_STORAGE = 507; - const STATUS_LOOP_DETECTED = 508; - const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509; - const STATUS_NOT_EXTENDED = 510; - const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; +class Http extends \OCP\AppFramework\Http\Http{ private $server; private $protocolVersion; diff --git a/lib/appframework/http/jsonresponse.php b/lib/appframework/http/jsonresponse.php deleted file mode 100644 index 750f8a2ad15..00000000000 --- a/lib/appframework/http/jsonresponse.php +++ /dev/null @@ -1,74 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Http; - - -/** - * A renderer for JSON calls - */ -class JSONResponse extends Response { - - protected $data; - - - /** - * @param array|object $data the object or array that should be transformed - * @param int $statusCode the Http status code, defaults to 200 - */ - public function __construct($data=array(), $statusCode=Http::STATUS_OK) { - $this->data = $data; - $this->setStatus($statusCode); - $this->addHeader('X-Content-Type-Options', 'nosniff'); - $this->addHeader('Content-type', 'application/json; charset=utf-8'); - } - - - /** - * Returns the rendered json - * @return string the rendered json - */ - public function render(){ - return json_encode($this->data); - } - - /** - * Sets values in the data json array - * @param array|object $params an array or object which will be transformed - * to JSON - */ - public function setData($data){ - $this->data = $data; - } - - - /** - * Used to get the set parameters - * @return array the data - */ - public function getData(){ - return $this->data; - } - -} diff --git a/lib/appframework/http/redirectresponse.php b/lib/appframework/http/redirectresponse.php index 727e0fb642e..688447f1618 100644 --- a/lib/appframework/http/redirectresponse.php +++ b/lib/appframework/http/redirectresponse.php @@ -24,6 +24,8 @@ namespace OC\AppFramework\Http; +use OCP\AppFramework\Http\Response; + /** * Redirects to a different URL diff --git a/lib/appframework/http/response.php b/lib/appframework/http/response.php deleted file mode 100644 index 50778105f24..00000000000 --- a/lib/appframework/http/response.php +++ /dev/null @@ -1,169 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Http; - - -/** - * Base class for responses. Also used to just send headers - */ -class Response { - - /** - * @var array default headers - */ - private $headers = array( - 'Cache-Control' => 'no-cache, must-revalidate' - ); - - - /** - * @var string - */ - private $status = Http::STATUS_OK; - - - /** - * @var \DateTime - */ - private $lastModified; - - - /** - * @var string - */ - private $ETag; - - - /** - * Caches the response - * @param int $cacheSeconds the amount of seconds that should be cached - * if 0 then caching will be disabled - */ - public function cacheFor($cacheSeconds) { - - if($cacheSeconds > 0) { - $this->addHeader('Cache-Control', 'max-age=' . $cacheSeconds . - ', must-revalidate'); - } else { - $this->addHeader('Cache-Control', 'no-cache, must-revalidate'); - } - - } - - - /** - * Adds a new header to the response that will be called before the render - * function - * @param string $name The name of the HTTP header - * @param string $value The value, null will delete it - */ - public function addHeader($name, $value) { - if(is_null($value)) { - unset($this->headers[$name]); - } else { - $this->headers[$name] = $value; - } - } - - - /** - * Returns the set headers - * @return array the headers - */ - public function getHeaders() { - $mergeWith = array(); - - if($this->lastModified) { - $mergeWith['Last-Modified'] = - $this->lastModified->format(\DateTime::RFC2822); - } - - if($this->ETag) { - $mergeWith['ETag'] = '"' . $this->ETag . '"'; - } - - return array_merge($mergeWith, $this->headers); - } - - - /** - * By default renders no output - * @return null - */ - public function render() { - return null; - } - - - /** - * Set response status - * @param int $status a HTTP status code, see also the STATUS constants - */ - public function setStatus($status) { - $this->status = $status; - } - - - /** - * Get response status - */ - public function getStatus() { - return $this->status; - } - - - /** - * @return string the etag - */ - public function getETag() { - return $this->ETag; - } - - - /** - * @return string RFC2822 formatted last modified date - */ - public function getLastModified() { - return $this->lastModified; - } - - - /** - * @param string $ETag - */ - public function setETag($ETag) { - $this->ETag = $ETag; - } - - - /** - * @param \DateTime $lastModified - */ - public function setLastModified($lastModified) { - $this->lastModified = $lastModified; - } - - -} diff --git a/lib/appframework/http/templateresponse.php b/lib/appframework/http/templateresponse.php deleted file mode 100644 index 0a32da4b1b4..00000000000 --- a/lib/appframework/http/templateresponse.php +++ /dev/null @@ -1,126 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Http; - -use OC\AppFramework\Core\API; - - -/** - * Response for a normal template - */ -class TemplateResponse extends Response { - - protected $templateName; - protected $params; - protected $api; - protected $renderAs; - protected $appName; - - /** - * @param API $api an API instance - * @param string $templateName the name of the template - * @param string $appName optional if you want to include a template from - * a different app - */ - public function __construct(API $api, $templateName, $appName=null) { - $this->templateName = $templateName; - $this->appName = $appName; - $this->api = $api; - $this->params = array(); - $this->renderAs = 'user'; - } - - - /** - * Sets template parameters - * @param array $params an array with key => value structure which sets template - * variables - */ - public function setParams(array $params){ - $this->params = $params; - } - - - /** - * Used for accessing the set parameters - * @return array the params - */ - public function getParams(){ - return $this->params; - } - - - /** - * Used for accessing the name of the set template - * @return string the name of the used template - */ - public function getTemplateName(){ - return $this->templateName; - } - - - /** - * Sets the template page - * @param string $renderAs admin, user or blank. Admin also prints the admin - * settings header and footer, user renders the normal - * normal page including footer and header and blank - * just renders the plain template - */ - public function renderAs($renderAs){ - $this->renderAs = $renderAs; - } - - - /** - * Returns the set renderAs - * @return string the renderAs value - */ - public function getRenderAs(){ - return $this->renderAs; - } - - - /** - * Returns the rendered html - * @return string the rendered html - */ - public function render(){ - - if($this->appName !== null){ - $appName = $this->appName; - } else { - $appName = $this->api->getAppName(); - } - - $template = $this->api->getTemplate($this->templateName, $this->renderAs, $appName); - - foreach($this->params as $key => $value){ - $template->assign($key, $value); - } - - return $template->fetchPage(); - } - -} diff --git a/lib/appframework/middleware/middleware.php b/lib/appframework/middleware/middleware.php index 4df88490468..b12c03c3eb8 100644 --- a/lib/appframework/middleware/middleware.php +++ b/lib/appframework/middleware/middleware.php @@ -24,7 +24,7 @@ namespace OC\AppFramework\Middleware; -use OC\AppFramework\Http\Response; +use OCP\AppFramework\Http\Response; /** diff --git a/lib/appframework/middleware/middlewaredispatcher.php b/lib/appframework/middleware/middlewaredispatcher.php index c2d16134dc5..70ab108e6b8 100644 --- a/lib/appframework/middleware/middlewaredispatcher.php +++ b/lib/appframework/middleware/middlewaredispatcher.php @@ -25,7 +25,7 @@ namespace OC\AppFramework\Middleware; use OC\AppFramework\Controller\Controller; -use OC\AppFramework\Http\Response; +use OCP\AppFramework\Http\Response; /** diff --git a/lib/appframework/middleware/security/securitymiddleware.php b/lib/appframework/middleware/security/securitymiddleware.php index 52818b1b53e..4f1447e1afb 100644 --- a/lib/appframework/middleware/security/securitymiddleware.php +++ b/lib/appframework/middleware/security/securitymiddleware.php @@ -27,12 +27,12 @@ namespace OC\AppFramework\Middleware\Security; use OC\AppFramework\Controller\Controller; use OC\AppFramework\Http\Http; use OC\AppFramework\Http\Request; -use OC\AppFramework\Http\Response; -use OC\AppFramework\Http\JSONResponse; use OC\AppFramework\Http\RedirectResponse; use OC\AppFramework\Utility\MethodAnnotationReader; use OC\AppFramework\Middleware\Middleware; use OC\AppFramework\Core\API; +use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http\JSONResponse; /** diff --git a/lib/public/appframework/http/http.php b/lib/public/appframework/http/http.php new file mode 100644 index 00000000000..9eafe782726 --- /dev/null +++ b/lib/public/appframework/http/http.php @@ -0,0 +1,89 @@ +. + * + */ + + +namespace OCP\AppFramework\Http; + + +class Http { + + const STATUS_CONTINUE = 100; + const STATUS_SWITCHING_PROTOCOLS = 101; + const STATUS_PROCESSING = 102; + const STATUS_OK = 200; + const STATUS_CREATED = 201; + const STATUS_ACCEPTED = 202; + const STATUS_NON_AUTHORATIVE_INFORMATION = 203; + const STATUS_NO_CONTENT = 204; + const STATUS_RESET_CONTENT = 205; + const STATUS_PARTIAL_CONTENT = 206; + const STATUS_MULTI_STATUS = 207; + const STATUS_ALREADY_REPORTED = 208; + const STATUS_IM_USED = 226; + const STATUS_MULTIPLE_CHOICES = 300; + const STATUS_MOVED_PERMANENTLY = 301; + const STATUS_FOUND = 302; + const STATUS_SEE_OTHER = 303; + const STATUS_NOT_MODIFIED = 304; + const STATUS_USE_PROXY = 305; + const STATUS_RESERVED = 306; + const STATUS_TEMPORARY_REDIRECT = 307; + const STATUS_BAD_REQUEST = 400; + const STATUS_UNAUTHORIZED = 401; + const STATUS_PAYMENT_REQUIRED = 402; + const STATUS_FORBIDDEN = 403; + const STATUS_NOT_FOUND = 404; + const STATUS_METHOD_NOT_ALLOWED = 405; + const STATUS_NOT_ACCEPTABLE = 406; + const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; + const STATUS_REQUEST_TIMEOUT = 408; + const STATUS_CONFLICT = 409; + const STATUS_GONE = 410; + const STATUS_LENGTH_REQUIRED = 411; + const STATUS_PRECONDITION_FAILED = 412; + const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; + const STATUS_REQUEST_URI_TOO_LONG = 414; + const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; + const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416; + const STATUS_EXPECTATION_FAILED = 417; + const STATUS_IM_A_TEAPOT = 418; + const STATUS_UNPROCESSABLE_ENTITY = 422; + const STATUS_LOCKED = 423; + const STATUS_FAILED_DEPENDENCY = 424; + const STATUS_UPGRADE_REQUIRED = 426; + const STATUS_PRECONDITION_REQUIRED = 428; + const STATUS_TOO_MANY_REQUESTS = 429; + const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; + const STATUS_INTERNAL_SERVER_ERROR = 500; + const STATUS_NOT_IMPLEMENTED = 501; + const STATUS_BAD_GATEWAY = 502; + const STATUS_SERVICE_UNAVAILABLE = 503; + const STATUS_GATEWAY_TIMEOUT = 504; + const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505; + const STATUS_VARIANT_ALSO_NEGOTIATES = 506; + const STATUS_INSUFFICIENT_STORAGE = 507; + const STATUS_LOOP_DETECTED = 508; + const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509; + const STATUS_NOT_EXTENDED = 510; + const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; +} diff --git a/lib/public/appframework/http/jsonresponse.php b/lib/public/appframework/http/jsonresponse.php new file mode 100644 index 00000000000..085fdbed2f9 --- /dev/null +++ b/lib/public/appframework/http/jsonresponse.php @@ -0,0 +1,74 @@ +. + * + */ + + +namespace OCP\AppFramework\Http; + + +/** + * A renderer for JSON calls + */ +class JSONResponse extends Response { + + protected $data; + + + /** + * @param array|object $data the object or array that should be transformed + * @param int $statusCode the Http status code, defaults to 200 + */ + public function __construct($data=array(), $statusCode=Http::STATUS_OK) { + $this->data = $data; + $this->setStatus($statusCode); + $this->addHeader('X-Content-Type-Options', 'nosniff'); + $this->addHeader('Content-type', 'application/json; charset=utf-8'); + } + + + /** + * Returns the rendered json + * @return string the rendered json + */ + public function render(){ + return json_encode($this->data); + } + + /** + * Sets values in the data json array + * @param array|object $params an array or object which will be transformed + * to JSON + */ + public function setData($data){ + $this->data = $data; + } + + + /** + * Used to get the set parameters + * @return array the data + */ + public function getData(){ + return $this->data; + } + +} diff --git a/lib/public/appframework/http/response.php b/lib/public/appframework/http/response.php new file mode 100644 index 00000000000..64477258948 --- /dev/null +++ b/lib/public/appframework/http/response.php @@ -0,0 +1,169 @@ +. + * + */ + + +namespace OCP\AppFramework\Http; + + +/** + * Base class for responses. Also used to just send headers + */ +class Response { + + /** + * @var array default headers + */ + private $headers = array( + 'Cache-Control' => 'no-cache, must-revalidate' + ); + + + /** + * @var string + */ + private $status = Http::STATUS_OK; + + + /** + * @var \DateTime + */ + private $lastModified; + + + /** + * @var string + */ + private $ETag; + + + /** + * Caches the response + * @param int $cacheSeconds the amount of seconds that should be cached + * if 0 then caching will be disabled + */ + public function cacheFor($cacheSeconds) { + + if($cacheSeconds > 0) { + $this->addHeader('Cache-Control', 'max-age=' . $cacheSeconds . + ', must-revalidate'); + } else { + $this->addHeader('Cache-Control', 'no-cache, must-revalidate'); + } + + } + + + /** + * Adds a new header to the response that will be called before the render + * function + * @param string $name The name of the HTTP header + * @param string $value The value, null will delete it + */ + public function addHeader($name, $value) { + if(is_null($value)) { + unset($this->headers[$name]); + } else { + $this->headers[$name] = $value; + } + } + + + /** + * Returns the set headers + * @return array the headers + */ + public function getHeaders() { + $mergeWith = array(); + + if($this->lastModified) { + $mergeWith['Last-Modified'] = + $this->lastModified->format(\DateTime::RFC2822); + } + + if($this->ETag) { + $mergeWith['ETag'] = '"' . $this->ETag . '"'; + } + + return array_merge($mergeWith, $this->headers); + } + + + /** + * By default renders no output + * @return null + */ + public function render() { + return null; + } + + + /** + * Set response status + * @param int $status a HTTP status code, see also the STATUS constants + */ + public function setStatus($status) { + $this->status = $status; + } + + + /** + * Get response status + */ + public function getStatus() { + return $this->status; + } + + + /** + * @return string the etag + */ + public function getETag() { + return $this->ETag; + } + + + /** + * @return string RFC2822 formatted last modified date + */ + public function getLastModified() { + return $this->lastModified; + } + + + /** + * @param string $ETag + */ + public function setETag($ETag) { + $this->ETag = $ETag; + } + + + /** + * @param \DateTime $lastModified + */ + public function setLastModified($lastModified) { + $this->lastModified = $lastModified; + } + + +} diff --git a/lib/public/appframework/http/templateresponse.php b/lib/public/appframework/http/templateresponse.php new file mode 100644 index 00000000000..97678c96cba --- /dev/null +++ b/lib/public/appframework/http/templateresponse.php @@ -0,0 +1,126 @@ +. + * + */ + + +namespace OCP\AppFramework\Http; + +use OC\AppFramework\Core\API; + + +/** + * Response for a normal template + */ +class TemplateResponse extends Response { + + protected $templateName; + protected $params; + protected $api; + protected $renderAs; + protected $appName; + + /** + * @param API $api an API instance + * @param string $templateName the name of the template + * @param string $appName optional if you want to include a template from + * a different app + */ + public function __construct(API $api, $templateName, $appName=null) { + $this->templateName = $templateName; + $this->appName = $appName; + $this->api = $api; + $this->params = array(); + $this->renderAs = 'user'; + } + + + /** + * Sets template parameters + * @param array $params an array with key => value structure which sets template + * variables + */ + public function setParams(array $params){ + $this->params = $params; + } + + + /** + * Used for accessing the set parameters + * @return array the params + */ + public function getParams(){ + return $this->params; + } + + + /** + * Used for accessing the name of the set template + * @return string the name of the used template + */ + public function getTemplateName(){ + return $this->templateName; + } + + + /** + * Sets the template page + * @param string $renderAs admin, user or blank. Admin also prints the admin + * settings header and footer, user renders the normal + * normal page including footer and header and blank + * just renders the plain template + */ + public function renderAs($renderAs){ + $this->renderAs = $renderAs; + } + + + /** + * Returns the set renderAs + * @return string the renderAs value + */ + public function getRenderAs(){ + return $this->renderAs; + } + + + /** + * Returns the rendered html + * @return string the rendered html + */ + public function render(){ + + if($this->appName !== null){ + $appName = $this->appName; + } else { + $appName = $this->api->getAppName(); + } + + $template = $this->api->getTemplate($this->templateName, $this->renderAs, $appName); + + foreach($this->params as $key => $value){ + $template->assign($key, $value); + } + + return $template->fetchPage(); + } + +} -- cgit v1.2.3 From 38f9df429397619482e3e3f7ffb0db5274222e4c Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 21 Aug 2013 01:02:15 +0200 Subject: introducing OCP\AppFramework\App --- lib/appframework/app.php | 3 +- lib/appframework/core/api.php | 3 +- .../dependencyinjection/dicontainer.php | 21 +- lib/public/appframework/App.php | 61 ++++++ lib/public/appframework/iapi.php | 238 +++++++++++++++++++++ lib/public/appframework/iappcontainer.php | 25 +++ 6 files changed, 348 insertions(+), 3 deletions(-) create mode 100644 lib/public/appframework/App.php create mode 100644 lib/public/appframework/iapi.php create mode 100644 lib/public/appframework/iappcontainer.php diff --git a/lib/appframework/app.php b/lib/appframework/app.php index 6224b858bbf..7ff55bb809d 100644 --- a/lib/appframework/app.php +++ b/lib/appframework/app.php @@ -25,6 +25,7 @@ namespace OC\AppFramework; use OC\AppFramework\DependencyInjection\DIContainer; +use OCP\AppFramework\IAppContainer; /** @@ -45,7 +46,7 @@ class App { * @param DIContainer $container an instance of a pimple container. */ public static function main($controllerName, $methodName, array $urlParams, - DIContainer $container) { + IAppContainer $container) { $container['urlParams'] = $urlParams; $controller = $container[$controllerName]; diff --git a/lib/appframework/core/api.php b/lib/appframework/core/api.php index eb8ee01e5db..337e3b57d6d 100644 --- a/lib/appframework/core/api.php +++ b/lib/appframework/core/api.php @@ -23,6 +23,7 @@ namespace OC\AppFramework\Core; +use OCP\AppFramework\IApi; /** @@ -32,7 +33,7 @@ namespace OC\AppFramework\Core; * Should you find yourself in need for more methods, simply inherit from this * class and add your methods */ -class API { +class API implements IApi{ private $appName; diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 88ad2cd414a..43f6eee29b0 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -32,9 +32,11 @@ use OC\AppFramework\Middleware\MiddlewareDispatcher; use OC\AppFramework\Middleware\Security\SecurityMiddleware; use OC\AppFramework\Utility\SimpleContainer; use OC\AppFramework\Utility\TimeFactory; +use OCP\AppFramework\IApi; +use OCP\AppFramework\IAppContainer; -class DIContainer extends SimpleContainer { +class DIContainer extends SimpleContainer implements IAppContainer{ /** @@ -45,6 +47,8 @@ class DIContainer extends SimpleContainer { $this['AppName'] = $appName; + $this->registerParameter('ServerContainer', \OC::$server); + $this['API'] = $this->share(function($c){ return new API($c['AppName']); }); @@ -119,4 +123,19 @@ class DIContainer extends SimpleContainer { } + /** + * @return IApi + */ + function getCoreApi() + { + return $this->query('API'); + } + + /** + * @return \OCP\Core\IServerContainer + */ + function getServer() + { + return $this->query('ServerContainer'); + } } diff --git a/lib/public/appframework/App.php b/lib/public/appframework/App.php new file mode 100644 index 00000000000..0c27fcb2ac5 --- /dev/null +++ b/lib/public/appframework/App.php @@ -0,0 +1,61 @@ +container = new \OC\AppFramework\DependencyInjection\DIContainer($appName); + } + + private $container; + + /** + * @return IAppContainer + */ + public function getContainer() { + return $this->container; + } + + /** + * This function is called by the routing component to fire up the frameworks dispatch mechanism. + * + * Example code in routes.php of the task app: + * $this->create('tasks_index', '/')->get()->action( + * function($params){ + * $app = new TaskApp(); + * $app->dispatch('PageController', 'index', $params); + * } + * ); + * + * + * Example for for TaskApp implementation: + * class TaskApp extends \OCP\AppFramework\App { + * + * public function __construct(){ + * parent::__construct('tasks'); + * + * $this->getContainer()->registerService('PageController', function(IAppContainer $c){ + * $a = $c->query('API'); + * $r = $c->query('Request'); + * return new PageController($a, $r); + * }); + * } + * } + * + * @param string $controllerName the name of the controller under which it is + * stored in the DI container + * @param string $methodName the method that you want to call + * @param array $urlParams an array with variables extracted from the routes + */ + public function dispatch($controllerName, $methodName, array $urlParams) { + \OC\AppFramework\App::main($controllerName, $methodName, $urlParams, $this->container); + } +} diff --git a/lib/public/appframework/iapi.php b/lib/public/appframework/iapi.php new file mode 100644 index 00000000000..5374f0dcaf5 --- /dev/null +++ b/lib/public/appframework/iapi.php @@ -0,0 +1,238 @@ +. + * + */ + + +namespace OCP\AppFramework; + + +/** + * A few very basic and frequently used API functions are combined in here + */ +interface IApi { + + /** + * used to return the appname of the set application + * @return string the name of your application + */ + function getAppName(); + + + /** + * Creates a new navigation entry + * @param array $entry containing: id, name, order, icon and href key + */ + function addNavigationEntry(array $entry); + + + /** + * Gets the userid of the current user + * @return string the user id of the current user + */ + function getUserId(); + + + /** + * Sets the current navigation entry to the currently running app + */ + function activateNavigationEntry(); + + + /** + * Adds a new javascript file + * @param string $scriptName the name of the javascript in js/ without the suffix + * @param string $appName the name of the app, defaults to the current one + */ + function addScript($scriptName, $appName = null); + + + /** + * Adds a new css file + * @param string $styleName the name of the css file in css/without the suffix + * @param string $appName the name of the app, defaults to the current one + */ + function addStyle($styleName, $appName = null); + + + /** + * shorthand for addScript for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + */ + function add3rdPartyScript($name); + + + /** + * shorthand for addStyle for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + */ + function add3rdPartyStyle($name); + + /** + * Looks up a system-wide defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + function getSystemValue($key); + + /** + * Sets a new system-wide value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + */ + function setSystemValue($key, $value); + + + /** + * Looks up an app-specific defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + function getAppValue($key, $appName = null); + + + /** + * Writes a new app-specific value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + */ + function setAppValue($key, $value, $appName = null); + + + /** + * Shortcut for setting a user defined value + * @param string $key the key under which the value is being stored + * @param string $value the value that you want to store + * @param string $userId the userId of the user that we want to store the value under, defaults to the current one + */ + function setUserValue($key, $value, $userId = null); + + + /** + * Shortcut for getting a user defined value + * @param string $key the key under which the value is being stored + * @param string $userId the userId of the user that we want to store the value under, defaults to the current one + */ + function getUserValue($key, $userId = null); + + /** + * Returns the translation object + * @return \OC_L10N the translation object + * + * FIXME: returns private object / should be retrieved from teh ServerContainer + */ + function getTrans(); + + + /** + * Used to abstract the owncloud database access away + * @param string $sql the sql query with ? placeholder for params + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @return \OCP\DB a query object + * + * FIXME: returns non public interface / object + */ + function prepareQuery($sql, $limit=null, $offset=null); + + + /** + * Used to get the id of the just inserted element + * @param string $tableName the name of the table where we inserted the item + * @return int the id of the inserted element + * + * FIXME: move to db object + */ + function getInsertId($tableName); + + + /** + * Returns the URL for a route + * @param string $routeName the name of the route + * @param array $arguments an array with arguments which will be filled into the url + * @return string the url + */ + function linkToRoute($routeName, $arguments=array()); + + + /** + * Returns an URL for an image or file + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + */ + function linkTo($file, $appName=null); + + + /** + * Returns the link to an image, like link to but only with prepending img/ + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + */ + function imagePath($file, $appName = null); + + + /** + * Makes an URL absolute + * @param string $url the url + * @return string the absolute url + * + * FIXME: function should live in Request / Response + */ + function getAbsoluteURL($url); + + + /** + * links to a file + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + * @deprecated replaced with linkToRoute() + * @return string the url + */ + function linkToAbsolute($file, $appName = null); + + + /** + * Checks if an app is enabled + * @param string $appName the name of an app + * @return bool true if app is enabled + */ + public function isAppEnabled($appName); + + + /** + * Writes a function into the error log + * @param string $msg the error message to be logged + * @param int $level the error level + * + * FIXME: add logger instance to ServerContainer + */ + function log($msg, $level = null); + + + /** + * Returns a template + * @param string $templateName the name of the template + * @param string $renderAs how it should be rendered + * @param string $appName the name of the app + * @return \OCP\Template a new template + */ + function getTemplate($templateName, $renderAs='user', $appName=null); +} diff --git a/lib/public/appframework/iappcontainer.php b/lib/public/appframework/iappcontainer.php new file mode 100644 index 00000000000..c2faea07b95 --- /dev/null +++ b/lib/public/appframework/iappcontainer.php @@ -0,0 +1,25 @@ + Date: Mon, 26 Aug 2013 23:48:18 +0200 Subject: as a quick example the public contacts API has been ported over as a service hosted within the server container --- lib/contactsmanager.php | 145 ++++++++++++++++++++++++++++++++ lib/public/contacts.php | 55 ++++--------- lib/public/core/contacts/imanager.php | 150 ++++++++++++++++++++++++++++++++++ lib/public/core/iservercontainer.php | 4 + lib/server.php | 15 +++- 5 files changed, 329 insertions(+), 40 deletions(-) create mode 100644 lib/contactsmanager.php create mode 100644 lib/public/core/contacts/imanager.php diff --git a/lib/contactsmanager.php b/lib/contactsmanager.php new file mode 100644 index 00000000000..59c413ec03b --- /dev/null +++ b/lib/contactsmanager.php @@ -0,0 +1,145 @@ +. + * + */ + +namespace OC { + + class ContactsManager implements \OCP\Core\Contacts\IManager { + + /** + * This function is used to search and find contacts within the users address books. + * In case $pattern is empty all contacts will be returned. + * + * @param string $pattern which should match within the $searchProperties + * @param array $searchProperties defines the properties within the query pattern should match + * @param array $options - for future use. One should always have options! + * @return array of contacts which are arrays of key-value-pairs + */ + public function search($pattern, $searchProperties = array(), $options = array()) { + $result = array(); + foreach($this->address_books as $address_book) { + $r = $address_book->search($pattern, $searchProperties, $options); + $result = array_merge($result, $r); + } + + return $result; + } + + /** + * This function can be used to delete the contact identified by the given id + * + * @param object $id the unique identifier to a contact + * @param $address_book_key + * @return bool successful or not + */ + public function delete($id, $address_book_key) { + if (!array_key_exists($address_book_key, $this->address_books)) + return null; + + $address_book = $this->address_books[$address_book_key]; + if ($address_book->getPermissions() & \OCP\PERMISSION_DELETE) + return null; + + return $address_book->delete($id); + } + + /** + * This function is used to create a new contact if 'id' is not given or not present. + * Otherwise the contact will be updated by replacing the entire data set. + * + * @param array $properties this array if key-value-pairs defines a contact + * @param $address_book_key string to identify the address book in which the contact shall be created or updated + * @return array representing the contact just created or updated + */ + public function createOrUpdate($properties, $address_book_key) { + + if (!array_key_exists($address_book_key, $this->address_books)) + return null; + + $address_book = $this->address_books[$address_book_key]; + if ($address_book->getPermissions() & \OCP\PERMISSION_CREATE) + return null; + + return $address_book->createOrUpdate($properties); + } + + /** + * Check if contacts are available (e.g. contacts app enabled) + * + * @return bool true if enabled, false if not + */ + public function isEnabled() { + return !empty($this->address_books); + } + + /** + * @param \OCP\IAddressBook $address_book + */ + public function registerAddressBook(\OCP\IAddressBook $address_book) { + $this->address_books[$address_book->getKey()] = $address_book; + } + + /** + * @param \OCP\IAddressBook $address_book + */ + public function unregisterAddressBook(\OCP\IAddressBook $address_book) { + unset($this->address_books[$address_book->getKey()]); + } + + /** + * @return array + */ + public function getAddressBooks() { + $result = array(); + foreach($this->address_books as $address_book) { + $result[$address_book->getKey()] = $address_book->getDisplayName(); + } + + return $result; + } + + /** + * removes all registered address book instances + */ + public function clear() { + $this->address_books = array(); + } + + /** + * @var \OCP\IAddressBook[] which holds all registered address books + */ + private $address_books = array(); + + /** + * In order to improve lazy loading a closure can be registered which will be called in case + * address books are actually requested + * + * @param string $key + * @param \Closure $callable + */ + function register($key, \Closure $callable) + { + // + //TODO: implement me + // + } + } +} diff --git a/lib/public/contacts.php b/lib/public/contacts.php index 88d812e735a..1b61d7aa4ff 100644 --- a/lib/public/contacts.php +++ b/lib/public/contacts.php @@ -90,13 +90,8 @@ namespace OCP { * @return array of contacts which are arrays of key-value-pairs */ public static function search($pattern, $searchProperties = array(), $options = array()) { - $result = array(); - foreach(self::$address_books as $address_book) { - $r = $address_book->search($pattern, $searchProperties, $options); - $result = array_merge($result, $r); - } - - return $result; + $cm = \OC::$server->getContactsManager(); + return $cm->search($pattern, $searchProperties, $options); } /** @@ -107,14 +102,8 @@ namespace OCP { * @return bool successful or not */ public static function delete($id, $address_book_key) { - if (!array_key_exists($address_book_key, self::$address_books)) - return null; - - $address_book = self::$address_books[$address_book_key]; - if ($address_book->getPermissions() & \OCP\PERMISSION_DELETE) - return null; - - return $address_book->delete($id); + $cm = \OC::$server->getContactsManager(); + return $cm->delete($id, $address_book_key); } /** @@ -126,15 +115,8 @@ namespace OCP { * @return array representing the contact just created or updated */ public static function createOrUpdate($properties, $address_book_key) { - - if (!array_key_exists($address_book_key, self::$address_books)) - return null; - - $address_book = self::$address_books[$address_book_key]; - if ($address_book->getPermissions() & \OCP\PERMISSION_CREATE) - return null; - - return $address_book->createOrUpdate($properties); + $cm = \OC::$server->getContactsManager(); + return $cm->search($properties, $address_book_key); } /** @@ -143,45 +125,40 @@ namespace OCP { * @return bool true if enabled, false if not */ public static function isEnabled() { - return !empty(self::$address_books); + $cm = \OC::$server->getContactsManager(); + return $cm->isEnabled(); } /** * @param \OCP\IAddressBook $address_book */ public static function registerAddressBook(\OCP\IAddressBook $address_book) { - self::$address_books[$address_book->getKey()] = $address_book; + $cm = \OC::$server->getContactsManager(); + return $cm->registerAddressBook($address_book); } /** * @param \OCP\IAddressBook $address_book */ public static function unregisterAddressBook(\OCP\IAddressBook $address_book) { - unset(self::$address_books[$address_book->getKey()]); + $cm = \OC::$server->getContactsManager(); + return $cm->unregisterAddressBook($address_book); } /** * @return array */ public static function getAddressBooks() { - $result = array(); - foreach(self::$address_books as $address_book) { - $result[$address_book->getKey()] = $address_book->getDisplayName(); - } - - return $result; + $cm = \OC::$server->getContactsManager(); + return $cm->getAddressBooks(); } /** * removes all registered address book instances */ public static function clear() { - self::$address_books = array(); + $cm = \OC::$server->getContactsManager(); + $cm->clear(); } - - /** - * @var \OCP\IAddressBook[] which holds all registered address books - */ - private static $address_books = array(); } } diff --git a/lib/public/core/contacts/imanager.php b/lib/public/core/contacts/imanager.php new file mode 100644 index 00000000000..4ae9d5766e0 --- /dev/null +++ b/lib/public/core/contacts/imanager.php @@ -0,0 +1,150 @@ +. + * + */ + +/** + * Public interface of ownCloud for apps to use. + * Contacts Class + * + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Core\Contacts { + + /** + * This class provides access to the contacts app. Use this class exclusively if you want to access contacts. + * + * Contacts in general will be expressed as an array of key-value-pairs. + * The keys will match the property names defined in https://tools.ietf.org/html/rfc2426#section-1 + * + * Proposed workflow for working with contacts: + * - search for the contacts + * - manipulate the results array + * - createOrUpdate will save the given contacts overwriting the existing data + * + * For updating it is mandatory to keep the id. + * Without an id a new contact will be created. + * + */ + interface IManager { + + /** + * This function is used to search and find contacts within the users address books. + * In case $pattern is empty all contacts will be returned. + * + * Example: + * Following function shows how to search for contacts for the name and the email address. + * + * public static function getMatchingRecipient($term) { + * $cm = \OC:$server->getContactsManager(); + * // The API is not active -> nothing to do + * if (!$cm->isEnabled()) { + * return array(); + * } + * + * $result = $cm->search($term, array('FN', 'EMAIL')); + * $receivers = array(); + * foreach ($result as $r) { + * $id = $r['id']; + * $fn = $r['FN']; + * $email = $r['EMAIL']; + * if (!is_array($email)) { + * $email = array($email); + * } + * + * // loop through all email addresses of this contact + * foreach ($email as $e) { + * $displayName = $fn . " <$e>"; + * $receivers[] = array( + * 'id' => $id, + * 'label' => $displayName, + * 'value' => $displayName); + * } + * } + * + * return $receivers; + * } + * + * + * @param string $pattern which should match within the $searchProperties + * @param array $searchProperties defines the properties within the query pattern should match + * @param array $options - for future use. One should always have options! + * @return array of contacts which are arrays of key-value-pairs + */ + function search($pattern, $searchProperties = array(), $options = array()); + + /** + * This function can be used to delete the contact identified by the given id + * + * @param object $id the unique identifier to a contact + * @param $address_book_key + * @return bool successful or not + */ + function delete($id, $address_book_key); + + /** + * This function is used to create a new contact if 'id' is not given or not present. + * Otherwise the contact will be updated by replacing the entire data set. + * + * @param array $properties this array if key-value-pairs defines a contact + * @param $address_book_key string to identify the address book in which the contact shall be created or updated + * @return array representing the contact just created or updated + */ + function createOrUpdate($properties, $address_book_key); + + /** + * Check if contacts are available (e.g. contacts app enabled) + * + * @return bool true if enabled, false if not + */ + function isEnabled(); + + /** + * @param \OCP\IAddressBook $address_book + */ + function registerAddressBook(\OCP\IAddressBook $address_book); + + /** + * @param \OCP\IAddressBook $address_book + */ + function unregisterAddressBook(\OCP\IAddressBook $address_book); + + /** + * In order to improve lazy loading a closure can be registered which will be called in case + * address books are actually requested + * + * @param string $key + * @param \Closure $callable + */ + function register($key, \Closure $callable); + + /** + * @return array + */ + function getAddressBooks(); + + /** + * removes all registered address book instances + */ + function clear(); + } +} diff --git a/lib/public/core/iservercontainer.php b/lib/public/core/iservercontainer.php index df744ab6fdf..464da19864d 100644 --- a/lib/public/core/iservercontainer.php +++ b/lib/public/core/iservercontainer.php @@ -11,4 +11,8 @@ namespace OCP\Core; */ interface IServerContainer { + /** + * @return \OCP\Core\Contacts\IManager + */ + function getContactsManager(); } diff --git a/lib/server.php b/lib/server.php index f8f25c046d6..72c82efe16b 100644 --- a/lib/server.php +++ b/lib/server.php @@ -2,6 +2,7 @@ namespace OC; +use OC\AppFramework\Utility\SimpleContainer; use OCP\Core\IServerContainer; /** @@ -10,6 +11,18 @@ use OCP\Core\IServerContainer; * * TODO: hookup all manager classes */ -class Server implements IServerContainer { +class Server extends SimpleContainer implements IServerContainer { + function __construct() { + $this->registerService('ContactsManager', function($c){ + return new ContactsManager(); + }); + } + + /** + * @return \OCP\Core\Contacts\IManager + */ + function getContactsManager() { + return $this->query('ContactsManager'); + } } -- cgit v1.2.3 From 14b67d6c5f1e3cd538714a8b5f512dd34847e795 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Thu, 29 Aug 2013 16:25:25 +0200 Subject: fixing typo --- lib/public/core/contacts/imanager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/core/contacts/imanager.php b/lib/public/core/contacts/imanager.php index 4ae9d5766e0..e8bb7bfd8e4 100644 --- a/lib/public/core/contacts/imanager.php +++ b/lib/public/core/contacts/imanager.php @@ -55,7 +55,7 @@ namespace OCP\Core\Contacts { * Following function shows how to search for contacts for the name and the email address. * * public static function getMatchingRecipient($term) { - * $cm = \OC:$server->getContactsManager(); + * $cm = \OC::$server->getContactsManager(); * // The API is not active -> nothing to do * if (!$cm->isEnabled()) { * return array(); -- cgit v1.2.3 From ec9b7d1e845527957aaaf6b235227b4e5c3f033d Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 31 Aug 2013 01:41:24 +0200 Subject: fixing file header --- lib/public/appframework/App.php | 20 ++++++++++++++++++++ lib/public/appframework/iappcontainer.php | 20 ++++++++++++++++++++ lib/public/core/icontainer.php | 20 ++++++++++++++++++++ lib/public/core/irequest.php | 23 ++++++++++++++++++----- lib/public/core/iservercontainer.php | 20 ++++++++++++++++++++ 5 files changed, 98 insertions(+), 5 deletions(-) diff --git a/lib/public/appframework/App.php b/lib/public/appframework/App.php index 0c27fcb2ac5..d97c5c81848 100644 --- a/lib/public/appframework/App.php +++ b/lib/public/appframework/App.php @@ -1,4 +1,24 @@ . + * + */ namespace OCP\AppFramework; diff --git a/lib/public/appframework/iappcontainer.php b/lib/public/appframework/iappcontainer.php index c2faea07b95..db909241e5d 100644 --- a/lib/public/appframework/iappcontainer.php +++ b/lib/public/appframework/iappcontainer.php @@ -1,4 +1,24 @@ . + * + */ namespace OCP\AppFramework; diff --git a/lib/public/core/icontainer.php b/lib/public/core/icontainer.php index a6c93abec67..8c4a63424bf 100644 --- a/lib/public/core/icontainer.php +++ b/lib/public/core/icontainer.php @@ -1,4 +1,24 @@ . + * + */ namespace OCP\Core; diff --git a/lib/public/core/irequest.php b/lib/public/core/irequest.php index fc2004d1835..6103215842b 100644 --- a/lib/public/core/irequest.php +++ b/lib/public/core/irequest.php @@ -1,10 +1,23 @@ . + * */ namespace OCP\Core; diff --git a/lib/public/core/iservercontainer.php b/lib/public/core/iservercontainer.php index 464da19864d..e169990a3f8 100644 --- a/lib/public/core/iservercontainer.php +++ b/lib/public/core/iservercontainer.php @@ -1,4 +1,24 @@ . + * + */ namespace OCP\Core; -- cgit v1.2.3 From 97bdf008b1cefaa092e23fc5a9bad787e755ed77 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 31 Aug 2013 20:57:16 +0200 Subject: PHPDoc added to existing interfaces --- lib/public/core/icontainer.php | 25 +++++++++++++++++++++++++ lib/public/core/irequest.php | 8 ++++++-- lib/public/core/iservercontainer.php | 13 +++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/lib/public/core/icontainer.php b/lib/public/core/icontainer.php index 8c4a63424bf..88ebc6cf64d 100644 --- a/lib/public/core/icontainer.php +++ b/lib/public/core/icontainer.php @@ -31,9 +31,34 @@ namespace OCP\Core; */ interface IContainer { + /** + * Look up a service for a given name in the container. + * + * @param string $name + * @return mixed + */ function query($name); + /** + * A value is stored in the container with it's corresponding name + * + * @param string $name + * @param mixed $value + * @return void + */ function registerParameter($name, $value); + /** + * A service is registered in the container where a closure is passed in which will actually + * create the service on demand. + * In case the parameter $shared is set to true (the default usage) the once created service will remain in + * memory and be reused on subsequent calls. + * In case the parameter is false the service will be recreated on every call. + * + * @param string $name + * @param callable $closure + * @param bool $shared + * @return void + */ function registerService($name, \Closure $closure, $shared = true); } diff --git a/lib/public/core/irequest.php b/lib/public/core/irequest.php index 6103215842b..be60978a3c3 100644 --- a/lib/public/core/irequest.php +++ b/lib/public/core/irequest.php @@ -45,6 +45,7 @@ interface IRequest { /** * Returns all params that were received, be it from the request + * * (as GET or POST) or through the URL by the route * @return array the array with all parameters */ @@ -52,12 +53,14 @@ interface IRequest { /** * Returns the method of the request + * * @return string the method of the request (POST, GET, etc) */ public function getMethod(); /** * Shortcut for accessing an uploaded file through the $_FILES array + * * @param string $key the key that will be taken from the $_FILES array * @return array the file in the $_FILES element */ @@ -66,6 +69,7 @@ interface IRequest { /** * Shortcut for getting env variables + * * @param string $key the key that will be taken from the $_ENV array * @return array the value in the $_ENV element */ @@ -74,6 +78,7 @@ interface IRequest { /** * Shortcut for getting session variables + * * @param string $key the key that will be taken from the $_SESSION array * @return array the value in the $_SESSION element */ @@ -82,6 +87,7 @@ interface IRequest { /** * Shortcut for getting cookie variables + * * @param string $key the key that will be taken from the $_COOKIE array * @return array the value in the $_COOKIE element */ @@ -92,9 +98,7 @@ interface IRequest { * Returns the request body content. * * @param Boolean $asResource If true, a resource will be returned - * * @return string|resource The request body content or a resource to read the body stream. - * * @throws \LogicException */ function getContent($asResource = false); diff --git a/lib/public/core/iservercontainer.php b/lib/public/core/iservercontainer.php index e169990a3f8..0517cc53e09 100644 --- a/lib/public/core/iservercontainer.php +++ b/lib/public/core/iservercontainer.php @@ -32,7 +32,20 @@ namespace OCP\Core; interface IServerContainer { /** + * The contacts manager will act as a broker between consumers for contacts information and + * providers which actual deliver the contact information. + * * @return \OCP\Core\Contacts\IManager */ function getContactsManager(); + + /** + * The current request object holding all information about the request currently being processed + * is returned from this method. + * In case the current execution was not initiated by a web request null is returned + * + * @return \OCP\Core\IRequest|null + */ + function getRequest(); + } -- cgit v1.2.3 From 206f83941b26b16f89e695ae84b998e9cf11132a Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 31 Aug 2013 21:34:29 +0200 Subject: move new interfaces into lib/public and OCP --- .../dependencyinjection/dicontainer.php | 2 +- lib/appframework/http/request.php | 2 +- lib/appframework/utility/simplecontainer.php | 2 +- lib/contactsmanager.php | 2 +- lib/public/appframework/iappcontainer.php | 4 +- lib/public/contacts/imanager.php | 150 +++++++++++++++++++++ lib/public/core/contacts/imanager.php | 150 --------------------- lib/public/core/icontainer.php | 64 --------- lib/public/core/irequest.php | 105 --------------- lib/public/core/iservercontainer.php | 51 ------- lib/public/icontainer.php | 64 +++++++++ lib/public/irequest.php | 105 +++++++++++++++ lib/public/iservercontainer.php | 51 +++++++ lib/server.php | 16 ++- 14 files changed, 390 insertions(+), 378 deletions(-) create mode 100644 lib/public/contacts/imanager.php delete mode 100644 lib/public/core/contacts/imanager.php delete mode 100644 lib/public/core/icontainer.php delete mode 100644 lib/public/core/irequest.php delete mode 100644 lib/public/core/iservercontainer.php create mode 100644 lib/public/icontainer.php create mode 100644 lib/public/irequest.php create mode 100644 lib/public/iservercontainer.php diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 43f6eee29b0..2ef885d7b2c 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -132,7 +132,7 @@ class DIContainer extends SimpleContainer implements IAppContainer{ } /** - * @return \OCP\Core\IServerContainer + * @return \OCP\IServerContainer */ function getServer() { diff --git a/lib/appframework/http/request.php b/lib/appframework/http/request.php index ab72a8db697..4f1775182a1 100644 --- a/lib/appframework/http/request.php +++ b/lib/appframework/http/request.php @@ -22,7 +22,7 @@ namespace OC\AppFramework\Http; -use OCP\Core\IRequest; +use OCP\IRequest; /** * Class for accessing variables in the request. diff --git a/lib/appframework/utility/simplecontainer.php b/lib/appframework/utility/simplecontainer.php index 04b6cd727b8..a51ace83a37 100644 --- a/lib/appframework/utility/simplecontainer.php +++ b/lib/appframework/utility/simplecontainer.php @@ -10,7 +10,7 @@ require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; * * SimpleContainer is a simple implementation of IContainer on basis of \Pimple */ -class SimpleContainer extends \Pimple implements \OCP\Core\IContainer { +class SimpleContainer extends \Pimple implements \OCP\IContainer { /** * @param string $name name of the service to query for diff --git a/lib/contactsmanager.php b/lib/contactsmanager.php index 59c413ec03b..fc6745b4505 100644 --- a/lib/contactsmanager.php +++ b/lib/contactsmanager.php @@ -22,7 +22,7 @@ namespace OC { - class ContactsManager implements \OCP\Core\Contacts\IManager { + class ContactsManager implements \OCP\Contacts\IManager { /** * This function is used to search and find contacts within the users address books. diff --git a/lib/public/appframework/iappcontainer.php b/lib/public/appframework/iappcontainer.php index db909241e5d..c8f6229dd9e 100644 --- a/lib/public/appframework/iappcontainer.php +++ b/lib/public/appframework/iappcontainer.php @@ -23,7 +23,7 @@ namespace OCP\AppFramework; use OCP\AppFramework\IApi; -use OCP\Core\IContainer; +use OCP\IContainer; /** * Class IAppContainer @@ -39,7 +39,7 @@ interface IAppContainer extends IContainer{ function getCoreApi(); /** - * @return \OCP\Core\IServerContainer + * @return \OCP\IServerContainer */ function getServer(); } diff --git a/lib/public/contacts/imanager.php b/lib/public/contacts/imanager.php new file mode 100644 index 00000000000..3bfbca7be50 --- /dev/null +++ b/lib/public/contacts/imanager.php @@ -0,0 +1,150 @@ +. + * + */ + +/** + * Public interface of ownCloud for apps to use. + * Contacts Class + * + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Contacts { + + /** + * This class provides access to the contacts app. Use this class exclusively if you want to access contacts. + * + * Contacts in general will be expressed as an array of key-value-pairs. + * The keys will match the property names defined in https://tools.ietf.org/html/rfc2426#section-1 + * + * Proposed workflow for working with contacts: + * - search for the contacts + * - manipulate the results array + * - createOrUpdate will save the given contacts overwriting the existing data + * + * For updating it is mandatory to keep the id. + * Without an id a new contact will be created. + * + */ + interface IManager { + + /** + * This function is used to search and find contacts within the users address books. + * In case $pattern is empty all contacts will be returned. + * + * Example: + * Following function shows how to search for contacts for the name and the email address. + * + * public static function getMatchingRecipient($term) { + * $cm = \OC::$server->getContactsManager(); + * // The API is not active -> nothing to do + * if (!$cm->isEnabled()) { + * return array(); + * } + * + * $result = $cm->search($term, array('FN', 'EMAIL')); + * $receivers = array(); + * foreach ($result as $r) { + * $id = $r['id']; + * $fn = $r['FN']; + * $email = $r['EMAIL']; + * if (!is_array($email)) { + * $email = array($email); + * } + * + * // loop through all email addresses of this contact + * foreach ($email as $e) { + * $displayName = $fn . " <$e>"; + * $receivers[] = array( + * 'id' => $id, + * 'label' => $displayName, + * 'value' => $displayName); + * } + * } + * + * return $receivers; + * } + * + * + * @param string $pattern which should match within the $searchProperties + * @param array $searchProperties defines the properties within the query pattern should match + * @param array $options - for future use. One should always have options! + * @return array of contacts which are arrays of key-value-pairs + */ + function search($pattern, $searchProperties = array(), $options = array()); + + /** + * This function can be used to delete the contact identified by the given id + * + * @param object $id the unique identifier to a contact + * @param $address_book_key + * @return bool successful or not + */ + function delete($id, $address_book_key); + + /** + * This function is used to create a new contact if 'id' is not given or not present. + * Otherwise the contact will be updated by replacing the entire data set. + * + * @param array $properties this array if key-value-pairs defines a contact + * @param $address_book_key string to identify the address book in which the contact shall be created or updated + * @return array representing the contact just created or updated + */ + function createOrUpdate($properties, $address_book_key); + + /** + * Check if contacts are available (e.g. contacts app enabled) + * + * @return bool true if enabled, false if not + */ + function isEnabled(); + + /** + * @param \OCP\IAddressBook $address_book + */ + function registerAddressBook(\OCP\IAddressBook $address_book); + + /** + * @param \OCP\IAddressBook $address_book + */ + function unregisterAddressBook(\OCP\IAddressBook $address_book); + + /** + * In order to improve lazy loading a closure can be registered which will be called in case + * address books are actually requested + * + * @param string $key + * @param \Closure $callable + */ + function register($key, \Closure $callable); + + /** + * @return array + */ + function getAddressBooks(); + + /** + * removes all registered address book instances + */ + function clear(); + } +} diff --git a/lib/public/core/contacts/imanager.php b/lib/public/core/contacts/imanager.php deleted file mode 100644 index e8bb7bfd8e4..00000000000 --- a/lib/public/core/contacts/imanager.php +++ /dev/null @@ -1,150 +0,0 @@ -. - * - */ - -/** - * Public interface of ownCloud for apps to use. - * Contacts Class - * - */ - -// use OCP namespace for all classes that are considered public. -// This means that they should be used by apps instead of the internal ownCloud classes -namespace OCP\Core\Contacts { - - /** - * This class provides access to the contacts app. Use this class exclusively if you want to access contacts. - * - * Contacts in general will be expressed as an array of key-value-pairs. - * The keys will match the property names defined in https://tools.ietf.org/html/rfc2426#section-1 - * - * Proposed workflow for working with contacts: - * - search for the contacts - * - manipulate the results array - * - createOrUpdate will save the given contacts overwriting the existing data - * - * For updating it is mandatory to keep the id. - * Without an id a new contact will be created. - * - */ - interface IManager { - - /** - * This function is used to search and find contacts within the users address books. - * In case $pattern is empty all contacts will be returned. - * - * Example: - * Following function shows how to search for contacts for the name and the email address. - * - * public static function getMatchingRecipient($term) { - * $cm = \OC::$server->getContactsManager(); - * // The API is not active -> nothing to do - * if (!$cm->isEnabled()) { - * return array(); - * } - * - * $result = $cm->search($term, array('FN', 'EMAIL')); - * $receivers = array(); - * foreach ($result as $r) { - * $id = $r['id']; - * $fn = $r['FN']; - * $email = $r['EMAIL']; - * if (!is_array($email)) { - * $email = array($email); - * } - * - * // loop through all email addresses of this contact - * foreach ($email as $e) { - * $displayName = $fn . " <$e>"; - * $receivers[] = array( - * 'id' => $id, - * 'label' => $displayName, - * 'value' => $displayName); - * } - * } - * - * return $receivers; - * } - * - * - * @param string $pattern which should match within the $searchProperties - * @param array $searchProperties defines the properties within the query pattern should match - * @param array $options - for future use. One should always have options! - * @return array of contacts which are arrays of key-value-pairs - */ - function search($pattern, $searchProperties = array(), $options = array()); - - /** - * This function can be used to delete the contact identified by the given id - * - * @param object $id the unique identifier to a contact - * @param $address_book_key - * @return bool successful or not - */ - function delete($id, $address_book_key); - - /** - * This function is used to create a new contact if 'id' is not given or not present. - * Otherwise the contact will be updated by replacing the entire data set. - * - * @param array $properties this array if key-value-pairs defines a contact - * @param $address_book_key string to identify the address book in which the contact shall be created or updated - * @return array representing the contact just created or updated - */ - function createOrUpdate($properties, $address_book_key); - - /** - * Check if contacts are available (e.g. contacts app enabled) - * - * @return bool true if enabled, false if not - */ - function isEnabled(); - - /** - * @param \OCP\IAddressBook $address_book - */ - function registerAddressBook(\OCP\IAddressBook $address_book); - - /** - * @param \OCP\IAddressBook $address_book - */ - function unregisterAddressBook(\OCP\IAddressBook $address_book); - - /** - * In order to improve lazy loading a closure can be registered which will be called in case - * address books are actually requested - * - * @param string $key - * @param \Closure $callable - */ - function register($key, \Closure $callable); - - /** - * @return array - */ - function getAddressBooks(); - - /** - * removes all registered address book instances - */ - function clear(); - } -} diff --git a/lib/public/core/icontainer.php b/lib/public/core/icontainer.php deleted file mode 100644 index 88ebc6cf64d..00000000000 --- a/lib/public/core/icontainer.php +++ /dev/null @@ -1,64 +0,0 @@ -. - * - */ - -namespace OCP\Core; - -/** - * Class IContainer - * - * IContainer is the basic interface to be used for any internal dependency injection mechanism - * - * @package OCP\Core - */ -interface IContainer { - - /** - * Look up a service for a given name in the container. - * - * @param string $name - * @return mixed - */ - function query($name); - - /** - * A value is stored in the container with it's corresponding name - * - * @param string $name - * @param mixed $value - * @return void - */ - function registerParameter($name, $value); - - /** - * A service is registered in the container where a closure is passed in which will actually - * create the service on demand. - * In case the parameter $shared is set to true (the default usage) the once created service will remain in - * memory and be reused on subsequent calls. - * In case the parameter is false the service will be recreated on every call. - * - * @param string $name - * @param callable $closure - * @param bool $shared - * @return void - */ - function registerService($name, \Closure $closure, $shared = true); -} diff --git a/lib/public/core/irequest.php b/lib/public/core/irequest.php deleted file mode 100644 index be60978a3c3..00000000000 --- a/lib/public/core/irequest.php +++ /dev/null @@ -1,105 +0,0 @@ -. - * - */ - -namespace OCP\Core; - - -interface IRequest { - - function getHeader($name); - - /** - * Lets you access post and get parameters by the index - * In case of json requests the encoded json body is accessed - * - * @param string $key the key which you want to access in the URL Parameter - * placeholder, $_POST or $_GET array. - * The priority how they're returned is the following: - * 1. URL parameters - * 2. POST parameters - * 3. GET parameters - * @param mixed $default If the key is not found, this value will be returned - * @return mixed the content of the array - */ - public function getParam($key, $default = null); - - - /** - * Returns all params that were received, be it from the request - * - * (as GET or POST) or through the URL by the route - * @return array the array with all parameters - */ - public function getParams(); - - /** - * Returns the method of the request - * - * @return string the method of the request (POST, GET, etc) - */ - public function getMethod(); - - /** - * Shortcut for accessing an uploaded file through the $_FILES array - * - * @param string $key the key that will be taken from the $_FILES array - * @return array the file in the $_FILES element - */ - public function getUploadedFile($key); - - - /** - * Shortcut for getting env variables - * - * @param string $key the key that will be taken from the $_ENV array - * @return array the value in the $_ENV element - */ - public function getEnv($key); - - - /** - * Shortcut for getting session variables - * - * @param string $key the key that will be taken from the $_SESSION array - * @return array the value in the $_SESSION element - */ - function getSession($key); - - - /** - * Shortcut for getting cookie variables - * - * @param string $key the key that will be taken from the $_COOKIE array - * @return array the value in the $_COOKIE element - */ - function getCookie($key); - - - /** - * Returns the request body content. - * - * @param Boolean $asResource If true, a resource will be returned - * @return string|resource The request body content or a resource to read the body stream. - * @throws \LogicException - */ - function getContent($asResource = false); -} diff --git a/lib/public/core/iservercontainer.php b/lib/public/core/iservercontainer.php deleted file mode 100644 index 0517cc53e09..00000000000 --- a/lib/public/core/iservercontainer.php +++ /dev/null @@ -1,51 +0,0 @@ -. - * - */ - -namespace OCP\Core; - - -/** - * Class IServerContainer - * @package OCP\Core - * - * This container holds all ownCloud services - */ -interface IServerContainer { - - /** - * The contacts manager will act as a broker between consumers for contacts information and - * providers which actual deliver the contact information. - * - * @return \OCP\Core\Contacts\IManager - */ - function getContactsManager(); - - /** - * The current request object holding all information about the request currently being processed - * is returned from this method. - * In case the current execution was not initiated by a web request null is returned - * - * @return \OCP\Core\IRequest|null - */ - function getRequest(); - -} diff --git a/lib/public/icontainer.php b/lib/public/icontainer.php new file mode 100644 index 00000000000..d43c1c90f11 --- /dev/null +++ b/lib/public/icontainer.php @@ -0,0 +1,64 @@ +. + * + */ + +namespace OCP; + +/** + * Class IContainer + * + * IContainer is the basic interface to be used for any internal dependency injection mechanism + * + * @package OCP + */ +interface IContainer { + + /** + * Look up a service for a given name in the container. + * + * @param string $name + * @return mixed + */ + function query($name); + + /** + * A value is stored in the container with it's corresponding name + * + * @param string $name + * @param mixed $value + * @return void + */ + function registerParameter($name, $value); + + /** + * A service is registered in the container where a closure is passed in which will actually + * create the service on demand. + * In case the parameter $shared is set to true (the default usage) the once created service will remain in + * memory and be reused on subsequent calls. + * In case the parameter is false the service will be recreated on every call. + * + * @param string $name + * @param callable $closure + * @param bool $shared + * @return void + */ + function registerService($name, \Closure $closure, $shared = true); +} diff --git a/lib/public/irequest.php b/lib/public/irequest.php new file mode 100644 index 00000000000..cd39855950b --- /dev/null +++ b/lib/public/irequest.php @@ -0,0 +1,105 @@ +. + * + */ + +namespace OCP; + + +interface IRequest { + + function getHeader($name); + + /** + * Lets you access post and get parameters by the index + * In case of json requests the encoded json body is accessed + * + * @param string $key the key which you want to access in the URL Parameter + * placeholder, $_POST or $_GET array. + * The priority how they're returned is the following: + * 1. URL parameters + * 2. POST parameters + * 3. GET parameters + * @param mixed $default If the key is not found, this value will be returned + * @return mixed the content of the array + */ + public function getParam($key, $default = null); + + + /** + * Returns all params that were received, be it from the request + * + * (as GET or POST) or through the URL by the route + * @return array the array with all parameters + */ + public function getParams(); + + /** + * Returns the method of the request + * + * @return string the method of the request (POST, GET, etc) + */ + public function getMethod(); + + /** + * Shortcut for accessing an uploaded file through the $_FILES array + * + * @param string $key the key that will be taken from the $_FILES array + * @return array the file in the $_FILES element + */ + public function getUploadedFile($key); + + + /** + * Shortcut for getting env variables + * + * @param string $key the key that will be taken from the $_ENV array + * @return array the value in the $_ENV element + */ + public function getEnv($key); + + + /** + * Shortcut for getting session variables + * + * @param string $key the key that will be taken from the $_SESSION array + * @return array the value in the $_SESSION element + */ + function getSession($key); + + + /** + * Shortcut for getting cookie variables + * + * @param string $key the key that will be taken from the $_COOKIE array + * @return array the value in the $_COOKIE element + */ + function getCookie($key); + + + /** + * Returns the request body content. + * + * @param Boolean $asResource If true, a resource will be returned + * @return string|resource The request body content or a resource to read the body stream. + * @throws \LogicException + */ + function getContent($asResource = false); +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php new file mode 100644 index 00000000000..5f5b9677549 --- /dev/null +++ b/lib/public/iservercontainer.php @@ -0,0 +1,51 @@ +. + * + */ + +namespace OCP; + + +/** + * Class IServerContainer + * @package OCP + * + * This container holds all ownCloud services + */ +interface IServerContainer { + + /** + * The contacts manager will act as a broker between consumers for contacts information and + * providers which actual deliver the contact information. + * + * @return \OCP\Contacts\IManager + */ + function getContactsManager(); + + /** + * The current request object holding all information about the request currently being processed + * is returned from this method. + * In case the current execution was not initiated by a web request null is returned + * + * @return \OCP\IRequest|null + */ + function getRequest(); + +} diff --git a/lib/server.php b/lib/server.php index 72c82efe16b..ad955bf5c65 100644 --- a/lib/server.php +++ b/lib/server.php @@ -3,7 +3,7 @@ namespace OC; use OC\AppFramework\Utility\SimpleContainer; -use OCP\Core\IServerContainer; +use OCP\IServerContainer; /** * Class Server @@ -20,9 +20,21 @@ class Server extends SimpleContainer implements IServerContainer { } /** - * @return \OCP\Core\Contacts\IManager + * @return \OCP\Contacts\IManager */ function getContactsManager() { return $this->query('ContactsManager'); } + + /** + * The current request object holding all information about the request currently being processed + * is returned from this method. + * In case the current execution was not initiated by a web request null is returned + * + * @return \OCP\IRequest|null + */ + function getRequest() + { + return $this->query('Request'); + } } -- cgit v1.2.3 From 823b4cce603d1d0a404d8b93fcca6101ff839767 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 4 Sep 2013 08:16:27 +0200 Subject: More trimming --- lib/vcategories.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 84036958359..a7e4c54be29 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -179,6 +179,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { + $category = trim($category); $catid = $this->array_searchi($category, $this->categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); @@ -240,6 +241,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { + $category = trim($category); $catid = $this->array_searchi($category, $this->categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); @@ -301,6 +303,7 @@ class OC_VCategories { * @returns int the id of the added category or false if it already exists. */ public function add($name) { + $name = trim($name); OCP\Util::writeLog('core', __METHOD__.', name: ' . $name, OCP\Util::DEBUG); if($this->hasCategory($name)) { OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', OCP\Util::DEBUG); @@ -331,6 +334,8 @@ class OC_VCategories { * @returns bool */ public function rename($from, $to) { + $from = trim($from); + $to = trim($to); $id = $this->array_searchi($from, $this->categories); if($id === false) { OCP\Util::writeLog('core', __METHOD__.', category: ' . $from. ' does not exist', OCP\Util::DEBUG); @@ -656,6 +661,7 @@ class OC_VCategories { public function addToCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; if(is_string($category) && !is_numeric($category)) { + $category = trim($category); if(!$this->hasCategory($category)) { $this->add($category, true); } @@ -688,9 +694,13 @@ class OC_VCategories { */ public function removeFromCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; - $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, $this->categories) - : $category; + if(is_string($category) && !is_numeric($category)) { + $category = trim($category); + $categoryid = $this->array_searchi($category, $this->categories); + } else { + $categoryid = $category; + } + try { $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; @@ -716,6 +726,8 @@ class OC_VCategories { $names = array($names); } + $names = array_map('trim', $names); + OC_Log::write('core', __METHOD__ . ', before: ' . print_r($this->categories, true), OC_Log::DEBUG); foreach($names as $name) { -- cgit v1.2.3 From 7618cf3005f8bda8375183010711a9a2cdfb1fea Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 4 Sep 2013 23:45:11 +0200 Subject: adding public interface for preview --- lib/preview.php | 5 ++++- lib/previewmanager.php | 38 ++++++++++++++++++++++++++++++++++++++ lib/public/ipreview.php | 35 +++++++++++++++++++++++++++++++++++ lib/public/iservercontainer.php | 6 ++++++ lib/public/preview.php | 34 ---------------------------------- lib/server.php | 40 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 35 deletions(-) create mode 100755 lib/previewmanager.php create mode 100644 lib/public/ipreview.php delete mode 100644 lib/public/preview.php diff --git a/lib/preview.php b/lib/preview.php index b40ba191fba..266f7795f12 100755 --- a/lib/preview.php +++ b/lib/preview.php @@ -42,6 +42,9 @@ class Preview { private $scalingup; //preview images object + /** + * @var \OC_Image + */ private $preview; //preview providers @@ -624,4 +627,4 @@ class Preview { } return false; } -} \ No newline at end of file +} diff --git a/lib/previewmanager.php b/lib/previewmanager.php new file mode 100755 index 00000000000..ac9a866a75b --- /dev/null +++ b/lib/previewmanager.php @@ -0,0 +1,38 @@ +getPreview(); + } + + /** + * @brief returns true if the passed mime type is supported + * @param string $mimeType + * @return boolean + */ + function isMimeSupported($mimeType = '*') + { + return \OC\Preview::isMimeSupported($mimeType); + } +} diff --git a/lib/public/ipreview.php b/lib/public/ipreview.php new file mode 100644 index 00000000000..b01e7f5b539 --- /dev/null +++ b/lib/public/ipreview.php @@ -0,0 +1,35 @@ +registerService('ContactsManager', function($c){ return new ContactsManager(); }); + $this->registerService('Request', function($c){ + $params = array(); + + // we json decode the body only in case of content type json + if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') === true ) { + $params = json_decode(file_get_contents('php://input'), true); + $params = is_array($params) ? $params: array(); + } + + return new Request( + array( + 'get' => $_GET, + 'post' => $_POST, + 'files' => $_FILES, + 'server' => $_SERVER, + 'env' => $_ENV, + 'session' => $_SESSION, + 'cookies' => $_COOKIE, + 'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) + ? $_SERVER['REQUEST_METHOD'] + : null, + 'params' => $params, + 'urlParams' => $c['urlParams'] + ) + ); + }); + $this->registerService('PreviewManager', function($c){ + return new PreviewManager(); + }); } /** @@ -37,4 +67,14 @@ class Server extends SimpleContainer implements IServerContainer { { return $this->query('Request'); } + + /** + * Returns the preview manager which can create preview images for a given file + * + * @return \OCP\IPreview + */ + function getPreviewManager() + { + return $this->query('PreviewManager'); + } } -- cgit v1.2.3 From 5acb3c4c0d570b2bf7b209d61e5e7849f4f3a363 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sun, 15 Sep 2013 21:20:22 +0200 Subject: first log the exception --- index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.php b/index.php index 90fd3efcc96..40063fa6e05 100755 --- a/index.php +++ b/index.php @@ -31,7 +31,7 @@ try { } catch (Exception $ex) { //show the user a detailed error page - OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR); \OCP\Util::writeLog('index', $ex->getMessage(), \OCP\Util::FATAL); + OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR); OC_Template::printExceptionErrorPage($ex); } -- cgit v1.2.3 From af0069bf032d2045abd18abf2e133835fc360481 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sun, 15 Sep 2013 22:24:57 +0200 Subject: adding getRootFolder() to server container and hooking up the new files api --- lib/public/iservercontainer.php | 8 ++++++++ lib/server.php | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 144c1a5b3b9..d88330698dc 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -54,4 +54,12 @@ interface IServerContainer { * @return \OCP\IPreview */ function getPreviewManager(); + + /** + * Returns the root folder of ownCloud's data directory + * + * @return \OCP\Files\Folder + */ + function getRootFolder(); + } diff --git a/lib/server.php b/lib/server.php index d85996612e9..9e87bd3190d 100644 --- a/lib/server.php +++ b/lib/server.php @@ -4,6 +4,8 @@ namespace OC; use OC\AppFramework\Http\Request; use OC\AppFramework\Utility\SimpleContainer; +use OC\Files\Node\Root; +use OC\Files\View; use OCP\IServerContainer; /** @@ -47,6 +49,14 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('PreviewManager', function($c){ return new PreviewManager(); }); + $this->registerService('RootFolder', function($c){ + // TODO: get user and user manager from container as well + $user = \OC_User::getUser(); + $user = \OC_User::getManager()->get($user); + $manager = \OC\Files\Filesystem::getMountManager(); + $view = new View(); + return new Root($manager, $view, $user); + }); } /** @@ -77,4 +87,14 @@ class Server extends SimpleContainer implements IServerContainer { { return $this->query('PreviewManager'); } + + /** + * Returns the root folder of ownCloud's data directory + * + * @return \OCP\Files\Folder + */ + function getRootFolder() + { + return $this->query('RootFolder'); + } } -- cgit v1.2.3 From 5d4e9e0d25831cbe1b9c2fef52016c6ed1bbcb55 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sun, 15 Sep 2013 23:07:18 +0200 Subject: /OC/Server has created too early causing issues with config operations as OC:$SERVERPATH was not yet initialized This fixes unit test execution --- lib/base.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/base.php b/lib/base.php index 05d151439a4..1720a5fd7e1 100644 --- a/lib/base.php +++ b/lib/base.php @@ -376,9 +376,6 @@ class OC { self::$loader->registerPrefix('Patchwork', '3rdparty'); spl_autoload_register(array(self::$loader, 'load')); - // setup the basic server - self::$server = new \OC\Server(); - // set some stuff //ob_start(); error_reporting(E_ALL | E_STRICT); @@ -458,6 +455,9 @@ class OC { stream_wrapper_register('quota', 'OC\Files\Stream\Quota'); stream_wrapper_register('oc', 'OC\Files\Stream\OC'); + // setup the basic server + self::$server = new \OC\Server(); + self::initTemplateEngine(); if (!self::$CLI) { self::initSession(); -- cgit v1.2.3 From 3c026b7cf601c0b83dd02436f17714fcf48cb9a8 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 16 Sep 2013 12:09:15 +0200 Subject: recreate an etag within the scanner if the cache contains an empty etag --- lib/files/cache/scanner.php | 8 +++++++- tests/lib/files/cache/scanner.php | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index 9d180820e9d..78cab6ed2da 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -97,13 +97,19 @@ class Scanner extends BasicEmitter { } $newData = $data; if ($reuseExisting and $cacheData = $this->cache->get($file)) { + // prevent empty etag + $etag = $cacheData['etag']; + if (empty($etag)) { + $etag = $data['etag']; + } + // only reuse data if the file hasn't explicitly changed if (isset($data['mtime']) && isset($cacheData['mtime']) && $data['mtime'] === $cacheData['mtime']) { if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { $data['size'] = $cacheData['size']; } if ($reuseExisting & self::REUSE_ETAG) { - $data['etag'] = $cacheData['etag']; + $data['etag'] = $etag; } } // Only update metadata that has changed diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php index f6deb93a49e..fa1b3406040 100644 --- a/tests/lib/files/cache/scanner.php +++ b/tests/lib/files/cache/scanner.php @@ -184,6 +184,23 @@ class Scanner extends \PHPUnit_Framework_TestCase { $this->assertFalse($this->cache->inCache('folder/bar.txt')); } + public function testETagRecreation() { + $this->fillTestFolders(); + + $this->scanner->scan(''); + + // manipulate etag to simulate an empty etag + $this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG); + $data['etag'] = ''; + $this->cache->put('', $data); + + // rescan + $this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG); + $newData = $this->cache->get(''); + $this->assertNotEmpty($newData['etag']); + + } + function setUp() { $this->storage = new \OC\Files\Storage\Temporary(array()); $this->scanner = new \OC\Files\Cache\Scanner($this->storage); -- cgit v1.2.3 From 07714d9a72bbc4d9bdc25a8c42d83b5a70fb5be3 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 14 Sep 2013 17:56:55 +0200 Subject: Tests whether expired/valid link share is still accessible. --- tests/lib/share/share.php | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index e02b0e4354d..8e9eef65d32 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -535,4 +535,52 @@ class Test_Share extends PHPUnit_Framework_TestCase { 'Failed asserting that user 3 still has access to test.txt after expiration date has been set.' ); } + + protected function getShareByValidToken($token) { + $row = OCP\Share::getShareByToken($token); + $this->assertInternalType( + 'array', + $row, + "Failed asserting that a share for token $token exists." + ); + return $row; + } + + public function testShareItemWithLink() { + OC_User::setUserId($this->user1); + $token = OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_LINK, null, OCP\PERMISSION_READ); + $this->assertInternalType( + 'string', + $token, + 'Failed asserting that user 1 successfully shared text.txt as link with token.' + ); + + // testGetShareByTokenNoExpiration + $row = $this->getShareByValidToken($token); + $this->assertEmpty( + $row['expiration'], + 'Failed asserting that the returned row does not have an expiration date.' + ); + + // testGetShareByTokenExpirationValid + $this->assertTrue( + OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInFuture), + 'Failed asserting that user 1 successfully set a future expiration date for the test.txt share.' + ); + $row = $this->getShareByValidToken($token); + $this->assertNotEmpty( + $row['expiration'], + 'Failed asserting that the returned row has an expiration date.' + ); + + // testGetShareByTokenExpirationExpired + $this->assertTrue( + OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInPast), + 'Failed asserting that user 1 successfully set a past expiration date for the test.txt share.' + ); + $this->assertFalse( + OCP\Share::getShareByToken($token), + 'Failed asserting that an expired share could not be found.' + ); + } } -- cgit v1.2.3 From a92d4c2c0932f5c662ed846763e3059ebdcde07c Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 14 Sep 2013 18:44:28 +0200 Subject: Perform expiration date checking before returning share data for token. --- lib/public/share.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/public/share.php b/lib/public/share.php index 9ab956d84b9..cc3c4de6208 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -293,7 +293,18 @@ class Share { if (\OC_DB::isError($result)) { \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', token=' . $token, \OC_Log::ERROR); } - return $result->fetchRow(); + $row = $result->fetchRow(); + + if (!empty($row['expiration'])) { + $now = new \DateTime(); + $expirationDate = new \DateTime($row['expiration'], new \DateTimeZone('UTC')); + if ($now > $expirationDate) { + self::delete($row['id']); + return false; + } + } + + return $row; } /** -- cgit v1.2.3 From c8f9efeb94b136ed0906cefe946629a091796ff2 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 16 Sep 2013 23:32:17 +0200 Subject: etag changes are now propagated up the file tree --- lib/files/cache/scanner.php | 14 ++++++++++++++ tests/lib/files/cache/scanner.php | 21 +++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index 78cab6ed2da..fdbce0d51fe 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -99,8 +99,10 @@ class Scanner extends BasicEmitter { if ($reuseExisting and $cacheData = $this->cache->get($file)) { // prevent empty etag $etag = $cacheData['etag']; + $propagateETagChange = false; if (empty($etag)) { $etag = $data['etag']; + $propagateETagChange = true; } // only reuse data if the file hasn't explicitly changed @@ -110,6 +112,18 @@ class Scanner extends BasicEmitter { } if ($reuseExisting & self::REUSE_ETAG) { $data['etag'] = $etag; + if ($propagateETagChange) { + $parent = $file; + while ($parent !== '') { + $parent = dirname($parent); + if ($parent === '.') { + $parent = ''; + } + $parentCacheData = $this->cache->get($parent); + $parentCacheData['etag'] = $this->storage->getETag($parent); + $this->cache->put($parent, $parentCacheData); + } + } } } // Only update metadata that has changed diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php index fa1b3406040..b137799bbcf 100644 --- a/tests/lib/files/cache/scanner.php +++ b/tests/lib/files/cache/scanner.php @@ -187,17 +187,26 @@ class Scanner extends \PHPUnit_Framework_TestCase { public function testETagRecreation() { $this->fillTestFolders(); - $this->scanner->scan(''); + $this->scanner->scan('folder/bar.txt'); // manipulate etag to simulate an empty etag $this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG); - $data['etag'] = ''; - $this->cache->put('', $data); + $data0 = $this->cache->get('folder/bar.txt'); + $data1 = $this->cache->get('folder'); + $data2 = $this->cache->get(''); + $data0['etag'] = ''; + $this->cache->put('folder/bar.txt', $data0); // rescan - $this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG); - $newData = $this->cache->get(''); - $this->assertNotEmpty($newData['etag']); + $this->scanner->scan('folder/bar.txt', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG); + + // verify cache content + $newData0 = $this->cache->get('folder/bar.txt'); + $newData1 = $this->cache->get('folder'); + $newData2 = $this->cache->get(''); + $this->assertNotEmpty($newData0['etag']); + $this->assertNotEquals($data1['etag'], $newData1['etag']); + $this->assertNotEquals($data2['etag'], $newData2['etag']); } -- cgit v1.2.3 From 981a41e2cdb0848bea6c433577a7ae60d2920a00 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 17 Sep 2013 00:26:55 +0200 Subject: adding interface for middleware --- lib/public/appframework/imiddleware.php | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 lib/public/appframework/imiddleware.php diff --git a/lib/public/appframework/imiddleware.php b/lib/public/appframework/imiddleware.php new file mode 100644 index 00000000000..9340034fcc9 --- /dev/null +++ b/lib/public/appframework/imiddleware.php @@ -0,0 +1,88 @@ +. + * + */ + + +namespace OCP\AppFramework; +use OCP\AppFramework\Http\Response; + + +/** + * Middleware is used to provide hooks before or after controller methods and + * deal with possible exceptions raised in the controller methods. + * They're modeled after Django's middleware system: + * https://docs.djangoproject.com/en/dev/topics/http/middleware/ + */ +interface MiddleWare { + + + /** + * This is being run in normal order before the controller is being + * called which allows several modifications and checks + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + */ + function beforeController($controller, $methodName); + + + /** + * This is being run when either the beforeController method or the + * controller method itself is throwing an exception. The middleware is + * asked in reverse order to handle the exception and to return a response. + * If the response is null, it is assumed that the exception could not be + * handled and the error will be thrown again + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param \Exception $exception the thrown exception + * @throws \Exception the passed in exception if it cant handle it + * @return Response a Response object in case that the exception was handled + */ + function afterException($controller, $methodName, \Exception $exception); + + /** + * This is being run after a successful controller method call and allows + * the manipulation of a Response object. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param Response $response the generated response from the controller + * @return Response a Response object + */ + function afterController($controller, $methodName, Response $response); + + /** + * This is being run after the response object has been rendered and + * allows the manipulation of the output. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param string $output the generated output from a response + * @return string the output that should be printed + */ + function beforeOutput($controller, $methodName, $output); +} -- cgit v1.2.3 From 822daa8f8adb9c31b9bfeac67ff165c18dc321c2 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 17 Sep 2013 00:27:22 +0200 Subject: class files have to be lowercase --- lib/public/appframework/App.php | 81 ----------------------------------------- lib/public/appframework/app.php | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 81 deletions(-) delete mode 100644 lib/public/appframework/App.php create mode 100644 lib/public/appframework/app.php diff --git a/lib/public/appframework/App.php b/lib/public/appframework/App.php deleted file mode 100644 index d97c5c81848..00000000000 --- a/lib/public/appframework/App.php +++ /dev/null @@ -1,81 +0,0 @@ -. - * - */ - -namespace OCP\AppFramework; - - -/** - * Class App - * @package OCP\AppFramework - * - * Any application must inherit this call - all controller instances to be used are - * to be registered using IContainer::registerService - */ -class App { - public function __construct($appName) { - $this->container = new \OC\AppFramework\DependencyInjection\DIContainer($appName); - } - - private $container; - - /** - * @return IAppContainer - */ - public function getContainer() { - return $this->container; - } - - /** - * This function is called by the routing component to fire up the frameworks dispatch mechanism. - * - * Example code in routes.php of the task app: - * $this->create('tasks_index', '/')->get()->action( - * function($params){ - * $app = new TaskApp(); - * $app->dispatch('PageController', 'index', $params); - * } - * ); - * - * - * Example for for TaskApp implementation: - * class TaskApp extends \OCP\AppFramework\App { - * - * public function __construct(){ - * parent::__construct('tasks'); - * - * $this->getContainer()->registerService('PageController', function(IAppContainer $c){ - * $a = $c->query('API'); - * $r = $c->query('Request'); - * return new PageController($a, $r); - * }); - * } - * } - * - * @param string $controllerName the name of the controller under which it is - * stored in the DI container - * @param string $methodName the method that you want to call - * @param array $urlParams an array with variables extracted from the routes - */ - public function dispatch($controllerName, $methodName, array $urlParams) { - \OC\AppFramework\App::main($controllerName, $methodName, $urlParams, $this->container); - } -} diff --git a/lib/public/appframework/app.php b/lib/public/appframework/app.php new file mode 100644 index 00000000000..d97c5c81848 --- /dev/null +++ b/lib/public/appframework/app.php @@ -0,0 +1,81 @@ +. + * + */ + +namespace OCP\AppFramework; + + +/** + * Class App + * @package OCP\AppFramework + * + * Any application must inherit this call - all controller instances to be used are + * to be registered using IContainer::registerService + */ +class App { + public function __construct($appName) { + $this->container = new \OC\AppFramework\DependencyInjection\DIContainer($appName); + } + + private $container; + + /** + * @return IAppContainer + */ + public function getContainer() { + return $this->container; + } + + /** + * This function is called by the routing component to fire up the frameworks dispatch mechanism. + * + * Example code in routes.php of the task app: + * $this->create('tasks_index', '/')->get()->action( + * function($params){ + * $app = new TaskApp(); + * $app->dispatch('PageController', 'index', $params); + * } + * ); + * + * + * Example for for TaskApp implementation: + * class TaskApp extends \OCP\AppFramework\App { + * + * public function __construct(){ + * parent::__construct('tasks'); + * + * $this->getContainer()->registerService('PageController', function(IAppContainer $c){ + * $a = $c->query('API'); + * $r = $c->query('Request'); + * return new PageController($a, $r); + * }); + * } + * } + * + * @param string $controllerName the name of the controller under which it is + * stored in the DI container + * @param string $methodName the method that you want to call + * @param array $urlParams an array with variables extracted from the routes + */ + public function dispatch($controllerName, $methodName, array $urlParams) { + \OC\AppFramework\App::main($controllerName, $methodName, $urlParams, $this->container); + } +} -- cgit v1.2.3 From b9e943f5d52d1bf888233fdc2288477322591c43 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 17 Sep 2013 09:42:14 +0200 Subject: fix naming --- lib/public/appframework/imiddleware.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/appframework/imiddleware.php b/lib/public/appframework/imiddleware.php index 9340034fcc9..1e76d3bbe49 100644 --- a/lib/public/appframework/imiddleware.php +++ b/lib/public/appframework/imiddleware.php @@ -32,7 +32,7 @@ use OCP\AppFramework\Http\Response; * They're modeled after Django's middleware system: * https://docs.djangoproject.com/en/dev/topics/http/middleware/ */ -interface MiddleWare { +interface IMiddleWare { /** -- cgit v1.2.3 From 9b420e8660404de27e3af629bfca188ae90cf7bd Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 17 Sep 2013 13:33:47 +0200 Subject: use \OC::$server->getPreviewManager() instead of \OCP\Preview --- apps/files/ajax/rawlist.php | 6 +++--- apps/files/lib/helper.php | 2 +- apps/files_sharing/public.php | 2 +- apps/files_trashbin/lib/helper.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/files/ajax/rawlist.php b/apps/files/ajax/rawlist.php index 9ccd4cc299a..802a3083533 100644 --- a/apps/files/ajax/rawlist.php +++ b/apps/files/ajax/rawlist.php @@ -26,7 +26,7 @@ $files = array(); if($mimetypes && !in_array('httpd/unix-directory', $mimetypes)) { foreach( \OC\Files\Filesystem::getDirectoryContent( $dir, 'httpd/unix-directory' ) as $file ) { $file['directory'] = $dir; - $file['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($file['mimetype']); + $file['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file['mimetype']); $file["date"] = OCP\Util::formatDate($file["mtime"]); $file['mimetype_icon'] = \OCA\files\lib\Helper::determineIcon($file); $files[] = $file; @@ -37,7 +37,7 @@ if (is_array($mimetypes) && count($mimetypes)) { foreach ($mimetypes as $mimetype) { foreach( \OC\Files\Filesystem::getDirectoryContent( $dir, $mimetype ) as $file ) { $file['directory'] = $dir; - $file['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($file['mimetype']); + $file['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file['mimetype']); $file["date"] = OCP\Util::formatDate($file["mtime"]); $file['mimetype_icon'] = \OCA\files\lib\Helper::determineIcon($file); $files[] = $file; @@ -46,7 +46,7 @@ if (is_array($mimetypes) && count($mimetypes)) { } else { foreach( \OC\Files\Filesystem::getDirectoryContent( $dir ) as $file ) { $file['directory'] = $dir; - $file['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($file['mimetype']); + $file['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file['mimetype']); $file["date"] = OCP\Util::formatDate($file["mtime"]); $file['mimetype_icon'] = \OCA\files\lib\Helper::determineIcon($file); $files[] = $file; diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index 3c13b8ea6e2..f0d3560b878 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -84,7 +84,7 @@ class Helper } } $i['directory'] = $dir; - $i['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($i['mimetype']); + $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']); $i['icon'] = \OCA\files\lib\Helper::determineIcon($i); $files[] = $i; } diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index 6d3a07a9d0b..8d474e87b48 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -187,7 +187,7 @@ if (isset($path)) { } else { $i['extension'] = ''; } - $i['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($i['mimetype']); + $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']); } $i['directory'] = $getPath; $i['permissions'] = OCP\PERMISSION_READ; diff --git a/apps/files_trashbin/lib/helper.php b/apps/files_trashbin/lib/helper.php index 098fc0b54b7..4cb5e8a3902 100644 --- a/apps/files_trashbin/lib/helper.php +++ b/apps/files_trashbin/lib/helper.php @@ -61,7 +61,7 @@ class Helper $i['directory'] = ''; } $i['permissions'] = \OCP\PERMISSION_READ; - $i['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($r['mime']); + $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($r['mime']); $i['icon'] = \OCA\files\lib\Helper::determineIcon($i); $files[] = $i; } -- cgit v1.2.3 From fe86182dac387817258942a46905f2b801862d4d Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 17 Sep 2013 17:46:33 +0200 Subject: OC_Cache namespace changes and add UserCache to server container. Refs #4863 --- lib/base.php | 4 +-- lib/cache.php | 8 +++-- lib/cache/broker.php | 4 ++- lib/cache/file.php | 13 +++---- lib/cache/fileglobal.php | 7 ++-- lib/cache/fileglobalgc.php | 5 +-- lib/cache/usercache.php | 77 +++++++++++++++++++++++++++++++++++++++++ lib/filechunking.php | 2 +- lib/public/icache.php | 55 +++++++++++++++++++++++++++++ lib/public/iservercontainer.php | 7 ++++ lib/server.php | 34 +++++++++++------- tests/lib/cache/file.php | 30 ++++++++-------- tests/lib/cache/usercache.php | 68 ++++++++++++++++++++++++++++++++++++ 13 files changed, 270 insertions(+), 44 deletions(-) create mode 100644 lib/cache/usercache.php create mode 100644 lib/public/icache.php create mode 100644 tests/lib/cache/usercache.php diff --git a/lib/base.php b/lib/base.php index 1720a5fd7e1..520be11bc52 100644 --- a/lib/base.php +++ b/lib/base.php @@ -564,11 +564,11 @@ class OC { if (OC_Config::getValue('installed', false)) { //don't try to do this before we are properly setup // register cache cleanup jobs try { //if this is executed before the upgrade to the new backgroundjob system is completed it will throw an exception - \OCP\BackgroundJob::registerJob('OC_Cache_FileGlobalGC'); + \OCP\BackgroundJob::registerJob('OC\Cache\FileGlobalGC'); } catch (Exception $e) { } - OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener'); + OC_Hook::connect('OC_User', 'post_login', 'OC\Cache\File', 'loginListener'); } } diff --git a/lib/cache.php b/lib/cache.php index 48b9964ba9d..c99663a0ca5 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class OC_Cache { +namespace OC\Cache; + +class Cache { /** * @var OC_Cache $user_cache */ @@ -22,7 +24,7 @@ class OC_Cache { */ static public function getGlobalCache() { if (!self::$global_cache) { - self::$global_cache = new OC_Cache_FileGlobal(); + self::$global_cache = new FileGlobal(); } return self::$global_cache; } @@ -33,7 +35,7 @@ class OC_Cache { */ static public function getUserCache() { if (!self::$user_cache) { - self::$user_cache = new OC_Cache_File(); + self::$user_cache = new File(); } return self::$user_cache; } diff --git a/lib/cache/broker.php b/lib/cache/broker.php index a161dbfa3bb..b7f1b67a6d3 100644 --- a/lib/cache/broker.php +++ b/lib/cache/broker.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class OC_Cache_Broker { +namespace OC\Cache; + +class Broker { protected $fast_cache; protected $slow_cache; diff --git a/lib/cache/file.php b/lib/cache/file.php index 361138e4736..2ab914d17b8 100644 --- a/lib/cache/file.php +++ b/lib/cache/file.php @@ -6,24 +6,25 @@ * See the COPYING-README file. */ +namespace OC\Cache; -class OC_Cache_File{ +class File { protected $storage; protected function getStorage() { if (isset($this->storage)) { return $this->storage; } - if(OC_User::isLoggedIn()) { - \OC\Files\Filesystem::initMountPoints(OC_User::getUser()); + if(\OC_User::isLoggedIn()) { + \OC\Files\Filesystem::initMountPoints(\OC_User::getUser()); $subdir = 'cache'; - $view = new \OC\Files\View('/'.OC_User::getUser()); + $view = new \OC\Files\View('/' . \OC_User::getUser()); if(!$view->file_exists($subdir)) { $view->mkdir($subdir); } - $this->storage = new \OC\Files\View('/'.OC_User::getUser().'/'.$subdir); + $this->storage = new \OC\Files\View('/' . \OC_User::getUser().'/'.$subdir); return $this->storage; }else{ - OC_Log::write('core', 'Can\'t get cache storage, user not logged in', OC_Log::ERROR); + \OC_Log::write('core', 'Can\'t get cache storage, user not logged in', \OC_Log::ERROR); return false; } } diff --git a/lib/cache/fileglobal.php b/lib/cache/fileglobal.php index c0bd8e45f39..9ca17402933 100644 --- a/lib/cache/fileglobal.php +++ b/lib/cache/fileglobal.php @@ -6,8 +6,9 @@ * See the COPYING-README file. */ +namespace OC\Cache; -class OC_Cache_FileGlobal{ +class FileGlobal { static protected function getCacheDir() { $cache_dir = get_temp_dir().'/owncloud-'.OC_Util::getInstanceId().'/'; if (!is_dir($cache_dir)) { @@ -80,13 +81,13 @@ class OC_Cache_FileGlobal{ } static public function gc() { - $last_run = OC_AppConfig::getValue('core', 'global_cache_gc_lastrun', 0); + $last_run = \OC_AppConfig::getValue('core', 'global_cache_gc_lastrun', 0); $now = time(); if (($now - $last_run) < 300) { // only do cleanup every 5 minutes return; } - OC_AppConfig::setValue('core', 'global_cache_gc_lastrun', $now); + \OC_AppConfig::setValue('core', 'global_cache_gc_lastrun', $now); $cache_dir = self::getCacheDir(); if($cache_dir and is_dir($cache_dir)) { $dh=opendir($cache_dir); diff --git a/lib/cache/fileglobalgc.php b/lib/cache/fileglobalgc.php index a29c31f9063..399dd5e6f94 100644 --- a/lib/cache/fileglobalgc.php +++ b/lib/cache/fileglobalgc.php @@ -1,8 +1,9 @@ userCache = new File(); + } + + /** + * Get a value from the user cache + * + * @param string $key + * @return mixed + */ + public function get($key) { + return $this->userCache->get($key); + } + + /** + * Set a value in the user cache + * + * @param string $key + * @param mixed $value + * @param int $ttl Time To Live in seconds. Defaults to 60*60*24 + * @return bool + */ + public function set($key, $value, $ttl = 0) { + if (empty($key)) { + return false; + } + return $this->userCache->set($key, $value, $ttl); + } + + /** + * Check if a value is set in the user cache + * + * @param string $key + * @return bool + */ + public function hasKey($key) { + return $this->userCache->hasKey($key); + } + + /** + * Remove an item from the user cache + * + * @param string $key + * @return bool + */ + public function remove($key) { + return $this->userCache->remove($key); + } + + /** + * clear the user cache of all entries starting with a prefix + * @param string prefix (optional) + * @return bool + */ + public function clear($prefix = '') { + return $this->userCache->clear($prefix); + } +} diff --git a/lib/filechunking.php b/lib/filechunking.php index e6d69273a44..313a6ee87d2 100644 --- a/lib/filechunking.php +++ b/lib/filechunking.php @@ -29,7 +29,7 @@ class OC_FileChunking { protected function getCache() { if (!isset($this->cache)) { - $this->cache = new OC_Cache_File(); + $this->cache = new \OC\Cache\File(); } return $this->cache; } diff --git a/lib/public/icache.php b/lib/public/icache.php new file mode 100644 index 00000000000..202459f7c24 --- /dev/null +++ b/lib/public/icache.php @@ -0,0 +1,55 @@ +registerService('ContactsManager', function($c){ + $this->registerService('ContactsManager', function($c) { return new ContactsManager(); }); - $this->registerService('Request', function($c){ + $this->registerService('Request', function($c) { $params = array(); // we json decode the body only in case of content type json @@ -46,10 +46,10 @@ class Server extends SimpleContainer implements IServerContainer { ) ); }); - $this->registerService('PreviewManager', function($c){ + $this->registerService('PreviewManager', function($c) { return new PreviewManager(); }); - $this->registerService('RootFolder', function($c){ + $this->registerService('RootFolder', function($c) { // TODO: get user and user manager from container as well $user = \OC_User::getUser(); $user = \OC_User::getManager()->get($user); @@ -57,6 +57,9 @@ class Server extends SimpleContainer implements IServerContainer { $view = new View(); return new Root($manager, $view, $user); }); + $this->registerService('UserCache', function($c) { + return new UserCache(); + }); } /** @@ -67,14 +70,13 @@ class Server extends SimpleContainer implements IServerContainer { } /** - * The current request object holding all information about the request currently being processed - * is returned from this method. + * The current request object holding all information about the request + * currently being processed is returned from this method. * In case the current execution was not initiated by a web request null is returned * * @return \OCP\IRequest|null */ - function getRequest() - { + function getRequest() { return $this->query('Request'); } @@ -83,8 +85,7 @@ class Server extends SimpleContainer implements IServerContainer { * * @return \OCP\IPreview */ - function getPreviewManager() - { + function getPreviewManager() { return $this->query('PreviewManager'); } @@ -93,8 +94,17 @@ class Server extends SimpleContainer implements IServerContainer { * * @return \OCP\Files\Folder */ - function getRootFolder() - { + function getRootFolder() { return $this->query('RootFolder'); } + + /** + * Returns an ICache instance + * + * @return \OCP\ICache + */ + function getCache() { + return $this->query('UserCache'); + } + } diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php index 038cb21b257..3767c83fcb1 100644 --- a/tests/lib/cache/file.php +++ b/tests/lib/cache/file.php @@ -20,7 +20,9 @@ * */ -class Test_Cache_File extends Test_Cache { +namespace Test\Cache; + +class FileCache extends \Test_Cache { private $user; private $datadir; @@ -30,8 +32,8 @@ class Test_Cache_File extends Test_Cache { public function setUp() { //clear all proxies and hooks so we can do clean testing - OC_FileProxy::clearProxies(); - OC_Hook::clear('OC_Filesystem'); + \OC_FileProxy::clearProxies(); + \OC_Hook::clear('OC_Filesystem'); //disabled atm //enable only the encryption hook if needed @@ -44,27 +46,27 @@ class Test_Cache_File extends Test_Cache { $storage = new \OC\Files\Storage\Temporary(array()); \OC\Files\Filesystem::mount($storage,array(),'/'); $datadir = str_replace('local::', '', $storage->getId()); - $this->datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data'); - OC_Config::setValue('datadirectory', $datadir); + $this->datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); + \OC_Config::setValue('datadirectory', $datadir); - OC_User::clearBackends(); - OC_User::useBackend(new OC_User_Dummy()); + \OC_User::clearBackends(); + \OC_User::useBackend(new \OC_User_Dummy()); //login - OC_User::createUser('test', 'test'); + \OC_User::createUser('test', 'test'); - $this->user=OC_User::getUser(); - OC_User::setUserId('test'); + $this->user = \OC_User::getUser(); + \OC_User::setUserId('test'); //set up the users dir - $rootView=new \OC\Files\View(''); + $rootView = new \OC\Files\View(''); $rootView->mkdir('/test'); - $this->instance=new OC_Cache_File(); + $this->instance=new \OC\Cache\File(); } public function tearDown() { - OC_User::setUserId($this->user); - OC_Config::setValue('datadirectory', $this->datadir); + \OC_User::setUserId($this->user); + \OC_Config::setValue('datadirectory', $this->datadir); } } diff --git a/tests/lib/cache/usercache.php b/tests/lib/cache/usercache.php new file mode 100644 index 00000000000..21b7f848ab6 --- /dev/null +++ b/tests/lib/cache/usercache.php @@ -0,0 +1,68 @@ +. +* +*/ + +namespace Test\Cache; + +class UserCache extends \Test_Cache { + private $user; + private $datadir; + + public function setUp() { + //clear all proxies and hooks so we can do clean testing + \OC_FileProxy::clearProxies(); + \OC_Hook::clear('OC_Filesystem'); + + //disabled atm + //enable only the encryption hook if needed + //if(OC_App::isEnabled('files_encryption')) { + // OC_FileProxy::register(new OC_FileProxy_Encryption()); + //} + + //set up temporary storage + \OC\Files\Filesystem::clearMounts(); + $storage = new \OC\Files\Storage\Temporary(array()); + \OC\Files\Filesystem::mount($storage,array(),'/'); + $datadir = str_replace('local::', '', $storage->getId()); + $this->datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); + \OC_Config::setValue('datadirectory', $datadir); + + \OC_User::clearBackends(); + \OC_User::useBackend(new \OC_User_Dummy()); + + //login + \OC_User::createUser('test', 'test'); + + $this->user = \OC_User::getUser(); + \OC_User::setUserId('test'); + + //set up the users dir + $rootView=new \OC\Files\View(''); + $rootView->mkdir('/test'); + + $this->instance=new \OC\Cache\UserCache(); + } + + public function tearDown() { + \OC_User::setUserId($this->user); + \OC_Config::setValue('datadirectory', $this->datadir); + } +} -- cgit v1.2.3 From 1a130627012bb17ed9edc4583a4d8250ff4e2882 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 17 Sep 2013 18:02:37 +0200 Subject: Add legacy wrapper --- lib/legacy/cache.php | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 lib/legacy/cache.php diff --git a/lib/legacy/cache.php b/lib/legacy/cache.php new file mode 100644 index 00000000000..83b214170f7 --- /dev/null +++ b/lib/legacy/cache.php @@ -0,0 +1,10 @@ + Date: Tue, 17 Sep 2013 18:11:43 +0200 Subject: check only permission from link-share to decide if public upload is enabled or disabled --- core/js/share.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/js/share.js b/core/js/share.js index 5d34faf8a5d..250f410072c 100644 --- a/core/js/share.js +++ b/core/js/share.js @@ -177,7 +177,9 @@ OC.Share={ if (allowPublicUploadStatus) { return true; } - allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false; + if (value.share_type === OC.Share.SHARE_TYPE_LINK) { + allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false; + } }); html += ''; -- cgit v1.2.3 From 642b064c5b98990f6ac0e3ba344db8cd1fe4d1f8 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 17 Sep 2013 18:18:23 +0200 Subject: we can leave the loop if the permission of the link share was checked --- core/js/share.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/js/share.js b/core/js/share.js index 250f410072c..641252a4d78 100644 --- a/core/js/share.js +++ b/core/js/share.js @@ -174,11 +174,9 @@ OC.Share={ var allowPublicUploadStatus = false; $.each(data.shares, function(key, value) { - if (allowPublicUploadStatus) { - return true; - } if (value.share_type === OC.Share.SHARE_TYPE_LINK) { allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false; + return true; } }); -- cgit v1.2.3 From 5c19b995db6dab9aae579274db82413117cce67b Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 17 Sep 2013 18:31:14 +0200 Subject: Add interface for Session and add getter in server container. --- lib/public/iservercontainer.php | 7 +++++++ lib/public/isession.php | 44 +++++++++++++++++++++++++++++++++++++++++ lib/server.php | 10 ++++++++++ lib/session/session.php | 2 +- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 lib/public/isession.php diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index d88330698dc..ec7212b306e 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -62,4 +62,11 @@ interface IServerContainer { */ function getRootFolder(); + /** + * Returns the current session + * + * @return \OCP\ISession + */ + function getSession(); + } diff --git a/lib/public/isession.php b/lib/public/isession.php new file mode 100644 index 00000000000..5f9ce32f3b1 --- /dev/null +++ b/lib/public/isession.php @@ -0,0 +1,44 @@ +query('RootFolder'); } + + /** + * Returns the current session + * + * @return \OCP\ISession + */ + function getSession() { + return \OC::$session; + } + } diff --git a/lib/session/session.php b/lib/session/session.php index 55515f57a87..c55001eccac 100644 --- a/lib/session/session.php +++ b/lib/session/session.php @@ -8,7 +8,7 @@ namespace OC\Session; -abstract class Session implements \ArrayAccess { +abstract class Session implements \ArrayAccess, \OCP\ISession { /** * $name serves as a namespace for the session keys * -- cgit v1.2.3 From 5bddb5377a40c987223804e8c3846437b6cf120a Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 17 Sep 2013 18:38:18 +0200 Subject: Purge session from Request - and fix some styles --- lib/appframework/http/request.php | 51 ++++++++++++--------------------------- lib/public/irequest.php | 9 ------- lib/server.php | 1 - 3 files changed, 16 insertions(+), 45 deletions(-) diff --git a/lib/appframework/http/request.php b/lib/appframework/http/request.php index 4f1775182a1..34605acdfea 100644 --- a/lib/appframework/http/request.php +++ b/lib/appframework/http/request.php @@ -33,16 +33,15 @@ class Request implements \ArrayAccess, \Countable, IRequest { protected $items = array(); protected $allowedKeys = array( - 'get', - 'post', - 'files', - 'server', - 'env', - 'session', - 'cookies', - 'urlParams', - 'params', - 'parameters', + 'get', + 'post', + 'files', + 'server', + 'env', + 'cookies', + 'urlParams', + 'params', + 'parameters', 'method' ); @@ -156,7 +155,6 @@ class Request implements \ArrayAccess, \Countable, IRequest { case 'files': case 'server': case 'env': - case 'session': case 'cookies': case 'parameters': case 'params': @@ -229,8 +227,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { * @param mixed $default If the key is not found, this value will be returned * @return mixed the content of the array */ - public function getParam($key, $default = null) - { + public function getParam($key, $default = null) { return isset($this->parameters[$key]) ? $this->parameters[$key] : $default; @@ -241,8 +238,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { * (as GET or POST) or throuh the URL by the route * @return array the array with all parameters */ - public function getParams() - { + public function getParams() { return $this->parameters; } @@ -250,8 +246,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { * Returns the method of the request * @return string the method of the request (POST, GET, etc) */ - public function getMethod() - { + public function getMethod() { return $this->method; } @@ -260,8 +255,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { * @param string $key the key that will be taken from the $_FILES array * @return array the file in the $_FILES element */ - public function getUploadedFile($key) - { + public function getUploadedFile($key) { return isset($this->files[$key]) ? $this->files[$key] : null; } @@ -270,28 +264,16 @@ class Request implements \ArrayAccess, \Countable, IRequest { * @param string $key the key that will be taken from the $_ENV array * @return array the value in the $_ENV element */ - public function getEnv($key) - { + public function getEnv($key) { return isset($this->env[$key]) ? $this->env[$key] : null; } - /** - * Shortcut for getting session variables - * @param string $key the key that will be taken from the $_SESSION array - * @return array the value in the $_SESSION element - */ - function getSession($key) - { - return isset($this->session[$key]) ? $this->session[$key] : null; - } - /** * Shortcut for getting cookie variables * @param string $key the key that will be taken from the $_COOKIE array * @return array the value in the $_COOKIE element */ - function getCookie($key) - { + function getCookie($key) { return isset($this->cookies[$key]) ? $this->cookies[$key] : null; } @@ -304,8 +286,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { * * @throws \LogicException */ - function getContent($asResource = false) - { + function getContent($asResource = false) { return null; // if (false === $this->content || (true === $asResource && null !== $this->content)) { // throw new \LogicException('getContent() can only be called once when using the resource return type.'); diff --git a/lib/public/irequest.php b/lib/public/irequest.php index cd39855950b..9f335b06f2a 100644 --- a/lib/public/irequest.php +++ b/lib/public/irequest.php @@ -76,15 +76,6 @@ interface IRequest { public function getEnv($key); - /** - * Shortcut for getting session variables - * - * @param string $key the key that will be taken from the $_SESSION array - * @return array the value in the $_SESSION element - */ - function getSession($key); - - /** * Shortcut for getting cookie variables * diff --git a/lib/server.php b/lib/server.php index 0124ad72c02..0eee3e0f73a 100644 --- a/lib/server.php +++ b/lib/server.php @@ -36,7 +36,6 @@ class Server extends SimpleContainer implements IServerContainer { 'files' => $_FILES, 'server' => $_SERVER, 'env' => $_ENV, - 'session' => $_SESSION, 'cookies' => $_COOKIE, 'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) ? $_SERVER['REQUEST_METHOD'] -- cgit v1.2.3 From 8b4f4a79e22dc08cf7c13a91c926c229676d6522 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 17 Sep 2013 19:46:08 +0200 Subject: Still some session leftovers. --- lib/appframework/controller/controller.php | 10 ---------- tests/lib/appframework/controller/ControllerTest.php | 5 ----- 2 files changed, 15 deletions(-) diff --git a/lib/appframework/controller/controller.php b/lib/appframework/controller/controller.php index a7498ba0e1e..0ea0a38cc09 100644 --- a/lib/appframework/controller/controller.php +++ b/lib/appframework/controller/controller.php @@ -106,16 +106,6 @@ abstract class Controller { } - /** - * Shortcut for getting session variables - * @param string $key the key that will be taken from the $_SESSION array - * @return array the value in the $_SESSION element - */ - public function session($key) { - return $this->request->getSession($key); - } - - /** * Shortcut for getting cookie variables * @param string $key the key that will be taken from the $_COOKIE array diff --git a/tests/lib/appframework/controller/ControllerTest.php b/tests/lib/appframework/controller/ControllerTest.php index 246371d249c..4441bddfca9 100644 --- a/tests/lib/appframework/controller/ControllerTest.php +++ b/tests/lib/appframework/controller/ControllerTest.php @@ -152,9 +152,4 @@ class ControllerTest extends \PHPUnit_Framework_TestCase { $this->assertEquals('daheim', $this->controller->env('PATH')); } - public function testGetSessionVariable(){ - $this->assertEquals('kein', $this->controller->session('sezession')); - } - - } -- cgit v1.2.3 From b0762ad3bf5121ccd300ec6c22641c3bf323ba61 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 00:37:00 +0200 Subject: OC_VCategories=>OC\Tags. Public interface + getter in server container --- lib/public/iservercontainer.php | 7 + lib/public/itags.php | 173 +++++++++ lib/server.php | 12 + lib/tags.php | 621 ++++++++++++++++++++++++++++++ lib/vcategories.php | 833 ---------------------------------------- tests/lib/tags.php | 133 +++++++ tests/lib/vcategories.php | 128 ------ 7 files changed, 946 insertions(+), 961 deletions(-) create mode 100644 lib/public/itags.php create mode 100644 lib/tags.php delete mode 100644 lib/vcategories.php create mode 100644 tests/lib/tags.php delete mode 100644 tests/lib/vcategories.php diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index d88330698dc..e44acee6533 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -55,6 +55,13 @@ interface IServerContainer { */ function getPreviewManager(); + /** + * Returns the tag manager which can get and set tags for different object types + * + * @return \OCP\ITags + */ + function getTagManager(); + /** * Returns the root folder of ownCloud's data directory * diff --git a/lib/public/itags.php b/lib/public/itags.php new file mode 100644 index 00000000000..047d4f5f40b --- /dev/null +++ b/lib/public/itags.php @@ -0,0 +1,173 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +namespace OCP; + +// FIXME: Where should I put this? Or should it be implemented as a Listener? +\OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Tags', 'post_deleteUser'); + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +interface ITags { + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function loadTagsFor($type, $defaultTags=array()); + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty(); + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @returns array + */ + public function tags(); + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function idsForTag($tag); + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name); + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name); + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to); + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMulti($names, $sync=false, $id = null); + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids); + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites(); + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid); + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid); + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag); + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag); + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names); + +} \ No newline at end of file diff --git a/lib/server.php b/lib/server.php index 9e87bd3190d..f25216b746d 100644 --- a/lib/server.php +++ b/lib/server.php @@ -49,6 +49,9 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('PreviewManager', function($c){ return new PreviewManager(); }); + $this->registerService('TagManager', function($c){ + return new Tags(); + }); $this->registerService('RootFolder', function($c){ // TODO: get user and user manager from container as well $user = \OC_User::getUser(); @@ -88,6 +91,15 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('PreviewManager'); } + /** + * Returns the tag manager which can get and set tags for different object types + * + * @return \OCP\ITags + */ + function getTagManager() { + return $this->query('TagManager'); + } + /** * Returns the root folder of ownCloud's data directory * diff --git a/lib/tags.php b/lib/tags.php new file mode 100644 index 00000000000..4aafff8e1bb --- /dev/null +++ b/lib/tags.php @@ -0,0 +1,621 @@ + +* @copyright 2012 Bart Visscher bartv@thisnet.nl +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class Tags implements \OCP\ITags { + + /** + * Tags + */ + private $tags = array(); + + /** + * Used for storing objectid/categoryname pairs while rescanning. + */ + private static $relations = array(); + + private $type = null; + private $user = null; + + const TAG_TABLE = '*PREFIX*vcategory'; + const RELATION_TABLE = '*PREFIX*vcategory_to_object'; + + const TAG_FAVORITE = '_$!!$_'; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user) { + + $this->user = $user; + + } + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function loadTagsFor($type, $defaultTags=array()) { + $this->type = $type; + $this->tags = array(); + $result = null; + $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $this->tags[$row['id']] = $row['category']; + } + } + + if(count($defaultTags) > 0 && count($this->tags) === 0) { + $this->addMulti($defaultTags, true); + } + \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), + \OCP\Util::DEBUG); + + return $this; + } + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty() { + $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ?'; + try { + $stmt = OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + return ($result->numRows() === 0); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @return array + */ + public function tags() { + if(!count($this->tags)) { + return array(); + } + + $tags = array_values($this->tags); + uasort($tags, 'strnatcasecmp'); + $tagMap = array(); + + foreach($tags as $tag) { + if($tag !== self::TAG_FAVORITE) { + $tagMap[] = array( + 'id' => $this->array_searchi($tag, $this->tags), + 'name' => $tag + ); + } + } + return $tagMap; + + } + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function idsForTag($tag) { + $result = null; + if(is_numeric($tag)) { + $tagId = $tag; + } elseif(is_string($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } + + if($tagId === false) { + $l10n = \OC_L10N::get('core'); + throw new \Exception( + $l10n->t('Could not find category "%s"', $tag) + ); + } + + $ids = array(); + $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE + . '` WHERE `categoryid` = ?'; + + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($tagId)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $ids[] = (int)$row['objid']; + } + } + + return $ids; + } + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name) { + return $this->in_arrayi($name, $this->tags); + } + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name) { + $name = trim($name); + + if($this->hasTag($name)) { + \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG); + return false; + } + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $name, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $id = \OCP\DB::insertid(self::TAG_TABLE); + \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); + $this->tags[$id] = $name; + return $id; + } + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to) { + $from = trim($from); + $to = trim($to); + $id = $this->array_searchi($from, $this->tags); + if($id === false) { + \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG); + return false; + } + + $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? ' + . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($to, $this->user, $this->type, $id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $this->tags[$id] = $to; + return true; + } + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMulti($names, $sync=false, $id = null) { + if(!is_array($names)) { + $names = array($names); + } + $names = array_map('trim', $names); + $newones = array(); + foreach($names as $name) { + if(($this->in_arrayi( + $name, $this->tags) == false) && $name !== '') { + $newones[] = $name; + } + if(!is_null($id) ) { + // Insert $objectid, $categoryid pairs if not exist. + self::$relations[] = array('objid' => $id, 'tag' => $name); + } + } + $this->tags = array_merge($this->tags, $newones); + if($sync === true) { + $this->save(); + } + + return true; + } + + /** + * Save the list of tags and their object relations + */ + protected function save() { + if(is_array($this->tags)) { + foreach($this->tags as $tag) { + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $tag, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + // reload tags to get the proper ids. + $this->loadTagsFor($this->type); + // Loop through temporarily cached objectid/tagname pairs + // and save relations. + $tags = $this->tags; + // For some reason this is needed or array_search(i) will return 0..? + ksort($tags); + foreach(self::$relations as $relation) { + $tagId = $this->array_searchi($relation['tag'], $tags); + \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG); + if($tagId) { + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $relation['objid'], + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } + self::$relations = array(); // reset + } else { + \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! ' + . print_r($this->tags, true), \OCP\Util::ERROR); + } + } + + /** + * Delete tags and tag/object relations for a user. + * + * For hooking up on post_deleteUser + * + * @param array + */ + public static function post_deleteUser($arguments) { + // Find all objectid/tagId pairs. + $result = null; + try { + $stmt = \OCP\DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'); + while( $row = $result->fetchRow()) { + try { + $stmt->execute(array($row['id'])); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), OCP\Util::ERROR); + } + } + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids) { + if(count($ids) === 0) { + // job done ;) + return true; + } + $updates = $ids; + try { + $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; + $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; + $query .= 'AND `type`= ?'; + $updates[] = $this->type; + $stmt = OCP\DB::prepare($query); + $result = $stmt->execute($updates); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites() { + try { + return $this->idsForTag(self::TAG_FAVORITE); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return array(); + } + } + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid) { + if(!$this->hasCategory(self::TAG_FAVORITE)) { + $this->add(self::TAG_FAVORITE, true); + } + return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid) { + return $this->unTag($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + if(!$this->hasTag($tag)) { + $this->add($tag, true); + } + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $objid, + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; + $stmt = \OCP\DB::prepare($sql); + $stmt->execute(array($objid, $tagId, $this->type)); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names) { + if(!is_array($names)) { + $names = array($names); + } + + $names = array_map('trim', $names); + + \OCP\Util::writeLog('core', __METHOD__ . ', before: ' + . print_r($this->tags, true), \OCP\Util::DEBUG); + foreach($names as $name) { + $id = null; + + if($this->hasTag($name)) { + $id = $this->array_searchi($name, $this->tags); + unset($this->tags[$id]); + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE ' + . '`uid` = ? AND `type` = ? AND `category` = ?'); + $result = $stmt->execute(array($this->user, $this->type, $name)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); + return false; + } + if(!is_null($id) && $id !== false) { + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'; + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', + __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), + \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + } + return true; + } + + // case-insensitive in_array + private function in_arrayi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return in_array(strtolower($needle), array_map('strtolower', $haystack)); + } + + // case-insensitive array_search + private function array_searchi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return array_search(strtolower($needle), array_map('strtolower', $haystack)); + } +} diff --git a/lib/vcategories.php b/lib/vcategories.php deleted file mode 100644 index a7e4c54be29..00000000000 --- a/lib/vcategories.php +++ /dev/null @@ -1,833 +0,0 @@ - -* @copyright 2012 Bart Visscher bartv@thisnet.nl -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 library. If not, see . -* -*/ - -OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'post_deleteUser'); - -/** - * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. - * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or - * anything else that is either parsed from a vobject or that the user chooses - * to add. - * Category names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a category 'family' for a type, and - * tries to add a category named 'Family' it will be silently ignored. - */ -class OC_VCategories { - - /** - * Categories - */ - private $categories = array(); - - /** - * Used for storing objectid/categoryname pairs while rescanning. - */ - private static $relations = array(); - - private $type = null; - private $user = null; - - const CATEGORY_TABLE = '*PREFIX*vcategory'; - const RELATION_TABLE = '*PREFIX*vcategory_to_object'; - - const CATEGORY_FAVORITE = '_$!!$_'; - - const FORMAT_LIST = 0; - const FORMAT_MAP = 1; - - /** - * @brief Constructor. - * @param $type The type identifier e.g. 'contact' or 'event'. - * @param $user The user whos data the object will operate on. This - * parameter should normally be omitted but to make an app able to - * update categories for all users it is made possible to provide it. - * @param $defcategories An array of default categories to be used if none is stored. - */ - public function __construct($type, $user=null, $defcategories=array()) { - $this->type = $type; - $this->user = is_null($user) ? OC_User::getUser() : $user; - - $this->loadCategories(); - OCP\Util::writeLog('core', __METHOD__ . ', categories: ' - . print_r($this->categories, true), - OCP\Util::DEBUG - ); - - if($defcategories && count($this->categories) === 0) { - $this->addMulti($defcategories, true); - } - } - - /** - * @brief Load categories from db. - */ - private function loadCategories() { - $this->categories = array(); - $result = null; - $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - // The keys are prefixed because array_search wouldn't work otherwise :-/ - $this->categories[$row['id']] = $row['category']; - } - } - OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r($this->categories, true), - OCP\Util::DEBUG); - } - - - /** - * @brief Check if any categories are saved for this type and user. - * @returns boolean. - * @param $type The type identifier e.g. 'contact' or 'event'. - * @param $user The user whos categories will be checked. If not set current user will be used. - */ - public static function isEmpty($type, $user = null) { - $user = is_null($user) ? OC_User::getUser() : $user; - $sql = 'SELECT COUNT(*) FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($user, $type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - return ($result->numRows() === 0); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - } - - /** - * @brief Get the categories for a specific user. - * @param - * @returns array containing the categories as strings. - */ - public function categories($format = null) { - if(!$this->categories) { - return array(); - } - $categories = array_values($this->categories); - uasort($categories, 'strnatcasecmp'); - if($format == self::FORMAT_MAP) { - $catmap = array(); - foreach($categories as $category) { - if($category !== self::CATEGORY_FAVORITE) { - $catmap[] = array( - 'id' => $this->array_searchi($category, $this->categories), - 'name' => $category - ); - } - } - return $catmap; - } - - // Don't add favorites to normal categories. - $favpos = array_search(self::CATEGORY_FAVORITE, $categories); - if($favpos !== false) { - return array_splice($categories, $favpos); - } else { - return $categories; - } - } - - /** - * Get the a list if items belonging to $category. - * - * Throws an exception if the category could not be found. - * - * @param string|integer $category Category id or name. - * @returns array An array of object ids or false on error. - */ - public function idsForCategory($category) { - $result = null; - if(is_numeric($category)) { - $catid = $category; - } elseif(is_string($category)) { - $category = trim($category); - $catid = $this->array_searchi($category, $this->categories); - } - OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); - if($catid === false) { - $l10n = OC_L10N::get('core'); - throw new Exception( - $l10n->t('Could not find category "%s"', $category) - ); - } - - $ids = array(); - $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE - . '` WHERE `categoryid` = ?'; - - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($catid)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $ids[] = (int)$row['objid']; - } - } - - return $ids; - } - - /** - * Get the a list if items belonging to $category. - * - * Throws an exception if the category could not be found. - * - * @param string|integer $category Category id or name. - * @param array $tableinfo Array in the form {'tablename' => table, 'fields' => ['field1', 'field2']} - * @param int $limit - * @param int $offset - * - * This generic method queries a table assuming that the id - * field is called 'id' and the table name provided is in - * the form '*PREFIX*table_name'. - * - * If the category name cannot be resolved an exception is thrown. - * - * TODO: Maybe add the getting permissions for objects? - * - * @returns array containing the resulting items or false on error. - */ - public function itemsForCategory($category, $tableinfo, $limit = null, $offset = null) { - $result = null; - if(is_numeric($category)) { - $catid = $category; - } elseif(is_string($category)) { - $category = trim($category); - $catid = $this->array_searchi($category, $this->categories); - } - OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); - if($catid === false) { - $l10n = OC_L10N::get('core'); - throw new Exception( - $l10n->t('Could not find category "%s"', $category) - ); - } - $fields = ''; - foreach($tableinfo['fields'] as $field) { - $fields .= '`' . $tableinfo['tablename'] . '`.`' . $field . '`,'; - } - $fields = substr($fields, 0, -1); - - $items = array(); - $sql = 'SELECT `' . self::RELATION_TABLE . '`.`categoryid`, ' . $fields - . ' FROM `' . $tableinfo['tablename'] . '` JOIN `' - . self::RELATION_TABLE . '` ON `' . $tableinfo['tablename'] - . '`.`id` = `' . self::RELATION_TABLE . '`.`objid` WHERE `' - . self::RELATION_TABLE . '`.`categoryid` = ?'; - - try { - $stmt = OCP\DB::prepare($sql, $limit, $offset); - $result = $stmt->execute(array($catid)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $items[] = $row; - } - } - //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); - //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); - - return $items; - } - - /** - * @brief Checks whether a category is already saved. - * @param $name The name to check for. - * @returns bool - */ - public function hasCategory($name) { - return $this->in_arrayi($name, $this->categories); - } - - /** - * @brief Add a new category. - * @param $name A string with a name of the category - * @returns int the id of the added category or false if it already exists. - */ - public function add($name) { - $name = trim($name); - OCP\Util::writeLog('core', __METHOD__.', name: ' . $name, OCP\Util::DEBUG); - if($this->hasCategory($name)) { - OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', OCP\Util::DEBUG); - return false; - } - try { - OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $name, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - $id = OCP\DB::insertid(self::CATEGORY_TABLE); - OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, OCP\Util::DEBUG); - $this->categories[$id] = $name; - return $id; - } - - /** - * @brief Rename category. - * @param string $from The name of the existing category - * @param string $to The new name of the category. - * @returns bool - */ - public function rename($from, $to) { - $from = trim($from); - $to = trim($to); - $id = $this->array_searchi($from, $this->categories); - if($id === false) { - OCP\Util::writeLog('core', __METHOD__.', category: ' . $from. ' does not exist', OCP\Util::DEBUG); - return false; - } - - $sql = 'UPDATE `' . self::CATEGORY_TABLE . '` SET `category` = ? ' - . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($to, $this->user, $this->type, $id)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - $this->categories[$id] = $to; - return true; - } - - /** - * @brief Add a new category. - * @param $names A string with a name or an array of strings containing - * the name(s) of the categor(y|ies) to add. - * @param $sync bool When true, save the categories - * @param $id int Optional object id to add to this|these categor(y|ies) - * @returns bool Returns false on error. - */ - public function addMulti($names, $sync=false, $id = null) { - if(!is_array($names)) { - $names = array($names); - } - $names = array_map('trim', $names); - $newones = array(); - foreach($names as $name) { - if(($this->in_arrayi( - $name, $this->categories) == false) && $name != '') { - $newones[] = $name; - } - if(!is_null($id) ) { - // Insert $objectid, $categoryid pairs if not exist. - self::$relations[] = array('objid' => $id, 'category' => $name); - } - } - $this->categories = array_merge($this->categories, $newones); - if($sync === true) { - $this->save(); - } - - return true; - } - - /** - * @brief Extracts categories from a vobject and add the ones not already present. - * @param $vobject The instance of OC_VObject to load the categories from. - */ - public function loadFromVObject($id, $vobject, $sync=false) { - $this->addMulti($vobject->getAsArray('CATEGORIES'), $sync, $id); - } - - /** - * @brief Reset saved categories and rescan supplied vobjects for categories. - * @param $objects An array of vobjects (as text). - * To get the object array, do something like: - * // For Addressbook: - * $categories = new OC_VCategories('contacts'); - * $stmt = OC_DB::prepare( 'SELECT `carddata` FROM `*PREFIX*contacts_cards`' ); - * $result = $stmt->execute(); - * $objects = array(); - * if(!is_null($result)) { - * while( $row = $result->fetchRow()){ - * $objects[] = array($row['id'], $row['carddata']); - * } - * } - * $categories->rescan($objects); - */ - public function rescan($objects, $sync=true, $reset=true) { - - if($reset === true) { - $result = null; - // Find all objectid/categoryid pairs. - try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - // And delete them. - if(!is_null($result)) { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ? AND `type`= ?'); - while( $row = $result->fetchRow()) { - $stmt->execute(array($row['id'], $this->type)); - } - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - return; - } - $this->categories = array(); - } - // Parse all the VObjects - foreach($objects as $object) { - $vobject = OC_VObject::parse($object[1]); - if(!is_null($vobject)) { - // Load the categories - $this->loadFromVObject($object[0], $vobject, $sync); - } else { - OC_Log::write('core', __METHOD__ . ', unable to parse. ID: ' . ', ' - . substr($object, 0, 100) . '(...)', OC_Log::DEBUG); - } - } - $this->save(); - } - - /** - * @brief Save the list with categories - */ - private function save() { - if(is_array($this->categories)) { - foreach($this->categories as $category) { - try { - OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $category, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - // reload categories to get the proper ids. - $this->loadCategories(); - // Loop through temporarily cached objectid/categoryname pairs - // and save relations. - $categories = $this->categories; - // For some reason this is needed or array_search(i) will return 0..? - ksort($categories); - foreach(self::$relations as $relation) { - $catid = $this->array_searchi($relation['category'], $categories); - OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG); - if($catid) { - try { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $relation['objid'], - 'categoryid' => $catid, - 'type' => $this->type, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - } - self::$relations = array(); // reset - } else { - OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' - . print_r($this->categories, true), OC_Log::ERROR); - } - } - - /** - * @brief Delete categories and category/object relations for a user. - * For hooking up on post_deleteUser - * @param string $uid The user id for which entries should be purged. - */ - public static function post_deleteUser($arguments) { - // Find all objectid/categoryid pairs. - $result = null; - try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - if(!is_null($result)) { - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'); - while( $row = $result->fetchRow()) { - try { - $stmt->execute(array($row['id'])); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - } - } - - /** - * @brief Delete category/object relations from the db - * @param array $ids The ids of the objects - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean Returns false on error. - */ - public function purgeObjects(array $ids, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(count($ids) === 0) { - // job done ;) - return true; - } - $updates = $ids; - try { - $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; - $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; - $query .= 'AND `type`= ?'; - $updates[] = $type; - $stmt = OCP\DB::prepare($query); - $result = $stmt->execute($updates); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Get favorites for an object type - * - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns array An array of object ids. - */ - public function getFavorites($type = null) { - $type = is_null($type) ? $this->type : $type; - - try { - return $this->idsForCategory(self::CATEGORY_FAVORITE); - } catch(Exception $e) { - // No favorites - return array(); - } - } - - /** - * Add an object to favorites - * - * @param int $objid The id of the object - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function addToFavorites($objid, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(!$this->hasCategory(self::CATEGORY_FAVORITE)) { - $this->add(self::CATEGORY_FAVORITE, true); - } - return $this->addToCategory($objid, self::CATEGORY_FAVORITE, $type); - } - - /** - * Remove an object from favorites - * - * @param int $objid The id of the object - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function removeFromFavorites($objid, $type = null) { - $type = is_null($type) ? $this->type : $type; - return $this->removeFromCategory($objid, self::CATEGORY_FAVORITE, $type); - } - - /** - * @brief Creates a category/object relation. - * @param int $objid The id of the object - * @param int|string $category The id or name of the category - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean Returns false on database error. - */ - public function addToCategory($objid, $category, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(is_string($category) && !is_numeric($category)) { - $category = trim($category); - if(!$this->hasCategory($category)) { - $this->add($category, true); - } - $categoryid = $this->array_searchi($category, $this->categories); - } else { - $categoryid = $category; - } - try { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $objid, - 'categoryid' => $categoryid, - 'type' => $type, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * @brief Delete single category/object relation from the db - * @param int $objid The id of the object - * @param int|string $category The id or name of the category - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function removeFromCategory($objid, $category, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(is_string($category) && !is_numeric($category)) { - $category = trim($category); - $categoryid = $this->array_searchi($category, $this->categories); - } else { - $categoryid = $category; - } - - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; - OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type, - OCP\Util::DEBUG); - $stmt = OCP\DB::prepare($sql); - $stmt->execute(array($objid, $categoryid, $type)); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * @brief Delete categories from the db and from all the vobject supplied - * @param $names An array of categories to delete - * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. - */ - public function delete($names, array &$objects=null) { - if(!is_array($names)) { - $names = array($names); - } - - $names = array_map('trim', $names); - - OC_Log::write('core', __METHOD__ . ', before: ' - . print_r($this->categories, true), OC_Log::DEBUG); - foreach($names as $name) { - $id = null; - OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); - if($this->hasCategory($name)) { - $id = $this->array_searchi($name, $this->categories); - unset($this->categories[$id]); - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' - . '`uid` = ? AND `type` = ? AND `category` = ?'); - $result = $stmt->execute(array($this->user, $this->type, $name)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - } - if(!is_null($id) && $id !== false) { - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'; - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($id)); - if (OC_DB::isError($result)) { - OC_Log::write('core', - __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), - OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - } - } - OC_Log::write('core', __METHOD__.', after: ' - . print_r($this->categories, true), OC_Log::DEBUG); - if(!is_null($objects)) { - foreach($objects as $key=>&$value) { - $vobject = OC_VObject::parse($value[1]); - if(!is_null($vobject)) { - $object = null; - $componentname = ''; - if (isset($vobject->VEVENT)) { - $object = $vobject->VEVENT; - $componentname = 'VEVENT'; - } else - if (isset($vobject->VTODO)) { - $object = $vobject->VTODO; - $componentname = 'VTODO'; - } else - if (isset($vobject->VJOURNAL)) { - $object = $vobject->VJOURNAL; - $componentname = 'VJOURNAL'; - } else { - $object = $vobject; - } - $categories = $object->getAsArray('CATEGORIES'); - foreach($names as $name) { - $idx = $this->array_searchi($name, $categories); - if($idx !== false) { - OC_Log::write('core', __METHOD__ - .', unsetting: ' - . $categories[$this->array_searchi($name, $categories)], - OC_Log::DEBUG); - unset($categories[$this->array_searchi($name, $categories)]); - } - } - - $object->setString('CATEGORIES', implode(',', $categories)); - if($vobject !== $object) { - $vobject[$componentname] = $object; - } - $value[1] = $vobject->serialize(); - $objects[$key] = $value; - } else { - OC_Log::write('core', __METHOD__ - .', unable to parse. ID: ' . $value[0] . ', ' - . substr($value[1], 0, 50) . '(...)', OC_Log::DEBUG); - } - } - } - } - - // case-insensitive in_array - private function in_arrayi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return in_array(strtolower($needle), array_map('strtolower', $haystack)); - } - - // case-insensitive array_search - private function array_searchi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return array_search(strtolower($needle), array_map('strtolower', $haystack)); - } -} diff --git a/tests/lib/tags.php b/tests/lib/tags.php new file mode 100644 index 00000000000..06baebc0af7 --- /dev/null +++ b/tests/lib/tags.php @@ -0,0 +1,133 @@ +. +* +*/ + +class Test_Tags extends PHPUnit_Framework_TestCase { + + protected $objectType; + protected $user; + protected $backupGlobals = FALSE; + + public function setUp() { + + OC_User::clearBackends(); + OC_User::useBackend('dummy'); + $this->user = uniqid('user_'); + $this->objectType = uniqid('type_'); + OC_User::createUser($this->user, 'pass'); + OC_User::setUserId($this->user); + + } + + public function tearDown() { + //$query = OC_DB::prepare('DELETE FROM `*PREFIX*vcategories` WHERE `item_type` = ?'); + //$query->execute(array('test')); + } + + public function testInstantiateWithDefaults() { + $defaultTags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertEquals(4, count($tagMgr->tags())); + } + + public function testAddTags() { + $tags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($tags as $tag) { + $result = $tagMgr->add($tag); + $this->assertTrue((bool)$result); + } + + $this->assertFalse($tagMgr->add('Family')); + $this->assertFalse($tagMgr->add('fAMILY')); + + $this->assertEquals(4, count($tagMgr->tags())); + } + + public function testdeleteTags() { + $defaultTags = array('Friends', 'Family', 'Work', 'Other'); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertEquals(4, count($tagMgr->tags())); + + $tagMgr->delete('family'); + $this->assertEquals(3, count($tagMgr->tags())); + + $tagMgr->delete(array('Friends', 'Work', 'Other')); + $this->assertEquals(0, count($tagMgr->tags())); + + } + + public function testRenameTag() { + $defaultTags = array('Friends', 'Family', 'Wrok', 'Other'); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertTrue($tagMgr->rename('Wrok', 'Work')); + $this->assertTrue($tagMgr->hasTag('Work')); + $this->assertFalse($tagMgr->hastag('Wrok')); + $this->assertFalse($tagMgr->rename('Wrok', 'Work')); + + } + + public function testTagAs() { + $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($objids as $id) { + $tagMgr->tagAs($id, 'Family'); + } + + $this->assertEquals(1, count($tagMgr->tags())); + $this->assertEquals(9, count($tagMgr->idsForTag('Family'))); + } + + /** + * @depends testTagAs + */ + public function testUnTag() { + $objIds = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + // Is this "legal"? + $this->testTagAs(); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($objIds as $id) { + $this->assertTrue(in_array($id, $tagMgr->idsForTag('Family'))); + $tagMgr->unTag($id, 'Family'); + $this->assertFalse(in_array($id, $tagMgr->idsForTag('Family'))); + } + + $this->assertEquals(1, count($tagMgr->tags())); + $this->assertEquals(0, count($tagMgr->idsForTag('Family'))); + } + +} diff --git a/tests/lib/vcategories.php b/tests/lib/vcategories.php deleted file mode 100644 index df5f600f20d..00000000000 --- a/tests/lib/vcategories.php +++ /dev/null @@ -1,128 +0,0 @@ -. -* -*/ - -//require_once("../lib/template.php"); - -class Test_VCategories extends PHPUnit_Framework_TestCase { - - protected $objectType; - protected $user; - protected $backupGlobals = FALSE; - - public function setUp() { - - OC_User::clearBackends(); - OC_User::useBackend('dummy'); - $this->user = uniqid('user_'); - $this->objectType = uniqid('type_'); - OC_User::createUser($this->user, 'pass'); - OC_User::setUserId($this->user); - - } - - public function tearDown() { - //$query = OC_DB::prepare('DELETE FROM `*PREFIX*vcategories` WHERE `item_type` = ?'); - //$query->execute(array('test')); - } - - public function testInstantiateWithDefaults() { - $defcategories = array('Friends', 'Family', 'Work', 'Other'); - - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - - $this->assertEquals(4, count($catmgr->categories())); - } - - public function testAddCategories() { - $categories = array('Friends', 'Family', 'Work', 'Other'); - - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($categories as $category) { - $result = $catmgr->add($category); - $this->assertTrue((bool)$result); - } - - $this->assertFalse($catmgr->add('Family')); - $this->assertFalse($catmgr->add('fAMILY')); - - $this->assertEquals(4, count($catmgr->categories())); - } - - public function testdeleteCategories() { - $defcategories = array('Friends', 'Family', 'Work', 'Other'); - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - $this->assertEquals(4, count($catmgr->categories())); - - $catmgr->delete('family'); - $this->assertEquals(3, count($catmgr->categories())); - - $catmgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($catmgr->categories())); - - } - - public function testrenameCategory() { - $defcategories = array('Friends', 'Family', 'Wrok', 'Other'); - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - - $this->assertTrue($catmgr->rename('Wrok', 'Work')); - $this->assertTrue($catmgr->hasCategory('Work')); - $this->assertFalse($catmgr->hasCategory('Wrok')); - $this->assertFalse($catmgr->rename('Wrok', 'Work')); - - } - - public function testAddToCategory() { - $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($objids as $id) { - $catmgr->addToCategory($id, 'Family'); - } - - $this->assertEquals(1, count($catmgr->categories())); - $this->assertEquals(9, count($catmgr->idsForCategory('Family'))); - } - - /** - * @depends testAddToCategory - */ - public function testRemoveFromCategory() { - $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - - // Is this "legal"? - $this->testAddToCategory(); - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($objids as $id) { - $this->assertTrue(in_array($id, $catmgr->idsForCategory('Family'))); - $catmgr->removeFromCategory($id, 'Family'); - $this->assertFalse(in_array($id, $catmgr->idsForCategory('Family'))); - } - - $this->assertEquals(1, count($catmgr->categories())); - $this->assertEquals(0, count($catmgr->idsForCategory('Family'))); - } - -} -- cgit v1.2.3 From 5ae4d675406b310df0940c8b9a43dcf556010e91 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 18 Sep 2013 11:06:00 +0200 Subject: in case the cache cannot be initialized within the autoloader we just shoul not use it --- lib/autoloader.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/autoloader.php b/lib/autoloader.php index 01841f831be..2c19350e904 100644 --- a/lib/autoloader.php +++ b/lib/autoloader.php @@ -117,7 +117,11 @@ class Autoloader { // Does this PHP have an in-memory cache? We cache the paths there if ($this->constructingMemoryCache && !$this->memoryCache) { $this->constructingMemoryCache = false; - $this->memoryCache = \OC\Memcache\Factory::createLowLatency('Autoloader'); + try { + $this->memoryCache = \OC\Memcache\Factory::createLowLatency('Autoloader'); + } catch(\Exception $ex) { + // no caching then - fine with me + } } if ($this->memoryCache) { $pathsToRequire = $this->memoryCache->get($class); -- cgit v1.2.3 From ce58c32c901fb874264922dabec1692f9d05123d Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 18 Sep 2013 11:07:19 +0200 Subject: using OC_Config::$object->setValue in order to get the underlying exception thrown up to the caller --- lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util.php b/lib/util.php index 41f5f1d16be..b9ff07a03fa 100755 --- a/lib/util.php +++ b/lib/util.php @@ -552,7 +552,7 @@ class OC_Util { if(is_null($id)) { // We need to guarantee at least one letter in instanceid so it can be used as the session_name $id = 'oc' . self::generateRandomBytes(10); - OC_Config::setValue('instanceid', $id); + OC_Config::$object->setValue('instanceid', $id); } return $id; } -- cgit v1.2.3 From d3f88ceeb49b9b86d32124163b0cea82567a4911 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 12:01:01 +0200 Subject: Add some docs to the sessions interface. --- lib/public/isession.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/public/isession.php b/lib/public/isession.php index 5f9ce32f3b1..0a77b0c823b 100644 --- a/lib/public/isession.php +++ b/lib/public/isession.php @@ -10,34 +10,46 @@ namespace OCP; +/** + * Interface ISession + * + * wrap PHP's internal session handling into the ISession interface + */ interface ISession { + /** + * Set a value in the session + * * @param string $key * @param mixed $value */ public function set($key, $value); /** + * Get a value from the session + * * @param string $key * @return mixed should return null if $key does not exist */ public function get($key); /** + * Check if a named key exists in the session + * * @param string $key * @return bool */ public function exists($key); /** - * should not throw any errors if $key does not exist + * Remove a $key/$value pair from the session * * @param string $key */ public function remove($key); /** - * removes all entries within the cache namespace + * Reset and recreate the session */ public function clear(); -- cgit v1.2.3 From 6ba23912a7c969ce24a3b295c55a60ea640ca690 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 12:34:10 +0200 Subject: Add getUserFolder/getAppFolder to Server. --- lib/public/iservercontainer.php | 14 ++++++++++++++ lib/server.php | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index ec7212b306e..89e71db8d17 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -62,6 +62,20 @@ interface IServerContainer { */ function getRootFolder(); + /** + * Returns a view to ownCloud's files folder + * + * @return \OCP\Files\Folder + */ + function getUserFolder(); + + /** + * Returns an app-specific view in ownClouds data directory + * + * @return \OCP\Files\Folder + */ + function getAppFolder(); + /** * Returns the current session * diff --git a/lib/server.php b/lib/server.php index 0eee3e0f73a..9525fce9fd7 100644 --- a/lib/server.php +++ b/lib/server.php @@ -56,6 +56,17 @@ class Server extends SimpleContainer implements IServerContainer { $view = new View(); return new Root($manager, $view, $user); }); + $this->registerService('CustomFolder', function($c) { + $dir = $c['CustomFolderPath']; + $root = $this->getRootFolder(); + $folder = null; + if(!$root->nodeExists($dir)) { + $folder = $root->newFolder($dir); + } else { + $folder = $root->get($dir); + } + return $folder; + }); } /** @@ -97,6 +108,30 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('RootFolder'); } + /** + * Returns a view to ownCloud's files folder + * + * @return \OCP\Files\Folder + */ + function getUserFolder() { + + $this->registerParameter('CustomFolderPath', '/files'); + return $this->query('CustomFolder'); + + } + + /** + * Returns an app-specific view in ownClouds data directory + * + * @return \OCP\Files\Folder + */ + function getAppFolder() { + + $this->registerParameter('CustomFolderPath', '/' . \OC_App::getCurrentApp()); + return $this->query('CustomFolder'); + + } + /** * Returns the current session * -- cgit v1.2.3 From 442a2e074cea694ce0d361b5433eb5473be438e6 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 12:35:46 +0200 Subject: Update to adhere to the coding guidelines. --- lib/server.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/server.php b/lib/server.php index 9525fce9fd7..6b1cb9c38d2 100644 --- a/lib/server.php +++ b/lib/server.php @@ -17,10 +17,10 @@ use OCP\IServerContainer; class Server extends SimpleContainer implements IServerContainer { function __construct() { - $this->registerService('ContactsManager', function($c){ + $this->registerService('ContactsManager', function($c) { return new ContactsManager(); }); - $this->registerService('Request', function($c){ + $this->registerService('Request', function($c) { $params = array(); // we json decode the body only in case of content type json @@ -45,10 +45,10 @@ class Server extends SimpleContainer implements IServerContainer { ) ); }); - $this->registerService('PreviewManager', function($c){ + $this->registerService('PreviewManager', function($c) { return new PreviewManager(); }); - $this->registerService('RootFolder', function($c){ + $this->registerService('RootFolder', function($c) { // TODO: get user and user manager from container as well $user = \OC_User::getUser(); $user = \OC_User::getManager()->get($user); @@ -83,8 +83,7 @@ class Server extends SimpleContainer implements IServerContainer { * * @return \OCP\IRequest|null */ - function getRequest() - { + function getRequest() { return $this->query('Request'); } @@ -93,8 +92,7 @@ class Server extends SimpleContainer implements IServerContainer { * * @return \OCP\IPreview */ - function getPreviewManager() - { + function getPreviewManager() { return $this->query('PreviewManager'); } @@ -103,8 +101,7 @@ class Server extends SimpleContainer implements IServerContainer { * * @return \OCP\Files\Folder */ - function getRootFolder() - { + function getRootFolder() { return $this->query('RootFolder'); } -- cgit v1.2.3 From 534933ee9bf6837fc75a389e4ed3aad4ffe1ab0f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 13:15:38 +0200 Subject: Use new emitter system --- lib/base.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/base.php b/lib/base.php index 520be11bc52..ce307b2bdd2 100644 --- a/lib/base.php +++ b/lib/base.php @@ -568,7 +568,9 @@ class OC { } catch (Exception $e) { } - OC_Hook::connect('OC_User', 'post_login', 'OC\Cache\File', 'loginListener'); + // NOTE: This will be replaced to use OCP + $userSession = \OC_User::getUserSession(); + $userSession->listen('postLogin', array('OC\Cache\File', 'loginListener')) } } -- cgit v1.2.3 From 2ef0b58ff6434254510c8be9c940126883022d76 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 14:25:12 +0200 Subject: Don't try to be clever --- lib/server.php | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/server.php b/lib/server.php index 6b1cb9c38d2..3454622425a 100644 --- a/lib/server.php +++ b/lib/server.php @@ -56,17 +56,6 @@ class Server extends SimpleContainer implements IServerContainer { $view = new View(); return new Root($manager, $view, $user); }); - $this->registerService('CustomFolder', function($c) { - $dir = $c['CustomFolderPath']; - $root = $this->getRootFolder(); - $folder = null; - if(!$root->nodeExists($dir)) { - $folder = $root->newFolder($dir); - } else { - $folder = $root->get($dir); - } - return $folder; - }); } /** @@ -112,8 +101,15 @@ class Server extends SimpleContainer implements IServerContainer { */ function getUserFolder() { - $this->registerParameter('CustomFolderPath', '/files'); - return $this->query('CustomFolder'); + $dir = '/files'; + $root = $this->getRootFolder(); + $folder = null; + if(!$root->nodeExists($dir)) { + $folder = $root->newFolder($dir); + } else { + $folder = $root->get($dir); + } + return $folder; } @@ -124,8 +120,15 @@ class Server extends SimpleContainer implements IServerContainer { */ function getAppFolder() { - $this->registerParameter('CustomFolderPath', '/' . \OC_App::getCurrentApp()); - return $this->query('CustomFolder'); + $dir = '/' . \OC_App::getCurrentApp(); + $root = $this->getRootFolder(); + $folder = null; + if(!$root->nodeExists($dir)) { + $folder = $root->newFolder($dir); + } else { + $folder = $root->get($dir); + } + return $folder; } -- cgit v1.2.3 From 79cd655920ae3346725539df2f443a66e51c5726 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 14:50:21 +0200 Subject: Note to self: Test before pushing!!! --- lib/base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base.php b/lib/base.php index ce307b2bdd2..fd31cfd9f29 100644 --- a/lib/base.php +++ b/lib/base.php @@ -570,7 +570,7 @@ class OC { } // NOTE: This will be replaced to use OCP $userSession = \OC_User::getUserSession(); - $userSession->listen('postLogin', array('OC\Cache\File', 'loginListener')) + $userSession->listen('postLogin', array('OC\Cache\File', 'loginListener')); } } -- cgit v1.2.3 From 09d043729a41a0e8966ed3bb81567ed1009a37b6 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 15:02:25 +0200 Subject: Note to self 2: Do as you preach. Test! --- lib/base.php | 2 +- lib/cache.php | 6 +++--- lib/cache/fileglobal.php | 2 +- lib/legacy/cache.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/base.php b/lib/base.php index fd31cfd9f29..0650361be91 100644 --- a/lib/base.php +++ b/lib/base.php @@ -570,7 +570,7 @@ class OC { } // NOTE: This will be replaced to use OCP $userSession = \OC_User::getUserSession(); - $userSession->listen('postLogin', array('OC\Cache\File', 'loginListener')); + $userSession->listen('postLogin', '\OC\Cache\File', 'loginListener'); } } diff --git a/lib/cache.php b/lib/cache.php index c99663a0ca5..a4fa8be710c 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -6,7 +6,7 @@ * See the COPYING-README file. */ -namespace OC\Cache; +namespace OC; class Cache { /** @@ -24,7 +24,7 @@ class Cache { */ static public function getGlobalCache() { if (!self::$global_cache) { - self::$global_cache = new FileGlobal(); + self::$global_cache = new Cache\FileGlobal(); } return self::$global_cache; } @@ -35,7 +35,7 @@ class Cache { */ static public function getUserCache() { if (!self::$user_cache) { - self::$user_cache = new File(); + self::$user_cache = new Cache\File(); } return self::$user_cache; } diff --git a/lib/cache/fileglobal.php b/lib/cache/fileglobal.php index 9ca17402933..bd049bba4d0 100644 --- a/lib/cache/fileglobal.php +++ b/lib/cache/fileglobal.php @@ -10,7 +10,7 @@ namespace OC\Cache; class FileGlobal { static protected function getCacheDir() { - $cache_dir = get_temp_dir().'/owncloud-'.OC_Util::getInstanceId().'/'; + $cache_dir = get_temp_dir().'/owncloud-' . \OC_Util::getInstanceId().'/'; if (!is_dir($cache_dir)) { mkdir($cache_dir); } diff --git a/lib/legacy/cache.php b/lib/legacy/cache.php index 83b214170f7..f915eb516b1 100644 --- a/lib/legacy/cache.php +++ b/lib/legacy/cache.php @@ -6,5 +6,5 @@ * See the COPYING-README file. */ -class Cache extends OC\Cache { +class OC_Cache extends \OC\Cache { } \ No newline at end of file -- cgit v1.2.3 From 1274d6116dc59a8238ad9d02d467260387fe2eac Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 18 Sep 2013 22:22:51 +0200 Subject: updating php docs --- lib/cache.php | 15 ++++++++++----- lib/cache/broker.php | 8 ++++++++ lib/cache/usercache.php | 4 ++-- lib/public/icache.php | 2 +- tests/lib/cache.php | 2 +- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/cache.php b/lib/cache.php index a4fa8be710c..a311f10a00f 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -10,17 +10,17 @@ namespace OC; class Cache { /** - * @var OC_Cache $user_cache + * @var Cache $user_cache */ static protected $user_cache; /** - * @var OC_Cache $global_cache + * @var Cache $global_cache */ static protected $global_cache; /** * get the global cache - * @return OC_Cache + * @return Cache */ static public function getGlobalCache() { if (!self::$global_cache) { @@ -31,7 +31,7 @@ class Cache { /** * get the user cache - * @return OC_Cache + * @return Cache */ static public function getUserCache() { if (!self::$user_cache) { @@ -87,7 +87,7 @@ class Cache { /** * clear the user cache of all entries starting with a prefix - * @param string prefix (optional) + * @param string $prefix (optional) * @return bool */ static public function clear($prefix='') { @@ -95,6 +95,11 @@ class Cache { return $user_cache->clear($prefix); } + /** + * creates cache key based on the files given + * @param $files + * @return string + */ static public function generateCacheKeyFromFiles($files) { $key = ''; sort($files); diff --git a/lib/cache/broker.php b/lib/cache/broker.php index b7f1b67a6d3..9b7e837e1bc 100644 --- a/lib/cache/broker.php +++ b/lib/cache/broker.php @@ -9,7 +9,15 @@ namespace OC\Cache; class Broker { + + /** + * @var \OC\Cache + */ protected $fast_cache; + + /** + * @var \OC\Cache + */ protected $slow_cache; public function __construct($fast_cache, $slow_cache) { diff --git a/lib/cache/usercache.php b/lib/cache/usercache.php index aac3b39af33..baa8820700b 100644 --- a/lib/cache/usercache.php +++ b/lib/cache/usercache.php @@ -13,7 +13,7 @@ namespace OC\Cache; class UserCache implements \OCP\ICache { /** - * @var OC\Cache\File $userCache + * @var \OC\Cache\File $userCache */ protected $userCache; @@ -68,7 +68,7 @@ class UserCache implements \OCP\ICache { /** * clear the user cache of all entries starting with a prefix - * @param string prefix (optional) + * @param string $prefix (optional) * @return bool */ public function clear($prefix = '') { diff --git a/lib/public/icache.php b/lib/public/icache.php index 202459f7c24..436ee71b2b9 100644 --- a/lib/public/icache.php +++ b/lib/public/icache.php @@ -48,7 +48,7 @@ interface ICache { /** * clear the user cache of all entries starting with a prefix - * @param string prefix (optional) + * @param string $prefix (optional) * @return bool */ public function clear($prefix = ''); diff --git a/tests/lib/cache.php b/tests/lib/cache.php index 3dcf39f7d60..8fefa25f65d 100644 --- a/tests/lib/cache.php +++ b/tests/lib/cache.php @@ -8,7 +8,7 @@ abstract class Test_Cache extends PHPUnit_Framework_TestCase { /** - * @var OC_Cache cache; + * @var \OC\Cache cache; */ protected $instance; -- cgit v1.2.3 From 76f8be3b7aadbb2c78f6c341ef8919973275efc8 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 18 Sep 2013 22:49:09 +0200 Subject: fixing namespaces and rename hasCategory to hasTag --- lib/tags.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/tags.php b/lib/tags.php index 4aafff8e1bb..3320d9ea1a8 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -113,7 +113,7 @@ class Tags implements \OCP\ITags { $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ?'; try { - $stmt = OCP\DB::prepare($sql); + $stmt = \OCP\DB::prepare($sql); $result = $stmt->execute(array($this->user, $this->type)); if (\OCP\DB::isError($result)) { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); @@ -191,7 +191,7 @@ class Tags implements \OCP\ITags { $stmt = \OCP\DB::prepare($sql); $result = $stmt->execute(array($tagId)); if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; } } catch(\Exception $e) { @@ -381,7 +381,7 @@ class Tags implements \OCP\ITags { . 'WHERE `uid` = ?'); $result = $stmt->execute(array($arguments['uid'])); if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); } } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), @@ -409,12 +409,12 @@ class Tags implements \OCP\ITags { $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` ' . 'WHERE `uid` = ?'); $result = $stmt->execute(array($arguments['uid'])); - if (OCP\DB::isError($result)) { + if (\OCP\DB::isError($result)) { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); } } catch(\Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); } } @@ -435,7 +435,7 @@ class Tags implements \OCP\ITags { $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; $query .= 'AND `type`= ?'; $updates[] = $this->type; - $stmt = OCP\DB::prepare($query); + $stmt = \OCP\DB::prepare($query); $result = $stmt->execute($updates); if (\OCP\DB::isError($result)) { \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); @@ -471,7 +471,7 @@ class Tags implements \OCP\ITags { * @return boolean */ public function addToFavorites($objid) { - if(!$this->hasCategory(self::TAG_FAVORITE)) { + if(!$this->hasTag(self::TAG_FAVORITE)) { $this->add(self::TAG_FAVORITE, true); } return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); @@ -574,7 +574,7 @@ class Tags implements \OCP\ITags { . '`uid` = ? AND `type` = ? AND `category` = ?'); $result = $stmt->execute(array($this->user, $this->type, $name)); if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); } } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' -- cgit v1.2.3 From 314ca843e81c2e26e83d58391e313503e0f30ebd Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 19 Sep 2013 11:27:13 +0200 Subject: Updated method names and added a few more tests. --- lib/public/itags.php | 6 +++--- lib/tags.php | 12 +++++------ tests/lib/tags.php | 59 ++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/lib/public/itags.php b/lib/public/itags.php index 047d4f5f40b..12643400548 100644 --- a/lib/public/itags.php +++ b/lib/public/itags.php @@ -65,7 +65,7 @@ interface ITags { * * @returns array */ - public function tags(); + public function getTags(); /** * Get the a list if items tagged with $tag. @@ -75,7 +75,7 @@ interface ITags { * @param string|integer $tag Tag id or name. * @return array An array of object ids or false on error. */ - public function idsForTag($tag); + public function getIdsForTag($tag); /** * Checks whether a tag is already saved. @@ -111,7 +111,7 @@ interface ITags { * @param int|null $id int Optional object id to add to this|these tag(s) * @return bool Returns false on error. */ - public function addMulti($names, $sync=false, $id = null); + public function addMultiple($names, $sync=false, $id = null); /** * Delete tag/object relations from the db diff --git a/lib/tags.php b/lib/tags.php index 3320d9ea1a8..2eaa603c1a3 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -96,7 +96,7 @@ class Tags implements \OCP\ITags { } if(count($defaultTags) > 0 && count($this->tags) === 0) { - $this->addMulti($defaultTags, true); + $this->addMultiple($defaultTags, true); } \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), \OCP\Util::DEBUG); @@ -119,7 +119,7 @@ class Tags implements \OCP\ITags { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; } - return ($result->numRows() === 0); + return ((int)$result->numRows() === 0); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR); @@ -138,7 +138,7 @@ class Tags implements \OCP\ITags { * * @return array */ - public function tags() { + public function getTags() { if(!count($this->tags)) { return array(); } @@ -167,7 +167,7 @@ class Tags implements \OCP\ITags { * @param string|integer $tag Tag id or name. * @return array An array of object ids or false on error. */ - public function idsForTag($tag) { + public function getIdsForTag($tag) { $result = null; if(is_numeric($tag)) { $tagId = $tag; @@ -293,7 +293,7 @@ class Tags implements \OCP\ITags { * @param int|null $id int Optional object id to add to this|these tag(s) * @return bool Returns false on error. */ - public function addMulti($names, $sync=false, $id = null) { + public function addMultiple($names, $sync=false, $id = null) { if(!is_array($names)) { $names = array($names); } @@ -456,7 +456,7 @@ class Tags implements \OCP\ITags { */ public function getFavorites() { try { - return $this->idsForTag(self::TAG_FAVORITE); + return $this->getIdsForTag(self::TAG_FAVORITE); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR); diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 06baebc0af7..16a03f5645a 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -48,7 +48,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr = new OC\Tags($this->user); $tagMgr->loadTagsFor($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); } public function testAddTags() { @@ -65,7 +65,37 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertFalse($tagMgr->add('Family')); $this->assertFalse($tagMgr->add('fAMILY')); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); + } + + public function testAddMultiple() { + $tags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($tags as $tag) { + $this->assertFalse($tagMgr->hasTag($tag)); + } + + $result = $tagMgr->addMultiple($tags); + $this->assertTrue((bool)$result); + + foreach($tags as $tag) { + $this->assertTrue($tagMgr->hasTag($tag)); + } + + $this->assertEquals(4, count($tagMgr->getTags())); + } + + public function testIsEmpty() { + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + $this->assertEquals(0, count($tagMgr->getTags())); + $this->assertTrue($tagMgr->isEmpty()); + $tagMgr->add('Tag'); + $this->assertFalse($tagMgr->isEmpty()); } public function testdeleteTags() { @@ -73,13 +103,13 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr = new OC\Tags($this->user); $tagMgr->loadTagsFor($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); $tagMgr->delete('family'); - $this->assertEquals(3, count($tagMgr->tags())); + $this->assertEquals(3, count($tagMgr->getTags())); $tagMgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($tagMgr->tags())); + $this->assertEquals(0, count($tagMgr->getTags())); } @@ -105,8 +135,8 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr->tagAs($id, 'Family'); } - $this->assertEquals(1, count($tagMgr->tags())); - $this->assertEquals(9, count($tagMgr->idsForTag('Family'))); + $this->assertEquals(1, count($tagMgr->getTags())); + $this->assertEquals(9, count($tagMgr->getIdsForTag('Family'))); } /** @@ -121,13 +151,20 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr->loadTagsFor($this->objectType); foreach($objIds as $id) { - $this->assertTrue(in_array($id, $tagMgr->idsForTag('Family'))); + $this->assertTrue(in_array($id, $tagMgr->getIdsForTag('Family'))); $tagMgr->unTag($id, 'Family'); - $this->assertFalse(in_array($id, $tagMgr->idsForTag('Family'))); + $this->assertFalse(in_array($id, $tagMgr->getIdsForTag('Family'))); } - $this->assertEquals(1, count($tagMgr->tags())); - $this->assertEquals(0, count($tagMgr->idsForTag('Family'))); + $this->assertEquals(1, count($tagMgr->getTags())); + $this->assertEquals(0, count($tagMgr->getIdsForTag('Family'))); + } + + public function testFavorite() { + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + $this->assertTrue($tagMgr->addToFavorites(1)); + $this->assertTrue($tagMgr->removeFromFavorites(1)); } } -- cgit v1.2.3 From 9e4d13858c92e3b42e99152cee7b899a7ddb926b Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 19 Sep 2013 13:27:41 +0200 Subject: Fix syntax error --- lib/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server.php b/lib/server.php index 5c386593f1d..4f5bcfbe676 100644 --- a/lib/server.php +++ b/lib/server.php @@ -113,7 +113,6 @@ class Server extends SimpleContainer implements IServerContainer { $folder = $root->get($dir); } return $folder; - } /** @@ -132,6 +131,7 @@ class Server extends SimpleContainer implements IServerContainer { $folder = $root->get($dir); } return $folder; + } /** * Returns an ICache instance -- cgit v1.2.3 From de81210bec4b08034e130cd5db4a426fe2f7820e Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 19 Sep 2013 13:55:45 +0200 Subject: Add another test. --- tests/lib/tags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 16a03f5645a..92a96a14772 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -94,7 +94,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertEquals(0, count($tagMgr->getTags())); $this->assertTrue($tagMgr->isEmpty()); - $tagMgr->add('Tag'); + $this->assertNotEquals(false, $tagMgr->add('Tag')); $this->assertFalse($tagMgr->isEmpty()); } -- cgit v1.2.3 From e8bf576184fdafbe74f3394dc253a56c07be6507 Mon Sep 17 00:00:00 2001 From: Jörn Friedrich Dreyer Date: Fri, 26 Jul 2013 14:11:59 +0200 Subject: add initial search in shared files --- apps/files_sharing/lib/cache.php | 26 +++++++++++++++++++++++++- lib/public/share.php | 2 +- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 33cd1428899..28e3cbdb2e1 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -226,7 +226,31 @@ class Shared_Cache extends Cache { * @return array of file data */ public function search($pattern) { - // TODO + + // normalize pattern + $pattern = $this->normalize($pattern); + + $ids = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL); + foreach ($ids as $file) { + $folderBackend = \OCP\Share::getBackend('folder'); + $children = $folderBackend->getChildren($file); + foreach ($children as $child) { + $ids[] = (int)$child['source']; + } + + } + $placeholders = join(',', array_fill(0, count($ids), '?')); + + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` + FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `fileid` IN (' . $placeholders . ')'; + $result = \OC_DB::executeAudited($sql, array_merge(array($pattern), $ids)); + $files = array(); + while ($row = $result->fetchRow()) { + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } + return $files; } /** diff --git a/lib/public/share.php b/lib/public/share.php index 9ab956d84b9..10922965ea8 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -748,7 +748,7 @@ class Share { * @param string Item type * @return Sharing backend object */ - private static function getBackend($itemType) { + public static function getBackend($itemType) { if (isset(self::$backends[$itemType])) { return self::$backends[$itemType]; } else if (isset(self::$backendTypes[$itemType]['class'])) { -- cgit v1.2.3 From 27511d9187a5ffd4d5a087602a9c648e9ec1c06e Mon Sep 17 00:00:00 2001 From: Jörn Friedrich Dreyer Date: Wed, 31 Jul 2013 15:13:00 +0200 Subject: divide ids into chunks of 1k --- apps/files_sharing/lib/cache.php | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 28e3cbdb2e1..6386f1d2c60 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -239,16 +239,25 @@ class Shared_Cache extends Cache { } } - $placeholders = join(',', array_fill(0, count($ids), '?')); - - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` - FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `fileid` IN (' . $placeholders . ')'; - $result = \OC_DB::executeAudited($sql, array_merge(array($pattern), $ids)); + $files = array(); - while ($row = $result->fetchRow()) { - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); - $files[] = $row; + + // divide into 1k chunks + $chunks = array_chunk($ids, 1000); + + foreach ($chunks as $chunk) { + $placeholders = join(',', array_fill(0, count($chunk), '?')); + + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` + FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `fileid` IN (' . $placeholders . ')'; + + $result = \OC_DB::executeAudited($sql, array_merge(array($pattern), $chunk)); + + while ($row = $result->fetchRow()) { + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } } return $files; } -- cgit v1.2.3 From 392c6b6832edfc37a2956ef3a77fab6020a7a746 Mon Sep 17 00:00:00 2001 From: Jörn Friedrich Dreyer Date: Wed, 7 Aug 2013 18:18:40 +0200 Subject: return fixed path, skip shared files outside of 'files' --- apps/files_sharing/lib/cache.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 6386f1d2c60..a4402464481 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -254,9 +254,12 @@ class Shared_Cache extends Cache { $result = \OC_DB::executeAudited($sql, array_merge(array($pattern), $chunk)); while ($row = $result->fetchRow()) { - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); - $files[] = $row; + if (substr($row['path'], 0, 6)==='files/') { + $row['path'] = substr($row['path'],6); // remove 'files/' from path as it's relative to '/Shared' + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } // else skip results out of the files folder } } return $files; -- cgit v1.2.3 From 466fd8acda010ad330930055925ce26ede1fbf06 Mon Sep 17 00:00:00 2001 From: Jörn Friedrich Dreyer Date: Wed, 28 Aug 2013 12:39:43 +0200 Subject: fix getAll(), refactor search by mime & search --- apps/files_sharing/lib/cache.php | 55 +++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index a4402464481..82588df42d2 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -230,15 +230,7 @@ class Shared_Cache extends Cache { // normalize pattern $pattern = $this->normalize($pattern); - $ids = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL); - foreach ($ids as $file) { - $folderBackend = \OCP\Share::getBackend('folder'); - $children = $folderBackend->getChildren($file); - foreach ($children as $child) { - $ids[] = (int)$child['source']; - } - - } + $ids = $this->getAll(); $files = array(); @@ -248,7 +240,8 @@ class Shared_Cache extends Cache { foreach ($chunks as $chunk) { $placeholders = join(',', array_fill(0, count($chunk), '?')); - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, + `encrypted`, `unencrypted_size`, `etag` FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `fileid` IN (' . $placeholders . ')'; $result = \OC_DB::executeAudited($sql, array_merge(array($pattern), $chunk)); @@ -280,13 +273,30 @@ class Shared_Cache extends Cache { } $mimetype = $this->getMimetypeId($mimetype); $ids = $this->getAll(); - $placeholders = join(',', array_fill(0, count($ids), '?')); - $query = \OC_DB::prepare(' - SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted` - FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `fileid` IN (' . $placeholders . ')' - ); - $result = $query->execute(array_merge(array($mimetype), $ids)); - return $result->fetchAll(); + + $files = array(); + + // divide into 1k chunks + $chunks = array_chunk($ids, 1000); + + foreach ($chunks as $chunk) { + $placeholders = join(',', array_fill(0, count($ids), '?')); + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, + `encrypted`, `unencrypted_size`, `etag` + FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `fileid` IN (' . $placeholders . ')'; + + $result = \OC_DB::executeAudited($sql, array_merge(array($mimetype), $chunk)); + + while ($row = $result->fetchRow()) { + if (substr($row['path'], 0, 6)==='files/') { + $row['path'] = substr($row['path'],6); // remove 'files/' from path as it's relative to '/Shared' + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } // else skip results out of the files folder + } + } + return $files; } /** @@ -308,7 +318,16 @@ class Shared_Cache extends Cache { * @return int[] */ public function getAll() { - return \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL); + $ids = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL); + $folderBackend = \OCP\Share::getBackend('folder'); + foreach ($ids as $file) { + $children = $folderBackend->getChildren($file); + foreach ($children as $child) { + $ids[] = (int)$child['source']; + } + + } + return $ids; } /** -- cgit v1.2.3 From 3b4020e81131cd526a6bbffe14bc14f1cac4fd60 Mon Sep 17 00:00:00 2001 From: Jörn Friedrich Dreyer Date: Wed, 28 Aug 2013 21:04:21 +0200 Subject: add all results, sharing cache also returns entries for shared files in external storages --- apps/files_sharing/lib/cache.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 82588df42d2..acb064f31aa 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -249,10 +249,10 @@ class Shared_Cache extends Cache { while ($row = $result->fetchRow()) { if (substr($row['path'], 0, 6)==='files/') { $row['path'] = substr($row['path'],6); // remove 'files/' from path as it's relative to '/Shared' - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); - $files[] = $row; - } // else skip results out of the files folder + } + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; } } return $files; -- cgit v1.2.3 From 6aeb0a99daf28ecb68b010d96369636a99ad77be Mon Sep 17 00:00:00 2001 From: Jörn Friedrich Dreyer Date: Wed, 28 Aug 2013 21:10:06 +0200 Subject: same for search by mime --- apps/files_sharing/lib/cache.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index acb064f31aa..51e8713b97a 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -290,10 +290,10 @@ class Shared_Cache extends Cache { while ($row = $result->fetchRow()) { if (substr($row['path'], 0, 6)==='files/') { $row['path'] = substr($row['path'],6); // remove 'files/' from path as it's relative to '/Shared' - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); - $files[] = $row; - } // else skip results out of the files folder + } + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; } } return $files; -- cgit v1.2.3 From ac73ce1b2a9cbcafce29d9f6be768b0629f68ddb Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 20 Sep 2013 12:45:56 +0200 Subject: Add UserSession to server container --- lib/public/iservercontainer.php | 7 ++++++ lib/public/iusersession.php | 30 ++++++++++++++++++++++ lib/server.php | 55 +++++++++++++++++++++++++++++++++++++++++ lib/user.php | 43 ++------------------------------ 4 files changed, 94 insertions(+), 41 deletions(-) create mode 100644 lib/public/iusersession.php diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 1725b7c74e0..ad714276660 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -62,6 +62,13 @@ interface IServerContainer { */ function getRootFolder(); + /** + * Returns the user session + * + * @return \OCP\IUserSession + */ + function getUserSession(); + /** * Returns an ICache instance * diff --git a/lib/public/iusersession.php b/lib/public/iusersession.php new file mode 100644 index 00000000000..5dc1ecf71e6 --- /dev/null +++ b/lib/public/iusersession.php @@ -0,0 +1,30 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OCP; + +/** + * User session + */ +interface IUserSession { + /** + * Do a user login + * @param string $user the username + * @param string $password the password + * @return bool true if successful + */ + public function login($user, $password); + + /** + * @brief Logs the user out including all the session data + * Logout, destroys session + */ + public function logout(); + +} diff --git a/lib/server.php b/lib/server.php index f4dc22a2be4..316ed39665b 100644 --- a/lib/server.php +++ b/lib/server.php @@ -56,6 +56,47 @@ class Server extends SimpleContainer implements IServerContainer { $view = new View(); return new Root($manager, $view, $user); }); + $this->registerService('UserManager', function($c) { + return new \OC\User\Manager(); + }); + $this->registerService('UserSession', function($c) { + $manager = $c->query('UserManager'); + $userSession = new \OC\User\Session($manager, \OC::$session); + $userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) { + \OC_Hook::emit('OC_User', 'pre_createUser', array('run' => true, 'uid' => $uid, 'password' => $password)); + }); + $userSession->listen('\OC\User', 'postCreateUser', function ($user, $password) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_createUser', array('uid' => $user->getUID(), 'password' => $password)); + }); + $userSession->listen('\OC\User', 'preDelete', function ($user) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'pre_deleteUser', array('run' => true, 'uid' => $user->getUID())); + }); + $userSession->listen('\OC\User', 'postDelete', function ($user) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_deleteUser', array('uid' => $user->getUID())); + }); + $userSession->listen('\OC\User', 'preSetPassword', function ($user, $password, $recoveryPassword) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'pre_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); + }); + $userSession->listen('\OC\User', 'postSetPassword', function ($user, $password, $recoveryPassword) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); + }); + $userSession->listen('\OC\User', 'preLogin', function ($uid, $password) { + \OC_Hook::emit('OC_User', 'pre_login', array('run' => true, 'uid' => $uid, 'password' => $password)); + }); + $userSession->listen('\OC\User', 'postLogin', function ($user, $password) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_login', array('run' => true, 'uid' => $user->getUID(), 'password' => $password)); + }); + $userSession->listen('\OC\User', 'logout', function () { + \OC_Hook::emit('OC_User', 'logout', array()); + }); + return $userSession; + }); $this->registerService('UserCache', function($c) { return new UserCache(); }); @@ -97,6 +138,20 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('RootFolder'); } + /** + * @return \OC\User\Manager + */ + function getUserManager() { + return $this->query('UserManager'); + } + + /** + * @return \OC\User\Session + */ + function getUserSession() { + return $this->query('UserSession'); + } + /** * Returns an ICache instance * diff --git a/lib/user.php b/lib/user.php index 0f6f40aec9a..7f6a296c3ea 100644 --- a/lib/user.php +++ b/lib/user.php @@ -37,54 +37,15 @@ * logout() */ class OC_User { - public static $userSession = null; - public static function getUserSession() { - if (!self::$userSession) { - $manager = new \OC\User\Manager(); - self::$userSession = new \OC\User\Session($manager, \OC::$session); - self::$userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) { - \OC_Hook::emit('OC_User', 'pre_createUser', array('run' => true, 'uid' => $uid, 'password' => $password)); - }); - self::$userSession->listen('\OC\User', 'postCreateUser', function ($user, $password) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'post_createUser', array('uid' => $user->getUID(), 'password' => $password)); - }); - self::$userSession->listen('\OC\User', 'preDelete', function ($user) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'pre_deleteUser', array('run' => true, 'uid' => $user->getUID())); - }); - self::$userSession->listen('\OC\User', 'postDelete', function ($user) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'post_deleteUser', array('uid' => $user->getUID())); - }); - self::$userSession->listen('\OC\User', 'preSetPassword', function ($user, $password, $recoveryPassword) { - /** @var $user \OC\User\User */ - OC_Hook::emit('OC_User', 'pre_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); - }); - self::$userSession->listen('\OC\User', 'postSetPassword', function ($user, $password, $recoveryPassword) { - /** @var $user \OC\User\User */ - OC_Hook::emit('OC_User', 'post_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); - }); - self::$userSession->listen('\OC\User', 'preLogin', function ($uid, $password) { - \OC_Hook::emit('OC_User', 'pre_login', array('run' => true, 'uid' => $uid, 'password' => $password)); - }); - self::$userSession->listen('\OC\User', 'postLogin', function ($user, $password) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'post_login', array('run' => true, 'uid' => $user->getUID(), 'password' => $password)); - }); - self::$userSession->listen('\OC\User', 'logout', function () { - \OC_Hook::emit('OC_User', 'logout', array()); - }); - } - return self::$userSession; + return OC::$server->getUserSession(); } /** * @return \OC\User\Manager */ public static function getManager() { - return self::getUserSession()->getManager(); + return OC::$server->getUserManager(); } private static $_backends = array(); -- cgit v1.2.3 From aa8a85f77d0c6705ee727d182e95d288ba7b7917 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 20 Sep 2013 14:33:45 +0200 Subject: Add DBConnection to server container --- lib/db/connection.php | 2 +- lib/public/idbconnection.php | 71 +++++++++++++++++++++++++++++++++++++++++ lib/public/iservercontainer.php | 7 ++++ lib/server.php | 8 +++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 lib/public/idbconnection.php diff --git a/lib/db/connection.php b/lib/db/connection.php index 2581969dbd0..2d3193a148a 100644 --- a/lib/db/connection.php +++ b/lib/db/connection.php @@ -12,7 +12,7 @@ use Doctrine\DBAL\Configuration; use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\Common\EventManager; -class Connection extends \Doctrine\DBAL\Connection { +class Connection extends \Doctrine\DBAL\Connection implements \OCP\IDBConnection { /** * @var string $tablePrefix */ diff --git a/lib/public/idbconnection.php b/lib/public/idbconnection.php new file mode 100644 index 00000000000..67dd7ccfc37 --- /dev/null +++ b/lib/public/idbconnection.php @@ -0,0 +1,71 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OCP; + +/** + * TODO: Description + */ +interface IDBConnection { + /** + * Used to abstract the owncloud database access away + * @param string $sql the sql query with ? placeholder for params + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @return \Doctrine\DBAL\Driver\Statement The prepared statement. + */ + public function prepare($sql, $limit=null, $offset=null); + + /** + * Used to get the id of the just inserted element + * @param string $tableName the name of the table where we inserted the item + * @return int the id of the inserted element + */ + public function lastInsertId($table = null); + + /** + * @brief Insert a row if a matching row doesn't exists. + * @param $table string The table name (will replace *PREFIX*) to perform the replace on. + * @param $input array + * + * The input array if in the form: + * + * array ( 'id' => array ( 'value' => 6, + * 'key' => true + * ), + * 'name' => array ('value' => 'Stoyan'), + * 'family' => array ('value' => 'Stefanov'), + * 'birth_date' => array ('value' => '1975-06-20') + * ); + * @return bool + * + */ + public function insertIfNotExist($table, $input); + + /** + * @brief Start a transaction + */ + public function beginTransaction(); + + /** + * @brief Commit the database changes done during a transaction that is in progress + */ + public function commit(); + + /** + * @brief Rollback the database changes done during a transaction that is in progress + */ + public function rollBack(); + + /** + * returns the error code and message as a string for logging + * @return string + */ + public function getError(); +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index ad714276660..5481cd6ce6a 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -83,4 +83,11 @@ interface IServerContainer { */ function getSession(); + /** + * Returns the current session + * + * @return \OCP\IDBConnection + */ + function getDatabaseConnection(); + } diff --git a/lib/server.php b/lib/server.php index 316ed39665b..a5288fa1482 100644 --- a/lib/server.php +++ b/lib/server.php @@ -170,4 +170,12 @@ class Server extends SimpleContainer implements IServerContainer { return \OC::$session; } + /** + * Returns the current session + * + * @return \OCP\IDBConnection + */ + function getDatabaseConnection() { + return \OC_DB::getConnection(); + } } -- cgit v1.2.3 From e3013c580108e6b0cc332ba14976f3ffb4b7b274 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 20 Sep 2013 17:34:33 +0200 Subject: Add Navigation class to server container --- lib/app.php | 31 ++++++++----------- lib/navigationmanager.php | 63 +++++++++++++++++++++++++++++++++++++++ lib/public/inavigationmanager.php | 27 +++++++++++++++++ lib/public/iservercontainer.php | 5 ++++ lib/server.php | 10 +++++++ 5 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 lib/navigationmanager.php create mode 100644 lib/public/inavigationmanager.php diff --git a/lib/app.php b/lib/app.php index d98af2dc296..0ab1ee57f63 100644 --- a/lib/app.php +++ b/lib/app.php @@ -27,8 +27,6 @@ * upgrading and removing apps. */ class OC_App{ - static private $activeapp = ''; - static private $navigation = array(); static private $settingsForms = array(); static private $adminForms = array(); static private $personalForms = array(); @@ -271,7 +269,7 @@ class OC_App{ /** * @brief adds an entry to the navigation - * @param string $data array containing the data + * @param array $data array containing the data * @return bool * * This function adds a new entry to the navigation visible to users. $data @@ -287,11 +285,7 @@ class OC_App{ * the navigation. Lower values come first. */ public static function addNavigationEntry( $data ) { - $data['active']=false; - if(!isset($data['icon'])) { - $data['icon']=''; - } - OC_App::$navigation[] = $data; + OC::$server->getNavigationManager()->add($data); return true; } @@ -305,9 +299,7 @@ class OC_App{ * highlighting the current position of the user. */ public static function setActiveNavigationEntry( $id ) { - // load all the apps, to make sure we have all the navigation entries - self::loadApps(); - self::$activeapp = $id; + OC::$server->getNavigationManager()->setActiveEntry($id); return true; } @@ -315,15 +307,14 @@ class OC_App{ * @brief Get the navigation entries for the $app * @param string $app app * @return array of the $data added with addNavigationEntry + * + * Warning: destroys the existing entries */ public static function getAppNavigationEntries($app) { if(is_file(self::getAppPath($app).'/appinfo/app.php')) { - $save = self::$navigation; - self::$navigation = array(); + OC::$server->getNavigationManager()->clear(); require $app.'/appinfo/app.php'; - $app_entries = self::$navigation; - self::$navigation = $save; - return $app_entries; + return OC::$server->getNavigationManager()->getAll(); } return array(); } @@ -336,7 +327,7 @@ class OC_App{ * setActiveNavigationEntry */ public static function getActiveNavigationEntry() { - return self::$activeapp; + return OC::$server->getNavigationManager()->getActiveEntry(); } /** @@ -419,8 +410,9 @@ class OC_App{ // This is private as well. It simply works, so don't ask for more details private static function proceedNavigation( $list ) { + $activeapp = OC::$server->getNavigationManager()->getActiveEntry(); foreach( $list as &$naventry ) { - if( $naventry['id'] == self::$activeapp ) { + if( $naventry['id'] == $activeapp ) { $naventry['active'] = true; } else{ @@ -572,7 +564,8 @@ class OC_App{ * - active: boolean, signals if the user is on this navigation entry */ public static function getNavigation() { - $navigation = self::proceedNavigation( self::$navigation ); + $entries = OC::$server->getNavigationManager()->getAll(); + $navigation = self::proceedNavigation( $entries ); return $navigation; } diff --git a/lib/navigationmanager.php b/lib/navigationmanager.php new file mode 100644 index 00000000000..f032afd1fc4 --- /dev/null +++ b/lib/navigationmanager.php @@ -0,0 +1,63 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OC; + +/** + * Manages the owncloud navigation + */ +class NavigationManager { + protected $entries = array(); + + /** + * Creates a new navigation entry + * @param array $entry containing: id, name, order, icon and href key + */ + public function add(array $entry) { + $entry['active'] = false; + if(!isset($entry['icon'])) { + $entry['icon'] = ''; + } + $this->entries[] = $entry; + } + + /** + * @brief returns all the added Menu entries + * @return array of the added entries + */ + public function getAll() { + return $this->entries; + } + + /** + * @brief removes all the entries + */ + public function clear() { + $this->entries = array(); + } + + /** + * Sets the current navigation entry of the currently running app + * @param string $id of the app entry to activate (from added $entry) + */ + public function setActiveEntry($id) { + $this->activeEntry = $id; + } + + /** + * @brief gets the active Menu entry + * @return string id or empty string + * + * This function returns the id of the active navigation entry (set by + * setActiveEntry + */ + public function getActiveEntry() { + return $this->activeEntry; + } +} diff --git a/lib/public/inavigationmanager.php b/lib/public/inavigationmanager.php new file mode 100644 index 00000000000..21744dd1c21 --- /dev/null +++ b/lib/public/inavigationmanager.php @@ -0,0 +1,27 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OCP; + +/** + * Manages the owncloud navigation + */ +interface INavigationManager { + /** + * Creates a new navigation entry + * @param array $entry containing: id, name, order, icon and href key + */ + public function add(array $entry); + + /** + * Sets the current navigation entry of the currently running app + * @param string $appId id of the app entry to activate (from added $entry) + */ + public function setActiveEntry($appId); +} \ No newline at end of file diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 5481cd6ce6a..ebcc0fe4cd4 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -69,6 +69,11 @@ interface IServerContainer { */ function getUserSession(); + /** + * @return \OCP\INavigationManager + */ + function getNavigationManager(); + /** * Returns an ICache instance * diff --git a/lib/server.php b/lib/server.php index a5288fa1482..13bda2dc30d 100644 --- a/lib/server.php +++ b/lib/server.php @@ -97,6 +97,9 @@ class Server extends SimpleContainer implements IServerContainer { }); return $userSession; }); + $this->registerService('NavigationManager', function($c) { + return new \OC\NavigationManager(); + }); $this->registerService('UserCache', function($c) { return new UserCache(); }); @@ -152,6 +155,13 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('UserSession'); } + /** + * @return \OC\NavigationManager + */ + function getNavigationManager() { + return $this->query('NavigationManager'); + } + /** * Returns an ICache instance * -- cgit v1.2.3 From e92abfd4d8dfb9dbb42ccfc0c23193b1ddde3bbf Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 20 Sep 2013 20:21:24 +0200 Subject: Add Config container class to server container --- lib/allconfig.php | 78 +++++++++++++++++++++++++++++++++++++++++ lib/public/iconfig.php | 59 +++++++++++++++++++++++++++++++ lib/public/iservercontainer.php | 5 +++ lib/server.php | 9 +++++ 4 files changed, 151 insertions(+) create mode 100644 lib/allconfig.php create mode 100644 lib/public/iconfig.php diff --git a/lib/allconfig.php b/lib/allconfig.php new file mode 100644 index 00000000000..81c8892348b --- /dev/null +++ b/lib/allconfig.php @@ -0,0 +1,78 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OC; + +/** + * Class to combine all the configuration options ownCloud offers + */ +class AllConfig implements \OCP\IConfig { + /** + * Sets a new systemwide value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + * @todo need a use case for this + */ +// public function setSystemValue($key, $value) { +// \OCP\Config::setSystemValue($key, $value); +// } + + /** + * Looks up a systemwide defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getSystemValue($key) { + return \OCP\Config::getSystemValue($key, ''); + } + + + /** + * Writes a new appwide value + * @param string $appName the appName that we want to store the value under + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + */ + public function setAppValue($appName, $key, $value) { + \OCP\Config::setAppValue($appName, $key, $value); + } + + /** + * Looks up an appwide defined value + * @param string $appName the appName that we stored the value under + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getAppValue($appName, $key) { + return \OCP\Config::getAppValue($appName, $key, ''); + } + + + /** + * Set a user defined value + * @param string $userId the userId of the user that we want to store the value under + * @param string $appName the appName that we want to store the value under + * @param string $key the key under which the value is being stored + * @param string $value the value that you want to store + */ + public function setUserValue($userId, $appName, $key, $value) { + \OCP\Config::setUserValue($userId, $appName, $key, $value); + } + + + /** + * Shortcut for getting a user defined value + * @param string $userId the userId of the user that we want to store the value under + * @param string $appName the appName that we stored the value under + * @param string $key the key under which the value is being stored + */ + public function getUserValue($userId, $appName, $key){ + return \OCP\Config::getUserValue($userId, $appName, $key); + } +} diff --git a/lib/public/iconfig.php b/lib/public/iconfig.php new file mode 100644 index 00000000000..0c150ec351a --- /dev/null +++ b/lib/public/iconfig.php @@ -0,0 +1,59 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ +namespace OCP; + +/** + * Access to all the configuration options ownCloud offers + */ +interface IConfig { + /** + * Sets a new systemwide value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + * @todo need a use case for this + */ +// public function setSystemValue($key, $value); + + /** + * Looks up a systemwide defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getSystemValue($key); + + + /** + * Writes a new appwide value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + */ + public function setAppValue($key, $value, $appName=null); + + /** + * Looks up an appwide defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getAppValue($key, $appName=null); + + + /** + * Shortcut for setting a user defined value + * @param string $key the key under which the value is being stored + * @param string $value the value that you want to store + * @param string $userId the userId of the user that we want to store the value under, defaults to the current one + */ + public function setUserValue($key, $value, $userId=null); + + /** + * Shortcut for getting a user defined value + * @param string $key the key under which the value is being stored + * @param string $userId the userId of the user that we want to store the value under, defaults to the current one + */ + public function getUserValue($key, $userId=null); +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index ebcc0fe4cd4..4478a4e8a6c 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -74,6 +74,11 @@ interface IServerContainer { */ function getNavigationManager(); + /** + * @return \OCP\IConfig + */ + function getConfig(); + /** * Returns an ICache instance * diff --git a/lib/server.php b/lib/server.php index 13bda2dc30d..57e7f4ab4f1 100644 --- a/lib/server.php +++ b/lib/server.php @@ -100,6 +100,9 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('NavigationManager', function($c) { return new \OC\NavigationManager(); }); + $this->registerService('AllConfig', function($c) { + return new \OC\AllConfig(); + }); $this->registerService('UserCache', function($c) { return new UserCache(); }); @@ -162,6 +165,12 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('NavigationManager'); } + /** + * @return \OC\Config + */ + function getConfig() { + return $this->query('AllConfig'); + } /** * Returns an ICache instance * -- cgit v1.2.3 From 45a7b0dbac307df9ea38a914fd3f1cfb9202a994 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 20 Sep 2013 20:29:15 +0200 Subject: Fix the apps enabling/disabling in settings --- settings/js/apps.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/settings/js/apps.js b/settings/js/apps.js index 54810776d2b..a55c55e24cf 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -84,6 +84,7 @@ OC.Settings.Apps = OC.Settings.Apps || { } else { appitem.data('active',false); + element.data('active',false); OC.Settings.Apps.removeNavigation(appid); appitem.removeClass('active'); element.val(t('settings','Enable')); @@ -104,6 +105,7 @@ OC.Settings.Apps = OC.Settings.Apps || { } else { OC.Settings.Apps.addNavigation(appid); appitem.data('active',true); + element.data('active',true); appitem.addClass('active'); element.val(t('settings','Disable')); } @@ -158,7 +160,7 @@ OC.Settings.Apps = OC.Settings.Apps || { if(response.status === 'success'){ var navIds=response.nav_ids; for(var i=0; i< navIds.length; i++){ - $('#apps').children('li[data-id="'+navIds[i]+'"]').remove(); + $('#apps .wrapper').children('li[data-id="'+navIds[i]+'"]').remove(); } } }); -- cgit v1.2.3 From d84d548618651c0a66bd2696d6547b33ca6b8e87 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 20 Sep 2013 20:34:17 +0200 Subject: when storing back the data field 'encrypted' it is necessary to cast the boolean to an integer to make pg happy --- lib/files/cache/scanner.php | 2 ++ tests/lib/files/cache/scanner.php | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index fdbce0d51fe..d296c606865 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -121,6 +121,8 @@ class Scanner extends BasicEmitter { } $parentCacheData = $this->cache->get($parent); $parentCacheData['etag'] = $this->storage->getETag($parent); + // the boolean to int conversion is necessary to make pg happy + $parentCacheData['encrypted'] = $parentCacheData['encrypted'] ? 1 : 0; $this->cache->put($parent, $parentCacheData); } } diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php index b137799bbcf..8112eada17c 100644 --- a/tests/lib/files/cache/scanner.php +++ b/tests/lib/files/cache/scanner.php @@ -195,6 +195,7 @@ class Scanner extends \PHPUnit_Framework_TestCase { $data1 = $this->cache->get('folder'); $data2 = $this->cache->get(''); $data0['etag'] = ''; + $data0['encrypted'] = $data0['encrypted'] ? 1: 0; $this->cache->put('folder/bar.txt', $data0); // rescan -- cgit v1.2.3 From 9116303cfc5259f05ec348809bfbc8757d4657cb Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 20 Sep 2013 21:40:54 +0200 Subject: fixing typos --- lib/allconfig.php | 8 ++++---- lib/public/iconfig.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/allconfig.php b/lib/allconfig.php index 81c8892348b..353608e5d21 100644 --- a/lib/allconfig.php +++ b/lib/allconfig.php @@ -14,7 +14,7 @@ namespace OC; */ class AllConfig implements \OCP\IConfig { /** - * Sets a new systemwide value + * Sets a new system wide value * @param string $key the key of the value, under which will be saved * @param string $value the value that should be stored * @todo need a use case for this @@ -24,7 +24,7 @@ class AllConfig implements \OCP\IConfig { // } /** - * Looks up a systemwide defined value + * Looks up a system wide defined value * @param string $key the key of the value, under which it was saved * @return string the saved value */ @@ -34,7 +34,7 @@ class AllConfig implements \OCP\IConfig { /** - * Writes a new appwide value + * Writes a new app wide value * @param string $appName the appName that we want to store the value under * @param string $key the key of the value, under which will be saved * @param string $value the value that should be stored @@ -44,7 +44,7 @@ class AllConfig implements \OCP\IConfig { } /** - * Looks up an appwide defined value + * Looks up an app wide defined value * @param string $appName the appName that we stored the value under * @param string $key the key of the value, under which it was saved * @return string the saved value diff --git a/lib/public/iconfig.php b/lib/public/iconfig.php index 0c150ec351a..dab4590969b 100644 --- a/lib/public/iconfig.php +++ b/lib/public/iconfig.php @@ -12,7 +12,7 @@ namespace OCP; */ interface IConfig { /** - * Sets a new systemwide value + * Sets a new system wide value * @param string $key the key of the value, under which will be saved * @param string $value the value that should be stored * @todo need a use case for this @@ -20,7 +20,7 @@ interface IConfig { // public function setSystemValue($key, $value); /** - * Looks up a systemwide defined value + * Looks up a system wide defined value * @param string $key the key of the value, under which it was saved * @return string the saved value */ @@ -28,14 +28,14 @@ interface IConfig { /** - * Writes a new appwide value + * Writes a new app wide value * @param string $key the key of the value, under which will be saved * @param string $value the value that should be stored */ public function setAppValue($key, $value, $appName=null); /** - * Looks up an appwide defined value + * Looks up an app wide defined value * @param string $key the key of the value, under which it was saved * @return string the saved value */ -- cgit v1.2.3 From e31f6c01e85bea52e973df65a7610d490bf6336c Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 20 Sep 2013 21:43:17 +0200 Subject: fixing PHPDoc --- lib/public/app.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/public/app.php b/lib/public/app.php index a1ecf524cc8..0a5721b334e 100644 --- a/lib/public/app.php +++ b/lib/public/app.php @@ -35,10 +35,10 @@ namespace OCP; */ class App { /** - * @brief Makes owncloud aware of this app + * @brief Makes ownCloud aware of this app * @brief This call is deprecated and not necessary to use. * @param $data array with all information - * @returns true/false + * @returns boolean * * @deprecated this method is deprecated * Do not call it anymore @@ -52,7 +52,7 @@ class App { /** * @brief adds an entry to the navigation * @param $data array containing the data - * @returns true/false + * @returns boolean * * This function adds a new entry to the navigation visible to users. $data * is an associative array. @@ -72,8 +72,8 @@ class App { /** * @brief marks a navigation entry as active - * @param $id id of the entry - * @returns true/false + * @param $id string id of the entry + * @returns boolean * * This function sets a navigation entry as active and removes the 'active' * property from all other entries. The templates can use this for @@ -104,7 +104,7 @@ class App { /** * @brief Read app metadata from the info.xml file * @param string $app id of the app or the path of the info.xml file - * @param boolean path (optional) + * @param boolean $path (optional) * @returns array */ public static function getAppInfo( $app, $path=false ) { @@ -114,7 +114,7 @@ class App { /** * @brief checks whether or not an app is enabled * @param $app app - * @returns true/false + * @returns boolean * * This function checks whether or not an app is enabled. */ @@ -133,7 +133,7 @@ class App { /** * @brief Get the last version of the app, either from appinfo/version or from appinfo/info.xml * @param $app app - * @returns true/false + * @returns boolean */ public static function getAppVersion( $app ) { return \OC_App::getAppVersion( $app ); -- cgit v1.2.3 From f83f32326949d6bc16c2b0d7aefcdbb48f9119d7 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 20 Sep 2013 21:45:27 +0200 Subject: fixing typos + adding missing filed $activeEntry --- lib/navigationmanager.php | 3 ++- lib/public/inavigationmanager.php | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/navigationmanager.php b/lib/navigationmanager.php index f032afd1fc4..cf3bf84d998 100644 --- a/lib/navigationmanager.php +++ b/lib/navigationmanager.php @@ -10,10 +10,11 @@ namespace OC; /** - * Manages the owncloud navigation + * Manages the ownCloud navigation */ class NavigationManager { protected $entries = array(); + protected $activeEntry; /** * Creates a new navigation entry diff --git a/lib/public/inavigationmanager.php b/lib/public/inavigationmanager.php index 21744dd1c21..f89e790c1d0 100644 --- a/lib/public/inavigationmanager.php +++ b/lib/public/inavigationmanager.php @@ -10,7 +10,7 @@ namespace OCP; /** - * Manages the owncloud navigation + * Manages the ownCloud navigation */ interface INavigationManager { /** @@ -24,4 +24,4 @@ interface INavigationManager { * @param string $appId id of the app entry to activate (from added $entry) */ public function setActiveEntry($appId); -} \ No newline at end of file +} -- cgit v1.2.3 From d3d52dd23f3da9a3d9ed2b50b1abd1a229dc4be8 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 20 Sep 2013 21:57:48 +0200 Subject: PHPDoc & get UserManager from container for RooFolder --- lib/server.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/server.php b/lib/server.php index 57e7f4ab4f1..804af6b0eac 100644 --- a/lib/server.php +++ b/lib/server.php @@ -4,6 +4,7 @@ namespace OC; use OC\AppFramework\Http\Request; use OC\AppFramework\Utility\SimpleContainer; +use OC\Cache\UserCache; use OC\Files\Node\Root; use OC\Files\View; use OCP\IServerContainer; @@ -49,9 +50,11 @@ class Server extends SimpleContainer implements IServerContainer { return new PreviewManager(); }); $this->registerService('RootFolder', function($c) { - // TODO: get user and user manager from container as well + // TODO: get user from container as well $user = \OC_User::getUser(); - $user = \OC_User::getManager()->get($user); + /** @var $c SimpleContainer */ + $userManager = $c->query('UserManager'); + $user = $userManager->get($user); $manager = \OC\Files\Filesystem::getMountManager(); $view = new View(); return new Root($manager, $view, $user); @@ -60,6 +63,7 @@ class Server extends SimpleContainer implements IServerContainer { return new \OC\User\Manager(); }); $this->registerService('UserSession', function($c) { + /** @var $c SimpleContainer */ $manager = $c->query('UserManager'); $userSession = new \OC\User\Session($manager, \OC::$session); $userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) { -- cgit v1.2.3 From 0c6dcdba6b890dc170f59a461ab80961a85a53db Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Fri, 20 Sep 2013 22:45:22 +0200 Subject: Add missing implements and fix parameters in IConfig --- lib/allconfig.php | 1 - lib/navigationmanager.php | 2 +- lib/public/iconfig.php | 22 ++++++++++++++-------- lib/public/idbconnection.php | 3 +++ lib/user/session.php | 2 +- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/allconfig.php b/lib/allconfig.php index 353608e5d21..72aabf60793 100644 --- a/lib/allconfig.php +++ b/lib/allconfig.php @@ -65,7 +65,6 @@ class AllConfig implements \OCP\IConfig { \OCP\Config::setUserValue($userId, $appName, $key, $value); } - /** * Shortcut for getting a user defined value * @param string $userId the userId of the user that we want to store the value under diff --git a/lib/navigationmanager.php b/lib/navigationmanager.php index cf3bf84d998..1f657b9ad80 100644 --- a/lib/navigationmanager.php +++ b/lib/navigationmanager.php @@ -12,7 +12,7 @@ namespace OC; /** * Manages the ownCloud navigation */ -class NavigationManager { +class NavigationManager implements \OCP\INavigationManager { protected $entries = array(); protected $activeEntry; diff --git a/lib/public/iconfig.php b/lib/public/iconfig.php index dab4590969b..850bddf6935 100644 --- a/lib/public/iconfig.php +++ b/lib/public/iconfig.php @@ -1,10 +1,12 @@ +/** + * Copyright (c) 2013 Bart Visscher * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. * */ + namespace OCP; /** @@ -29,31 +31,35 @@ interface IConfig { /** * Writes a new app wide value + * @param string $appName the appName that we want to store the value under * @param string $key the key of the value, under which will be saved * @param string $value the value that should be stored */ - public function setAppValue($key, $value, $appName=null); + public function setAppValue($appName, $key, $value); /** * Looks up an app wide defined value + * @param string $appName the appName that we stored the value under * @param string $key the key of the value, under which it was saved * @return string the saved value */ - public function getAppValue($key, $appName=null); + public function getAppValue($appName, $key); /** - * Shortcut for setting a user defined value + * Set a user defined value + * @param string $userId the userId of the user that we want to store the value under + * @param string $appName the appName that we want to store the value under * @param string $key the key under which the value is being stored * @param string $value the value that you want to store - * @param string $userId the userId of the user that we want to store the value under, defaults to the current one */ - public function setUserValue($key, $value, $userId=null); + public function setUserValue($userId, $appName, $key, $value); /** * Shortcut for getting a user defined value + * @param string $userId the userId of the user that we want to store the value under + * @param string $appName the appName that we stored the value under * @param string $key the key under which the value is being stored - * @param string $userId the userId of the user that we want to store the value under, defaults to the current one */ - public function getUserValue($key, $userId=null); + public function getUserValue($userId, $appName, $key); } diff --git a/lib/public/idbconnection.php b/lib/public/idbconnection.php index 67dd7ccfc37..c741a0f061a 100644 --- a/lib/public/idbconnection.php +++ b/lib/public/idbconnection.php @@ -50,16 +50,19 @@ interface IDBConnection { /** * @brief Start a transaction + * @return bool TRUE on success or FALSE on failure */ public function beginTransaction(); /** * @brief Commit the database changes done during a transaction that is in progress + * @return bool TRUE on success or FALSE on failure */ public function commit(); /** * @brief Rollback the database changes done during a transaction that is in progress + * @return bool TRUE on success or FALSE on failure */ public function rollBack(); diff --git a/lib/user/session.php b/lib/user/session.php index 9a6c669e935..98a24d5bb00 100644 --- a/lib/user/session.php +++ b/lib/user/session.php @@ -27,7 +27,7 @@ use OC\Hooks\Emitter; * * @package OC\User */ -class Session implements Emitter { +class Session implements Emitter, \OCP\IUserSession { /** * @var \OC\User\Manager $manager */ -- cgit v1.2.3 From a2f82da572eaf9cebfe4de53b329af700d63e93f Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 20 Sep 2013 23:52:05 +0200 Subject: Use update() instead of put(). --- lib/files/cache/scanner.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index d296c606865..3f1970fb4a2 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -121,9 +121,7 @@ class Scanner extends BasicEmitter { } $parentCacheData = $this->cache->get($parent); $parentCacheData['etag'] = $this->storage->getETag($parent); - // the boolean to int conversion is necessary to make pg happy - $parentCacheData['encrypted'] = $parentCacheData['encrypted'] ? 1 : 0; - $this->cache->put($parent, $parentCacheData); + $this->cache->update($parentCacheData['fileid'], $parentCacheData); } } } -- cgit v1.2.3 From 011bca7b7f0a67c9cf23773b625ee334db1e6c06 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 20 Sep 2013 23:53:02 +0200 Subject: Only update the etag. Do not re-submit any other unchanged data. --- lib/files/cache/scanner.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index 3f1970fb4a2..fcb8ccdc8d5 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -120,8 +120,9 @@ class Scanner extends BasicEmitter { $parent = ''; } $parentCacheData = $this->cache->get($parent); - $parentCacheData['etag'] = $this->storage->getETag($parent); - $this->cache->update($parentCacheData['fileid'], $parentCacheData); + $this->cache->update($parentCacheData['fileid'], array( + 'etag' => $this->storage->getETag($parent), + )); } } } -- cgit v1.2.3 From de2e6e137b3be966622b0b608a3b69f6282e2e56 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 21 Sep 2013 00:12:13 +0200 Subject: Do not convert boolean to integer in tests. put() already does this. --- tests/lib/files/cache/scanner.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php index 8112eada17c..b137799bbcf 100644 --- a/tests/lib/files/cache/scanner.php +++ b/tests/lib/files/cache/scanner.php @@ -195,7 +195,6 @@ class Scanner extends \PHPUnit_Framework_TestCase { $data1 = $this->cache->get('folder'); $data2 = $this->cache->get(''); $data0['etag'] = ''; - $data0['encrypted'] = $data0['encrypted'] ? 1: 0; $this->cache->put('folder/bar.txt', $data0); // rescan -- cgit v1.2.3 From 2a17025d537c41b9366c9592c985b911d9394337 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 21 Sep 2013 02:20:01 +0200 Subject: Move bool to int conversion to buildParts(), so it also happens for update(). --- lib/files/cache/cache.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php index 39e36684b7b..e69733727af 100644 --- a/lib/files/cache/cache.php +++ b/lib/files/cache/cache.php @@ -201,7 +201,6 @@ class Cache { $data['path'] = $file; $data['parent'] = $this->getParentId($file); $data['name'] = \OC_Util::basename($file); - $data['encrypted'] = isset($data['encrypted']) ? ((int)$data['encrypted']) : 0; list($queryParts, $params) = $this->buildParts($data); $queryParts[] = '`storage`'; @@ -265,6 +264,9 @@ class Cache { $params[] = $value; $queryParts[] = '`mtime`'; } + } elseif ($name === 'encrypted') { + // Boolean to integer conversion + $value = $value ? 1 : 0; } $params[] = $value; $queryParts[] = '`' . $name . '`'; -- cgit v1.2.3 From edd38e59481a98c56645a43ca6c9048fe1458d20 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Mon, 23 Sep 2013 10:26:46 +0200 Subject: fix previews in shared folders --- apps/files/lib/helper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index 08c807d7f7b..1d431df04f1 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -39,8 +39,8 @@ class Helper } if($file['isPreviewAvailable']) { - $relativePath = substr($file['path'], 6); - return \OC_Helper::previewIcon($relativePath); + $pathForPreview = $file['directory'] . '/' . $file['name']; + return \OC_Helper::previewIcon($pathForPreview); } return \OC_Helper::mimetypeIcon($file['mimetype']); } -- cgit v1.2.3 From 8a1618bce56a32e311626cd9f0e322dd7cf330c4 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Mon, 23 Sep 2013 12:27:05 +0200 Subject: implement previews for public upload --- apps/files/js/files.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 8ccb448abfb..ec688eaf63e 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -644,7 +644,11 @@ function lazyLoadPreview(path, mime, ready, width, height) { if ( ! height ) { height = $('#filestable').data('preview-y'); } - var previewURL = OC.Router.generate('core_ajax_preview', {file: encodeURIComponent(path), x:width, y:height}); + if( $('#publicUploadButtonMock').length ) { + var previewURL = OC.Router.generate('core_ajax_public_preview', {file: encodeURIComponent(path), x:width, y:height, t:$('#dirToken').val()}); + } else { + var previewURL = OC.Router.generate('core_ajax_preview', {file: encodeURIComponent(path), x:width, y:height}); + } $.get(previewURL, function() { previewURL = previewURL.replace('(', '%28'); previewURL = previewURL.replace(')', '%29'); -- cgit v1.2.3 From d9a36ee82ec3bffb83515248b69c287f5fd0170f Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Mon, 23 Sep 2013 12:45:02 +0200 Subject: Move setUp() and tearDown() up in tests/lib/files/cache/scanner.php. --- tests/lib/files/cache/scanner.php | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php index 6956e7aa948..3f3a045377a 100644 --- a/tests/lib/files/cache/scanner.php +++ b/tests/lib/files/cache/scanner.php @@ -24,6 +24,21 @@ class Scanner extends \PHPUnit_Framework_TestCase { */ private $cache; + function setUp() { + $this->storage = new \OC\Files\Storage\Temporary(array()); + $this->scanner = new \OC\Files\Cache\Scanner($this->storage); + $this->cache = new \OC\Files\Cache\Cache($this->storage); + } + + function tearDown() { + if ($this->cache) { + $ids = $this->cache->getAll(); + $permissionsCache = $this->storage->getPermissionsCache(); + $permissionsCache->removeMultiple($ids, \OC_User::getUser()); + $this->cache->clear(); + } + } + function testFile() { $data = "dummy file data\n"; $this->storage->file_put_contents('foo.txt', $data); @@ -218,19 +233,4 @@ class Scanner extends \PHPUnit_Framework_TestCase { $this->assertNotEquals($data1['etag'], $newData1['etag']); $this->assertNotEquals($data2['etag'], $newData2['etag']); } - - function setUp() { - $this->storage = new \OC\Files\Storage\Temporary(array()); - $this->scanner = new \OC\Files\Cache\Scanner($this->storage); - $this->cache = new \OC\Files\Cache\Cache($this->storage); - } - - function tearDown() { - if ($this->cache) { - $ids = $this->cache->getAll(); - $permissionsCache = $this->storage->getPermissionsCache(); - $permissionsCache->removeMultiple($ids, \OC_User::getUser()); - $this->cache->clear(); - } - } } -- cgit v1.2.3 From 0b4de847a93357160dc4acb3de651a7ee08a10df Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 13:27:43 +0200 Subject: Added more error checking in add() --- lib/tags.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/tags.php b/lib/tags.php index 2eaa603c1a3..e2e1a83dd94 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -233,17 +233,25 @@ class Tags implements \OCP\ITags { return false; } try { - \OCP\DB::insertIfNotExist(self::TAG_TABLE, + $result = \OCP\DB::insertIfNotExist( + self::TAG_TABLE, array( 'uid' => $this->user, 'type' => $this->type, 'category' => $name, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); + ) + ); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; + } elseif((int)$result === 0) { + \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } $id = \OCP\DB::insertid(self::TAG_TABLE); \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); $this->tags[$id] = $name; -- cgit v1.2.3 From 93258e11701205b47b3775dbbb5f187a3a76266b Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 13:29:21 +0200 Subject: Forgot to return false if add() didn't add anything. --- lib/tags.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tags.php b/lib/tags.php index e2e1a83dd94..955eb3cd363 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -246,6 +246,7 @@ class Tags implements \OCP\ITags { return false; } elseif((int)$result === 0) { \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); + return false; } } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), -- cgit v1.2.3 From 910a0338bb296e2e51d6c9d37d0483f8d05b1c5c Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 15:52:06 +0200 Subject: Use fetchOne() instead of numRows() when doing a COUNT(*). --- lib/tags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tags.php b/lib/tags.php index 955eb3cd363..ff9f35ebc9e 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -119,7 +119,7 @@ class Tags implements \OCP\ITags { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; } - return ((int)$result->numRows() === 0); + return ((int)$result->fetchOne() === 0); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR); -- cgit v1.2.3 From d27416edf767219f77a828d22bb070345a179631 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 15:52:50 +0200 Subject: Moar tests. --- tests/lib/tags.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 92a96a14772..75db9f50f72 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -59,13 +59,14 @@ class Test_Tags extends PHPUnit_Framework_TestCase { foreach($tags as $tag) { $result = $tagMgr->add($tag); + $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); $this->assertTrue((bool)$result); } $this->assertFalse($tagMgr->add('Family')); $this->assertFalse($tagMgr->add('fAMILY')); - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertCount(4, $tagMgr->getTags(), 'Wrong number of added tags'); } public function testAddMultiple() { @@ -85,7 +86,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertTrue($tagMgr->hasTag($tag)); } - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertCount(4, $tagMgr->getTags(), 'Not all tags added'); } public function testIsEmpty() { @@ -94,7 +95,10 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertEquals(0, count($tagMgr->getTags())); $this->assertTrue($tagMgr->isEmpty()); - $this->assertNotEquals(false, $tagMgr->add('Tag')); + + $result = $tagMgr->add('Tag'); + $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); + $this->assertNotEquals(false, $result, 'add() returned false'); $this->assertFalse($tagMgr->isEmpty()); } -- cgit v1.2.3 From d7409547aa0c6fe23cb408e266a09392b4752a72 Mon Sep 17 00:00:00 2001 From: kondou Date: Mon, 23 Sep 2013 16:39:42 +0200 Subject: Fix not displaying "Upload something!" message Fix #4940 --- apps/files/templates/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index bd991c3fcb0..96a80738989 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -47,7 +47,7 @@ -
0 or !$_['ajaxLoad']):?>class="hidden">t('Nothing in here. Upload something!'))?>
+
0 or $_['ajaxLoad']):?>class="hidden">t('Nothing in here. Upload something!'))?>
-- cgit v1.2.3 From e55f25b64df09a3ba6535274eaf738e82910e1f6 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 23 Sep 2013 22:04:37 +0200 Subject: handle error situation of rename proper --- lib/connector/sabre/directory.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index 3181a4b310f..9e0fe5e64e7 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -88,7 +88,12 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa } // rename to correct path - \OC\Files\Filesystem::rename($partpath, $newPath); + $renameOkay = \OC\Files\Filesystem::rename($partpath, $newPath); + if (!$renameOkay) { + \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + \OC\Files\Filesystem::unlink($partpath); + throw new Sabre_DAV_Exception(); + } // allow sync clients to send the mtime along in a header $mtime = OC_Request::hasModificationTime(); -- cgit v1.2.3 From 5ca181eb23de7d3436b22ba924788db62976a059 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 4 Sep 2013 08:16:27 +0200 Subject: More trimming --- lib/vcategories.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 84036958359..a7e4c54be29 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -179,6 +179,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { + $category = trim($category); $catid = $this->array_searchi($category, $this->categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); @@ -240,6 +241,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { + $category = trim($category); $catid = $this->array_searchi($category, $this->categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); @@ -301,6 +303,7 @@ class OC_VCategories { * @returns int the id of the added category or false if it already exists. */ public function add($name) { + $name = trim($name); OCP\Util::writeLog('core', __METHOD__.', name: ' . $name, OCP\Util::DEBUG); if($this->hasCategory($name)) { OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', OCP\Util::DEBUG); @@ -331,6 +334,8 @@ class OC_VCategories { * @returns bool */ public function rename($from, $to) { + $from = trim($from); + $to = trim($to); $id = $this->array_searchi($from, $this->categories); if($id === false) { OCP\Util::writeLog('core', __METHOD__.', category: ' . $from. ' does not exist', OCP\Util::DEBUG); @@ -656,6 +661,7 @@ class OC_VCategories { public function addToCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; if(is_string($category) && !is_numeric($category)) { + $category = trim($category); if(!$this->hasCategory($category)) { $this->add($category, true); } @@ -688,9 +694,13 @@ class OC_VCategories { */ public function removeFromCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; - $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, $this->categories) - : $category; + if(is_string($category) && !is_numeric($category)) { + $category = trim($category); + $categoryid = $this->array_searchi($category, $this->categories); + } else { + $categoryid = $category; + } + try { $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; @@ -716,6 +726,8 @@ class OC_VCategories { $names = array($names); } + $names = array_map('trim', $names); + OC_Log::write('core', __METHOD__ . ', before: ' . print_r($this->categories, true), OC_Log::DEBUG); foreach($names as $name) { -- cgit v1.2.3 From 45f73feb6967b878b2e39fc4413aca92f0dbaf9f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 00:37:00 +0200 Subject: OC_VCategories=>OC\Tags. Public interface + getter in server container --- lib/public/iservercontainer.php | 7 + lib/public/itags.php | 173 +++++++++ lib/server.php | 16 +- lib/tags.php | 621 ++++++++++++++++++++++++++++++ lib/vcategories.php | 833 ---------------------------------------- tests/lib/tags.php | 133 +++++++ tests/lib/vcategories.php | 128 ------ 7 files changed, 948 insertions(+), 963 deletions(-) create mode 100644 lib/public/itags.php create mode 100644 lib/tags.php delete mode 100644 lib/vcategories.php create mode 100644 tests/lib/tags.php delete mode 100644 tests/lib/vcategories.php diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 4478a4e8a6c..0df746a28ed 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -55,6 +55,13 @@ interface IServerContainer { */ function getPreviewManager(); + /** + * Returns the tag manager which can get and set tags for different object types + * + * @return \OCP\ITags + */ + function getTagManager(); + /** * Returns the root folder of ownCloud's data directory * diff --git a/lib/public/itags.php b/lib/public/itags.php new file mode 100644 index 00000000000..047d4f5f40b --- /dev/null +++ b/lib/public/itags.php @@ -0,0 +1,173 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +namespace OCP; + +// FIXME: Where should I put this? Or should it be implemented as a Listener? +\OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Tags', 'post_deleteUser'); + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +interface ITags { + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function loadTagsFor($type, $defaultTags=array()); + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty(); + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @returns array + */ + public function tags(); + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function idsForTag($tag); + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name); + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name); + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to); + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMulti($names, $sync=false, $id = null); + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids); + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites(); + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid); + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid); + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag); + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag); + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names); + +} \ No newline at end of file diff --git a/lib/server.php b/lib/server.php index 804af6b0eac..b09d380b0e9 100644 --- a/lib/server.php +++ b/lib/server.php @@ -49,8 +49,11 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('PreviewManager', function($c) { return new PreviewManager(); }); - $this->registerService('RootFolder', function($c) { - // TODO: get user from container as well + $this->registerService('TagManager', function($c){ + return new Tags(); + }); + $this->registerService('RootFolder', function($c){ + // TODO: get user and user manager from container as well $user = \OC_User::getUser(); /** @var $c SimpleContainer */ $userManager = $c->query('UserManager'); @@ -139,6 +142,15 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('PreviewManager'); } + /** + * Returns the tag manager which can get and set tags for different object types + * + * @return \OCP\ITags + */ + function getTagManager() { + return $this->query('TagManager'); + } + /** * Returns the root folder of ownCloud's data directory * diff --git a/lib/tags.php b/lib/tags.php new file mode 100644 index 00000000000..4aafff8e1bb --- /dev/null +++ b/lib/tags.php @@ -0,0 +1,621 @@ + +* @copyright 2012 Bart Visscher bartv@thisnet.nl +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class Tags implements \OCP\ITags { + + /** + * Tags + */ + private $tags = array(); + + /** + * Used for storing objectid/categoryname pairs while rescanning. + */ + private static $relations = array(); + + private $type = null; + private $user = null; + + const TAG_TABLE = '*PREFIX*vcategory'; + const RELATION_TABLE = '*PREFIX*vcategory_to_object'; + + const TAG_FAVORITE = '_$!!$_'; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user) { + + $this->user = $user; + + } + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function loadTagsFor($type, $defaultTags=array()) { + $this->type = $type; + $this->tags = array(); + $result = null; + $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $this->tags[$row['id']] = $row['category']; + } + } + + if(count($defaultTags) > 0 && count($this->tags) === 0) { + $this->addMulti($defaultTags, true); + } + \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), + \OCP\Util::DEBUG); + + return $this; + } + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty() { + $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ?'; + try { + $stmt = OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + return ($result->numRows() === 0); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @return array + */ + public function tags() { + if(!count($this->tags)) { + return array(); + } + + $tags = array_values($this->tags); + uasort($tags, 'strnatcasecmp'); + $tagMap = array(); + + foreach($tags as $tag) { + if($tag !== self::TAG_FAVORITE) { + $tagMap[] = array( + 'id' => $this->array_searchi($tag, $this->tags), + 'name' => $tag + ); + } + } + return $tagMap; + + } + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function idsForTag($tag) { + $result = null; + if(is_numeric($tag)) { + $tagId = $tag; + } elseif(is_string($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } + + if($tagId === false) { + $l10n = \OC_L10N::get('core'); + throw new \Exception( + $l10n->t('Could not find category "%s"', $tag) + ); + } + + $ids = array(); + $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE + . '` WHERE `categoryid` = ?'; + + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($tagId)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $ids[] = (int)$row['objid']; + } + } + + return $ids; + } + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name) { + return $this->in_arrayi($name, $this->tags); + } + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name) { + $name = trim($name); + + if($this->hasTag($name)) { + \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG); + return false; + } + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $name, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $id = \OCP\DB::insertid(self::TAG_TABLE); + \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); + $this->tags[$id] = $name; + return $id; + } + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to) { + $from = trim($from); + $to = trim($to); + $id = $this->array_searchi($from, $this->tags); + if($id === false) { + \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG); + return false; + } + + $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? ' + . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($to, $this->user, $this->type, $id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $this->tags[$id] = $to; + return true; + } + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMulti($names, $sync=false, $id = null) { + if(!is_array($names)) { + $names = array($names); + } + $names = array_map('trim', $names); + $newones = array(); + foreach($names as $name) { + if(($this->in_arrayi( + $name, $this->tags) == false) && $name !== '') { + $newones[] = $name; + } + if(!is_null($id) ) { + // Insert $objectid, $categoryid pairs if not exist. + self::$relations[] = array('objid' => $id, 'tag' => $name); + } + } + $this->tags = array_merge($this->tags, $newones); + if($sync === true) { + $this->save(); + } + + return true; + } + + /** + * Save the list of tags and their object relations + */ + protected function save() { + if(is_array($this->tags)) { + foreach($this->tags as $tag) { + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $tag, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + // reload tags to get the proper ids. + $this->loadTagsFor($this->type); + // Loop through temporarily cached objectid/tagname pairs + // and save relations. + $tags = $this->tags; + // For some reason this is needed or array_search(i) will return 0..? + ksort($tags); + foreach(self::$relations as $relation) { + $tagId = $this->array_searchi($relation['tag'], $tags); + \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG); + if($tagId) { + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $relation['objid'], + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } + self::$relations = array(); // reset + } else { + \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! ' + . print_r($this->tags, true), \OCP\Util::ERROR); + } + } + + /** + * Delete tags and tag/object relations for a user. + * + * For hooking up on post_deleteUser + * + * @param array + */ + public static function post_deleteUser($arguments) { + // Find all objectid/tagId pairs. + $result = null; + try { + $stmt = \OCP\DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'); + while( $row = $result->fetchRow()) { + try { + $stmt->execute(array($row['id'])); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), OCP\Util::ERROR); + } + } + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids) { + if(count($ids) === 0) { + // job done ;) + return true; + } + $updates = $ids; + try { + $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; + $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; + $query .= 'AND `type`= ?'; + $updates[] = $this->type; + $stmt = OCP\DB::prepare($query); + $result = $stmt->execute($updates); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites() { + try { + return $this->idsForTag(self::TAG_FAVORITE); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return array(); + } + } + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid) { + if(!$this->hasCategory(self::TAG_FAVORITE)) { + $this->add(self::TAG_FAVORITE, true); + } + return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid) { + return $this->unTag($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + if(!$this->hasTag($tag)) { + $this->add($tag, true); + } + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $objid, + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; + $stmt = \OCP\DB::prepare($sql); + $stmt->execute(array($objid, $tagId, $this->type)); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names) { + if(!is_array($names)) { + $names = array($names); + } + + $names = array_map('trim', $names); + + \OCP\Util::writeLog('core', __METHOD__ . ', before: ' + . print_r($this->tags, true), \OCP\Util::DEBUG); + foreach($names as $name) { + $id = null; + + if($this->hasTag($name)) { + $id = $this->array_searchi($name, $this->tags); + unset($this->tags[$id]); + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE ' + . '`uid` = ? AND `type` = ? AND `category` = ?'); + $result = $stmt->execute(array($this->user, $this->type, $name)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); + return false; + } + if(!is_null($id) && $id !== false) { + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'; + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', + __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), + \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + } + return true; + } + + // case-insensitive in_array + private function in_arrayi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return in_array(strtolower($needle), array_map('strtolower', $haystack)); + } + + // case-insensitive array_search + private function array_searchi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return array_search(strtolower($needle), array_map('strtolower', $haystack)); + } +} diff --git a/lib/vcategories.php b/lib/vcategories.php deleted file mode 100644 index a7e4c54be29..00000000000 --- a/lib/vcategories.php +++ /dev/null @@ -1,833 +0,0 @@ - -* @copyright 2012 Bart Visscher bartv@thisnet.nl -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 library. If not, see . -* -*/ - -OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'post_deleteUser'); - -/** - * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. - * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or - * anything else that is either parsed from a vobject or that the user chooses - * to add. - * Category names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a category 'family' for a type, and - * tries to add a category named 'Family' it will be silently ignored. - */ -class OC_VCategories { - - /** - * Categories - */ - private $categories = array(); - - /** - * Used for storing objectid/categoryname pairs while rescanning. - */ - private static $relations = array(); - - private $type = null; - private $user = null; - - const CATEGORY_TABLE = '*PREFIX*vcategory'; - const RELATION_TABLE = '*PREFIX*vcategory_to_object'; - - const CATEGORY_FAVORITE = '_$!!$_'; - - const FORMAT_LIST = 0; - const FORMAT_MAP = 1; - - /** - * @brief Constructor. - * @param $type The type identifier e.g. 'contact' or 'event'. - * @param $user The user whos data the object will operate on. This - * parameter should normally be omitted but to make an app able to - * update categories for all users it is made possible to provide it. - * @param $defcategories An array of default categories to be used if none is stored. - */ - public function __construct($type, $user=null, $defcategories=array()) { - $this->type = $type; - $this->user = is_null($user) ? OC_User::getUser() : $user; - - $this->loadCategories(); - OCP\Util::writeLog('core', __METHOD__ . ', categories: ' - . print_r($this->categories, true), - OCP\Util::DEBUG - ); - - if($defcategories && count($this->categories) === 0) { - $this->addMulti($defcategories, true); - } - } - - /** - * @brief Load categories from db. - */ - private function loadCategories() { - $this->categories = array(); - $result = null; - $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - // The keys are prefixed because array_search wouldn't work otherwise :-/ - $this->categories[$row['id']] = $row['category']; - } - } - OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r($this->categories, true), - OCP\Util::DEBUG); - } - - - /** - * @brief Check if any categories are saved for this type and user. - * @returns boolean. - * @param $type The type identifier e.g. 'contact' or 'event'. - * @param $user The user whos categories will be checked. If not set current user will be used. - */ - public static function isEmpty($type, $user = null) { - $user = is_null($user) ? OC_User::getUser() : $user; - $sql = 'SELECT COUNT(*) FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($user, $type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - return ($result->numRows() === 0); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - } - - /** - * @brief Get the categories for a specific user. - * @param - * @returns array containing the categories as strings. - */ - public function categories($format = null) { - if(!$this->categories) { - return array(); - } - $categories = array_values($this->categories); - uasort($categories, 'strnatcasecmp'); - if($format == self::FORMAT_MAP) { - $catmap = array(); - foreach($categories as $category) { - if($category !== self::CATEGORY_FAVORITE) { - $catmap[] = array( - 'id' => $this->array_searchi($category, $this->categories), - 'name' => $category - ); - } - } - return $catmap; - } - - // Don't add favorites to normal categories. - $favpos = array_search(self::CATEGORY_FAVORITE, $categories); - if($favpos !== false) { - return array_splice($categories, $favpos); - } else { - return $categories; - } - } - - /** - * Get the a list if items belonging to $category. - * - * Throws an exception if the category could not be found. - * - * @param string|integer $category Category id or name. - * @returns array An array of object ids or false on error. - */ - public function idsForCategory($category) { - $result = null; - if(is_numeric($category)) { - $catid = $category; - } elseif(is_string($category)) { - $category = trim($category); - $catid = $this->array_searchi($category, $this->categories); - } - OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); - if($catid === false) { - $l10n = OC_L10N::get('core'); - throw new Exception( - $l10n->t('Could not find category "%s"', $category) - ); - } - - $ids = array(); - $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE - . '` WHERE `categoryid` = ?'; - - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($catid)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $ids[] = (int)$row['objid']; - } - } - - return $ids; - } - - /** - * Get the a list if items belonging to $category. - * - * Throws an exception if the category could not be found. - * - * @param string|integer $category Category id or name. - * @param array $tableinfo Array in the form {'tablename' => table, 'fields' => ['field1', 'field2']} - * @param int $limit - * @param int $offset - * - * This generic method queries a table assuming that the id - * field is called 'id' and the table name provided is in - * the form '*PREFIX*table_name'. - * - * If the category name cannot be resolved an exception is thrown. - * - * TODO: Maybe add the getting permissions for objects? - * - * @returns array containing the resulting items or false on error. - */ - public function itemsForCategory($category, $tableinfo, $limit = null, $offset = null) { - $result = null; - if(is_numeric($category)) { - $catid = $category; - } elseif(is_string($category)) { - $category = trim($category); - $catid = $this->array_searchi($category, $this->categories); - } - OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); - if($catid === false) { - $l10n = OC_L10N::get('core'); - throw new Exception( - $l10n->t('Could not find category "%s"', $category) - ); - } - $fields = ''; - foreach($tableinfo['fields'] as $field) { - $fields .= '`' . $tableinfo['tablename'] . '`.`' . $field . '`,'; - } - $fields = substr($fields, 0, -1); - - $items = array(); - $sql = 'SELECT `' . self::RELATION_TABLE . '`.`categoryid`, ' . $fields - . ' FROM `' . $tableinfo['tablename'] . '` JOIN `' - . self::RELATION_TABLE . '` ON `' . $tableinfo['tablename'] - . '`.`id` = `' . self::RELATION_TABLE . '`.`objid` WHERE `' - . self::RELATION_TABLE . '`.`categoryid` = ?'; - - try { - $stmt = OCP\DB::prepare($sql, $limit, $offset); - $result = $stmt->execute(array($catid)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $items[] = $row; - } - } - //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); - //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); - - return $items; - } - - /** - * @brief Checks whether a category is already saved. - * @param $name The name to check for. - * @returns bool - */ - public function hasCategory($name) { - return $this->in_arrayi($name, $this->categories); - } - - /** - * @brief Add a new category. - * @param $name A string with a name of the category - * @returns int the id of the added category or false if it already exists. - */ - public function add($name) { - $name = trim($name); - OCP\Util::writeLog('core', __METHOD__.', name: ' . $name, OCP\Util::DEBUG); - if($this->hasCategory($name)) { - OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', OCP\Util::DEBUG); - return false; - } - try { - OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $name, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - $id = OCP\DB::insertid(self::CATEGORY_TABLE); - OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, OCP\Util::DEBUG); - $this->categories[$id] = $name; - return $id; - } - - /** - * @brief Rename category. - * @param string $from The name of the existing category - * @param string $to The new name of the category. - * @returns bool - */ - public function rename($from, $to) { - $from = trim($from); - $to = trim($to); - $id = $this->array_searchi($from, $this->categories); - if($id === false) { - OCP\Util::writeLog('core', __METHOD__.', category: ' . $from. ' does not exist', OCP\Util::DEBUG); - return false; - } - - $sql = 'UPDATE `' . self::CATEGORY_TABLE . '` SET `category` = ? ' - . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($to, $this->user, $this->type, $id)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - $this->categories[$id] = $to; - return true; - } - - /** - * @brief Add a new category. - * @param $names A string with a name or an array of strings containing - * the name(s) of the categor(y|ies) to add. - * @param $sync bool When true, save the categories - * @param $id int Optional object id to add to this|these categor(y|ies) - * @returns bool Returns false on error. - */ - public function addMulti($names, $sync=false, $id = null) { - if(!is_array($names)) { - $names = array($names); - } - $names = array_map('trim', $names); - $newones = array(); - foreach($names as $name) { - if(($this->in_arrayi( - $name, $this->categories) == false) && $name != '') { - $newones[] = $name; - } - if(!is_null($id) ) { - // Insert $objectid, $categoryid pairs if not exist. - self::$relations[] = array('objid' => $id, 'category' => $name); - } - } - $this->categories = array_merge($this->categories, $newones); - if($sync === true) { - $this->save(); - } - - return true; - } - - /** - * @brief Extracts categories from a vobject and add the ones not already present. - * @param $vobject The instance of OC_VObject to load the categories from. - */ - public function loadFromVObject($id, $vobject, $sync=false) { - $this->addMulti($vobject->getAsArray('CATEGORIES'), $sync, $id); - } - - /** - * @brief Reset saved categories and rescan supplied vobjects for categories. - * @param $objects An array of vobjects (as text). - * To get the object array, do something like: - * // For Addressbook: - * $categories = new OC_VCategories('contacts'); - * $stmt = OC_DB::prepare( 'SELECT `carddata` FROM `*PREFIX*contacts_cards`' ); - * $result = $stmt->execute(); - * $objects = array(); - * if(!is_null($result)) { - * while( $row = $result->fetchRow()){ - * $objects[] = array($row['id'], $row['carddata']); - * } - * } - * $categories->rescan($objects); - */ - public function rescan($objects, $sync=true, $reset=true) { - - if($reset === true) { - $result = null; - // Find all objectid/categoryid pairs. - try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - // And delete them. - if(!is_null($result)) { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ? AND `type`= ?'); - while( $row = $result->fetchRow()) { - $stmt->execute(array($row['id'], $this->type)); - } - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - return; - } - $this->categories = array(); - } - // Parse all the VObjects - foreach($objects as $object) { - $vobject = OC_VObject::parse($object[1]); - if(!is_null($vobject)) { - // Load the categories - $this->loadFromVObject($object[0], $vobject, $sync); - } else { - OC_Log::write('core', __METHOD__ . ', unable to parse. ID: ' . ', ' - . substr($object, 0, 100) . '(...)', OC_Log::DEBUG); - } - } - $this->save(); - } - - /** - * @brief Save the list with categories - */ - private function save() { - if(is_array($this->categories)) { - foreach($this->categories as $category) { - try { - OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $category, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - // reload categories to get the proper ids. - $this->loadCategories(); - // Loop through temporarily cached objectid/categoryname pairs - // and save relations. - $categories = $this->categories; - // For some reason this is needed or array_search(i) will return 0..? - ksort($categories); - foreach(self::$relations as $relation) { - $catid = $this->array_searchi($relation['category'], $categories); - OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG); - if($catid) { - try { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $relation['objid'], - 'categoryid' => $catid, - 'type' => $this->type, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - } - self::$relations = array(); // reset - } else { - OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' - . print_r($this->categories, true), OC_Log::ERROR); - } - } - - /** - * @brief Delete categories and category/object relations for a user. - * For hooking up on post_deleteUser - * @param string $uid The user id for which entries should be purged. - */ - public static function post_deleteUser($arguments) { - // Find all objectid/categoryid pairs. - $result = null; - try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - if(!is_null($result)) { - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'); - while( $row = $result->fetchRow()) { - try { - $stmt->execute(array($row['id'])); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - } - } - - /** - * @brief Delete category/object relations from the db - * @param array $ids The ids of the objects - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean Returns false on error. - */ - public function purgeObjects(array $ids, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(count($ids) === 0) { - // job done ;) - return true; - } - $updates = $ids; - try { - $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; - $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; - $query .= 'AND `type`= ?'; - $updates[] = $type; - $stmt = OCP\DB::prepare($query); - $result = $stmt->execute($updates); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Get favorites for an object type - * - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns array An array of object ids. - */ - public function getFavorites($type = null) { - $type = is_null($type) ? $this->type : $type; - - try { - return $this->idsForCategory(self::CATEGORY_FAVORITE); - } catch(Exception $e) { - // No favorites - return array(); - } - } - - /** - * Add an object to favorites - * - * @param int $objid The id of the object - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function addToFavorites($objid, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(!$this->hasCategory(self::CATEGORY_FAVORITE)) { - $this->add(self::CATEGORY_FAVORITE, true); - } - return $this->addToCategory($objid, self::CATEGORY_FAVORITE, $type); - } - - /** - * Remove an object from favorites - * - * @param int $objid The id of the object - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function removeFromFavorites($objid, $type = null) { - $type = is_null($type) ? $this->type : $type; - return $this->removeFromCategory($objid, self::CATEGORY_FAVORITE, $type); - } - - /** - * @brief Creates a category/object relation. - * @param int $objid The id of the object - * @param int|string $category The id or name of the category - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean Returns false on database error. - */ - public function addToCategory($objid, $category, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(is_string($category) && !is_numeric($category)) { - $category = trim($category); - if(!$this->hasCategory($category)) { - $this->add($category, true); - } - $categoryid = $this->array_searchi($category, $this->categories); - } else { - $categoryid = $category; - } - try { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $objid, - 'categoryid' => $categoryid, - 'type' => $type, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * @brief Delete single category/object relation from the db - * @param int $objid The id of the object - * @param int|string $category The id or name of the category - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function removeFromCategory($objid, $category, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(is_string($category) && !is_numeric($category)) { - $category = trim($category); - $categoryid = $this->array_searchi($category, $this->categories); - } else { - $categoryid = $category; - } - - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; - OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type, - OCP\Util::DEBUG); - $stmt = OCP\DB::prepare($sql); - $stmt->execute(array($objid, $categoryid, $type)); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * @brief Delete categories from the db and from all the vobject supplied - * @param $names An array of categories to delete - * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. - */ - public function delete($names, array &$objects=null) { - if(!is_array($names)) { - $names = array($names); - } - - $names = array_map('trim', $names); - - OC_Log::write('core', __METHOD__ . ', before: ' - . print_r($this->categories, true), OC_Log::DEBUG); - foreach($names as $name) { - $id = null; - OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); - if($this->hasCategory($name)) { - $id = $this->array_searchi($name, $this->categories); - unset($this->categories[$id]); - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' - . '`uid` = ? AND `type` = ? AND `category` = ?'); - $result = $stmt->execute(array($this->user, $this->type, $name)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - } - if(!is_null($id) && $id !== false) { - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'; - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($id)); - if (OC_DB::isError($result)) { - OC_Log::write('core', - __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), - OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - } - } - OC_Log::write('core', __METHOD__.', after: ' - . print_r($this->categories, true), OC_Log::DEBUG); - if(!is_null($objects)) { - foreach($objects as $key=>&$value) { - $vobject = OC_VObject::parse($value[1]); - if(!is_null($vobject)) { - $object = null; - $componentname = ''; - if (isset($vobject->VEVENT)) { - $object = $vobject->VEVENT; - $componentname = 'VEVENT'; - } else - if (isset($vobject->VTODO)) { - $object = $vobject->VTODO; - $componentname = 'VTODO'; - } else - if (isset($vobject->VJOURNAL)) { - $object = $vobject->VJOURNAL; - $componentname = 'VJOURNAL'; - } else { - $object = $vobject; - } - $categories = $object->getAsArray('CATEGORIES'); - foreach($names as $name) { - $idx = $this->array_searchi($name, $categories); - if($idx !== false) { - OC_Log::write('core', __METHOD__ - .', unsetting: ' - . $categories[$this->array_searchi($name, $categories)], - OC_Log::DEBUG); - unset($categories[$this->array_searchi($name, $categories)]); - } - } - - $object->setString('CATEGORIES', implode(',', $categories)); - if($vobject !== $object) { - $vobject[$componentname] = $object; - } - $value[1] = $vobject->serialize(); - $objects[$key] = $value; - } else { - OC_Log::write('core', __METHOD__ - .', unable to parse. ID: ' . $value[0] . ', ' - . substr($value[1], 0, 50) . '(...)', OC_Log::DEBUG); - } - } - } - } - - // case-insensitive in_array - private function in_arrayi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return in_array(strtolower($needle), array_map('strtolower', $haystack)); - } - - // case-insensitive array_search - private function array_searchi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return array_search(strtolower($needle), array_map('strtolower', $haystack)); - } -} diff --git a/tests/lib/tags.php b/tests/lib/tags.php new file mode 100644 index 00000000000..06baebc0af7 --- /dev/null +++ b/tests/lib/tags.php @@ -0,0 +1,133 @@ +. +* +*/ + +class Test_Tags extends PHPUnit_Framework_TestCase { + + protected $objectType; + protected $user; + protected $backupGlobals = FALSE; + + public function setUp() { + + OC_User::clearBackends(); + OC_User::useBackend('dummy'); + $this->user = uniqid('user_'); + $this->objectType = uniqid('type_'); + OC_User::createUser($this->user, 'pass'); + OC_User::setUserId($this->user); + + } + + public function tearDown() { + //$query = OC_DB::prepare('DELETE FROM `*PREFIX*vcategories` WHERE `item_type` = ?'); + //$query->execute(array('test')); + } + + public function testInstantiateWithDefaults() { + $defaultTags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertEquals(4, count($tagMgr->tags())); + } + + public function testAddTags() { + $tags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($tags as $tag) { + $result = $tagMgr->add($tag); + $this->assertTrue((bool)$result); + } + + $this->assertFalse($tagMgr->add('Family')); + $this->assertFalse($tagMgr->add('fAMILY')); + + $this->assertEquals(4, count($tagMgr->tags())); + } + + public function testdeleteTags() { + $defaultTags = array('Friends', 'Family', 'Work', 'Other'); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertEquals(4, count($tagMgr->tags())); + + $tagMgr->delete('family'); + $this->assertEquals(3, count($tagMgr->tags())); + + $tagMgr->delete(array('Friends', 'Work', 'Other')); + $this->assertEquals(0, count($tagMgr->tags())); + + } + + public function testRenameTag() { + $defaultTags = array('Friends', 'Family', 'Wrok', 'Other'); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertTrue($tagMgr->rename('Wrok', 'Work')); + $this->assertTrue($tagMgr->hasTag('Work')); + $this->assertFalse($tagMgr->hastag('Wrok')); + $this->assertFalse($tagMgr->rename('Wrok', 'Work')); + + } + + public function testTagAs() { + $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($objids as $id) { + $tagMgr->tagAs($id, 'Family'); + } + + $this->assertEquals(1, count($tagMgr->tags())); + $this->assertEquals(9, count($tagMgr->idsForTag('Family'))); + } + + /** + * @depends testTagAs + */ + public function testUnTag() { + $objIds = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + // Is this "legal"? + $this->testTagAs(); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($objIds as $id) { + $this->assertTrue(in_array($id, $tagMgr->idsForTag('Family'))); + $tagMgr->unTag($id, 'Family'); + $this->assertFalse(in_array($id, $tagMgr->idsForTag('Family'))); + } + + $this->assertEquals(1, count($tagMgr->tags())); + $this->assertEquals(0, count($tagMgr->idsForTag('Family'))); + } + +} diff --git a/tests/lib/vcategories.php b/tests/lib/vcategories.php deleted file mode 100644 index df5f600f20d..00000000000 --- a/tests/lib/vcategories.php +++ /dev/null @@ -1,128 +0,0 @@ -. -* -*/ - -//require_once("../lib/template.php"); - -class Test_VCategories extends PHPUnit_Framework_TestCase { - - protected $objectType; - protected $user; - protected $backupGlobals = FALSE; - - public function setUp() { - - OC_User::clearBackends(); - OC_User::useBackend('dummy'); - $this->user = uniqid('user_'); - $this->objectType = uniqid('type_'); - OC_User::createUser($this->user, 'pass'); - OC_User::setUserId($this->user); - - } - - public function tearDown() { - //$query = OC_DB::prepare('DELETE FROM `*PREFIX*vcategories` WHERE `item_type` = ?'); - //$query->execute(array('test')); - } - - public function testInstantiateWithDefaults() { - $defcategories = array('Friends', 'Family', 'Work', 'Other'); - - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - - $this->assertEquals(4, count($catmgr->categories())); - } - - public function testAddCategories() { - $categories = array('Friends', 'Family', 'Work', 'Other'); - - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($categories as $category) { - $result = $catmgr->add($category); - $this->assertTrue((bool)$result); - } - - $this->assertFalse($catmgr->add('Family')); - $this->assertFalse($catmgr->add('fAMILY')); - - $this->assertEquals(4, count($catmgr->categories())); - } - - public function testdeleteCategories() { - $defcategories = array('Friends', 'Family', 'Work', 'Other'); - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - $this->assertEquals(4, count($catmgr->categories())); - - $catmgr->delete('family'); - $this->assertEquals(3, count($catmgr->categories())); - - $catmgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($catmgr->categories())); - - } - - public function testrenameCategory() { - $defcategories = array('Friends', 'Family', 'Wrok', 'Other'); - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - - $this->assertTrue($catmgr->rename('Wrok', 'Work')); - $this->assertTrue($catmgr->hasCategory('Work')); - $this->assertFalse($catmgr->hasCategory('Wrok')); - $this->assertFalse($catmgr->rename('Wrok', 'Work')); - - } - - public function testAddToCategory() { - $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($objids as $id) { - $catmgr->addToCategory($id, 'Family'); - } - - $this->assertEquals(1, count($catmgr->categories())); - $this->assertEquals(9, count($catmgr->idsForCategory('Family'))); - } - - /** - * @depends testAddToCategory - */ - public function testRemoveFromCategory() { - $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - - // Is this "legal"? - $this->testAddToCategory(); - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($objids as $id) { - $this->assertTrue(in_array($id, $catmgr->idsForCategory('Family'))); - $catmgr->removeFromCategory($id, 'Family'); - $this->assertFalse(in_array($id, $catmgr->idsForCategory('Family'))); - } - - $this->assertEquals(1, count($catmgr->categories())); - $this->assertEquals(0, count($catmgr->idsForCategory('Family'))); - } - -} -- cgit v1.2.3 From b63acdb12599c4ad062d7509c0079fad0b1ccfa2 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 18 Sep 2013 22:49:09 +0200 Subject: fixing namespaces and rename hasCategory to hasTag --- lib/tags.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/tags.php b/lib/tags.php index 4aafff8e1bb..3320d9ea1a8 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -113,7 +113,7 @@ class Tags implements \OCP\ITags { $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ?'; try { - $stmt = OCP\DB::prepare($sql); + $stmt = \OCP\DB::prepare($sql); $result = $stmt->execute(array($this->user, $this->type)); if (\OCP\DB::isError($result)) { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); @@ -191,7 +191,7 @@ class Tags implements \OCP\ITags { $stmt = \OCP\DB::prepare($sql); $result = $stmt->execute(array($tagId)); if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; } } catch(\Exception $e) { @@ -381,7 +381,7 @@ class Tags implements \OCP\ITags { . 'WHERE `uid` = ?'); $result = $stmt->execute(array($arguments['uid'])); if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); } } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), @@ -409,12 +409,12 @@ class Tags implements \OCP\ITags { $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` ' . 'WHERE `uid` = ?'); $result = $stmt->execute(array($arguments['uid'])); - if (OCP\DB::isError($result)) { + if (\OCP\DB::isError($result)) { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); } } catch(\Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); } } @@ -435,7 +435,7 @@ class Tags implements \OCP\ITags { $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; $query .= 'AND `type`= ?'; $updates[] = $this->type; - $stmt = OCP\DB::prepare($query); + $stmt = \OCP\DB::prepare($query); $result = $stmt->execute($updates); if (\OCP\DB::isError($result)) { \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); @@ -471,7 +471,7 @@ class Tags implements \OCP\ITags { * @return boolean */ public function addToFavorites($objid) { - if(!$this->hasCategory(self::TAG_FAVORITE)) { + if(!$this->hasTag(self::TAG_FAVORITE)) { $this->add(self::TAG_FAVORITE, true); } return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); @@ -574,7 +574,7 @@ class Tags implements \OCP\ITags { . '`uid` = ? AND `type` = ? AND `category` = ?'); $result = $stmt->execute(array($this->user, $this->type, $name)); if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); } } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' -- cgit v1.2.3 From 1bbeb12e2e8acc47b94c23d6a17332fb45c2a97e Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 19 Sep 2013 11:27:13 +0200 Subject: Updated method names and added a few more tests. --- lib/public/itags.php | 6 +++--- lib/tags.php | 12 +++++------ tests/lib/tags.php | 59 ++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/lib/public/itags.php b/lib/public/itags.php index 047d4f5f40b..12643400548 100644 --- a/lib/public/itags.php +++ b/lib/public/itags.php @@ -65,7 +65,7 @@ interface ITags { * * @returns array */ - public function tags(); + public function getTags(); /** * Get the a list if items tagged with $tag. @@ -75,7 +75,7 @@ interface ITags { * @param string|integer $tag Tag id or name. * @return array An array of object ids or false on error. */ - public function idsForTag($tag); + public function getIdsForTag($tag); /** * Checks whether a tag is already saved. @@ -111,7 +111,7 @@ interface ITags { * @param int|null $id int Optional object id to add to this|these tag(s) * @return bool Returns false on error. */ - public function addMulti($names, $sync=false, $id = null); + public function addMultiple($names, $sync=false, $id = null); /** * Delete tag/object relations from the db diff --git a/lib/tags.php b/lib/tags.php index 3320d9ea1a8..2eaa603c1a3 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -96,7 +96,7 @@ class Tags implements \OCP\ITags { } if(count($defaultTags) > 0 && count($this->tags) === 0) { - $this->addMulti($defaultTags, true); + $this->addMultiple($defaultTags, true); } \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), \OCP\Util::DEBUG); @@ -119,7 +119,7 @@ class Tags implements \OCP\ITags { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; } - return ($result->numRows() === 0); + return ((int)$result->numRows() === 0); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR); @@ -138,7 +138,7 @@ class Tags implements \OCP\ITags { * * @return array */ - public function tags() { + public function getTags() { if(!count($this->tags)) { return array(); } @@ -167,7 +167,7 @@ class Tags implements \OCP\ITags { * @param string|integer $tag Tag id or name. * @return array An array of object ids or false on error. */ - public function idsForTag($tag) { + public function getIdsForTag($tag) { $result = null; if(is_numeric($tag)) { $tagId = $tag; @@ -293,7 +293,7 @@ class Tags implements \OCP\ITags { * @param int|null $id int Optional object id to add to this|these tag(s) * @return bool Returns false on error. */ - public function addMulti($names, $sync=false, $id = null) { + public function addMultiple($names, $sync=false, $id = null) { if(!is_array($names)) { $names = array($names); } @@ -456,7 +456,7 @@ class Tags implements \OCP\ITags { */ public function getFavorites() { try { - return $this->idsForTag(self::TAG_FAVORITE); + return $this->getIdsForTag(self::TAG_FAVORITE); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR); diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 06baebc0af7..16a03f5645a 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -48,7 +48,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr = new OC\Tags($this->user); $tagMgr->loadTagsFor($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); } public function testAddTags() { @@ -65,7 +65,37 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertFalse($tagMgr->add('Family')); $this->assertFalse($tagMgr->add('fAMILY')); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); + } + + public function testAddMultiple() { + $tags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($tags as $tag) { + $this->assertFalse($tagMgr->hasTag($tag)); + } + + $result = $tagMgr->addMultiple($tags); + $this->assertTrue((bool)$result); + + foreach($tags as $tag) { + $this->assertTrue($tagMgr->hasTag($tag)); + } + + $this->assertEquals(4, count($tagMgr->getTags())); + } + + public function testIsEmpty() { + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + $this->assertEquals(0, count($tagMgr->getTags())); + $this->assertTrue($tagMgr->isEmpty()); + $tagMgr->add('Tag'); + $this->assertFalse($tagMgr->isEmpty()); } public function testdeleteTags() { @@ -73,13 +103,13 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr = new OC\Tags($this->user); $tagMgr->loadTagsFor($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); $tagMgr->delete('family'); - $this->assertEquals(3, count($tagMgr->tags())); + $this->assertEquals(3, count($tagMgr->getTags())); $tagMgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($tagMgr->tags())); + $this->assertEquals(0, count($tagMgr->getTags())); } @@ -105,8 +135,8 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr->tagAs($id, 'Family'); } - $this->assertEquals(1, count($tagMgr->tags())); - $this->assertEquals(9, count($tagMgr->idsForTag('Family'))); + $this->assertEquals(1, count($tagMgr->getTags())); + $this->assertEquals(9, count($tagMgr->getIdsForTag('Family'))); } /** @@ -121,13 +151,20 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr->loadTagsFor($this->objectType); foreach($objIds as $id) { - $this->assertTrue(in_array($id, $tagMgr->idsForTag('Family'))); + $this->assertTrue(in_array($id, $tagMgr->getIdsForTag('Family'))); $tagMgr->unTag($id, 'Family'); - $this->assertFalse(in_array($id, $tagMgr->idsForTag('Family'))); + $this->assertFalse(in_array($id, $tagMgr->getIdsForTag('Family'))); } - $this->assertEquals(1, count($tagMgr->tags())); - $this->assertEquals(0, count($tagMgr->idsForTag('Family'))); + $this->assertEquals(1, count($tagMgr->getTags())); + $this->assertEquals(0, count($tagMgr->getIdsForTag('Family'))); + } + + public function testFavorite() { + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + $this->assertTrue($tagMgr->addToFavorites(1)); + $this->assertTrue($tagMgr->removeFromFavorites(1)); } } -- cgit v1.2.3 From 8fab9eef28d2146c2c65f7e7f1aa826216915301 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 19 Sep 2013 13:55:45 +0200 Subject: Add another test. --- tests/lib/tags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 16a03f5645a..92a96a14772 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -94,7 +94,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertEquals(0, count($tagMgr->getTags())); $this->assertTrue($tagMgr->isEmpty()); - $tagMgr->add('Tag'); + $this->assertNotEquals(false, $tagMgr->add('Tag')); $this->assertFalse($tagMgr->isEmpty()); } -- cgit v1.2.3 From 8a02afd87ae1e9a8d223f20ca2df35145a16ce74 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 13:27:43 +0200 Subject: Added more error checking in add() --- lib/tags.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/tags.php b/lib/tags.php index 2eaa603c1a3..e2e1a83dd94 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -233,17 +233,25 @@ class Tags implements \OCP\ITags { return false; } try { - \OCP\DB::insertIfNotExist(self::TAG_TABLE, + $result = \OCP\DB::insertIfNotExist( + self::TAG_TABLE, array( 'uid' => $this->user, 'type' => $this->type, 'category' => $name, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); + ) + ); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; + } elseif((int)$result === 0) { + \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } $id = \OCP\DB::insertid(self::TAG_TABLE); \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); $this->tags[$id] = $name; -- cgit v1.2.3 From be402fab53bb4eb3ce027ef9d6edb089e356a820 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 13:29:21 +0200 Subject: Forgot to return false if add() didn't add anything. --- lib/tags.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tags.php b/lib/tags.php index e2e1a83dd94..955eb3cd363 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -246,6 +246,7 @@ class Tags implements \OCP\ITags { return false; } elseif((int)$result === 0) { \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); + return false; } } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), -- cgit v1.2.3 From 60bff6c5896c22b31ee7864fa48026a1de5ce3fb Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 15:52:06 +0200 Subject: Use fetchOne() instead of numRows() when doing a COUNT(*). --- lib/tags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tags.php b/lib/tags.php index 955eb3cd363..ff9f35ebc9e 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -119,7 +119,7 @@ class Tags implements \OCP\ITags { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; } - return ((int)$result->numRows() === 0); + return ((int)$result->fetchOne() === 0); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR); -- cgit v1.2.3 From f022ea752ddd86feccaaf5f1f83f808fd6df5e20 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 15:52:50 +0200 Subject: Moar tests. --- tests/lib/tags.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 92a96a14772..75db9f50f72 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -59,13 +59,14 @@ class Test_Tags extends PHPUnit_Framework_TestCase { foreach($tags as $tag) { $result = $tagMgr->add($tag); + $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); $this->assertTrue((bool)$result); } $this->assertFalse($tagMgr->add('Family')); $this->assertFalse($tagMgr->add('fAMILY')); - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertCount(4, $tagMgr->getTags(), 'Wrong number of added tags'); } public function testAddMultiple() { @@ -85,7 +86,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertTrue($tagMgr->hasTag($tag)); } - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertCount(4, $tagMgr->getTags(), 'Not all tags added'); } public function testIsEmpty() { @@ -94,7 +95,10 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertEquals(0, count($tagMgr->getTags())); $this->assertTrue($tagMgr->isEmpty()); - $this->assertNotEquals(false, $tagMgr->add('Tag')); + + $result = $tagMgr->add('Tag'); + $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); + $this->assertNotEquals(false, $result, 'add() returned false'); $this->assertFalse($tagMgr->isEmpty()); } -- cgit v1.2.3 From 4d3e7fa78a3c4692a7dc8587dd6e126866fc9870 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 12:34:10 +0200 Subject: Add getUserFolder/getAppFolder to Server. --- lib/public/iservercontainer.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 4478a4e8a6c..dcf8c162e6f 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -86,6 +86,20 @@ interface IServerContainer { */ function getCache(); + /** + * Returns a view to ownCloud's files folder + * + * @return \OCP\Files\Folder + */ + function getUserFolder(); + + /** + * Returns an app-specific view in ownClouds data directory + * + * @return \OCP\Files\Folder + */ + function getAppFolder(); + /** * Returns the current session * -- cgit v1.2.3 From f2de5a34eff78add366b7a89c93a8128a097996f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 14:25:12 +0200 Subject: Don't try to be clever --- lib/server.php | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/server.php b/lib/server.php index 804af6b0eac..dcfd0a2db99 100644 --- a/lib/server.php +++ b/lib/server.php @@ -148,6 +148,42 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('RootFolder'); } + /** + * Returns a view to ownCloud's files folder + * + * @return \OCP\Files\Folder + */ + function getUserFolder() { + + $dir = '/files'; + $root = $this->getRootFolder(); + $folder = null; + if(!$root->nodeExists($dir)) { + $folder = $root->newFolder($dir); + } else { + $folder = $root->get($dir); + } + return $folder; + } + + /** + * Returns an app-specific view in ownClouds data directory + * + * @return \OCP\Files\Folder + */ + function getAppFolder() { + + $dir = '/' . \OC_App::getCurrentApp(); + $root = $this->getRootFolder(); + $folder = null; + if(!$root->nodeExists($dir)) { + $folder = $root->newFolder($dir); + } else { + $folder = $root->get($dir); + } + return $folder; + } + /** * @return \OC\User\Manager */ -- cgit v1.2.3 From 8c469394e61b0f13c4e111a7804e27273cf62458 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 24 Sep 2013 00:12:23 +0200 Subject: Remove duplicate method definitions --- lib/public/iservercontainer.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index d3ee5d15dcc..6d291321957 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -75,6 +75,7 @@ interface IServerContainer { * @return \OCP\Files\Folder */ function getAppFolder(); + /** * Returns the user session * @@ -99,20 +100,6 @@ interface IServerContainer { */ function getCache(); - /** - * Returns a view to ownCloud's files folder - * - * @return \OCP\Files\Folder - */ - function getUserFolder(); - - /** - * Returns an app-specific view in ownClouds data directory - * - * @return \OCP\Files\Folder - */ - function getAppFolder(); - /** * Returns the current session * -- cgit v1.2.3 From 235517f111a6d570e43cff1cd3701553412fc1a3 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 19 Sep 2013 21:37:52 +0200 Subject: clear permissions cache when scanning a file --- lib/files/cache/scanner.php | 15 ++++++++++++--- tests/lib/files/cache/permissions.php | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index a986c1ca725..af819c47c61 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -36,6 +36,11 @@ class Scanner extends BasicEmitter { */ private $cache; + /** + * @var \OC\Files\Cache\Permissions $permissionsCache + */ + private $permissionsCache; + const SCAN_RECURSIVE = true; const SCAN_SHALLOW = false; @@ -46,6 +51,7 @@ class Scanner extends BasicEmitter { $this->storage = $storage; $this->storageId = $this->storage->getId(); $this->cache = $storage->getCache(); + $this->permissionsCache = $storage->getPermissionsCache(); } /** @@ -96,7 +102,11 @@ class Scanner extends BasicEmitter { } } $newData = $data; - if ($reuseExisting and $cacheData = $this->cache->get($file)) { + $cacheData = $this->cache->get($file); + if ($cacheData) { + $this->permissionsCache->remove($cacheData['fileid']); + } + if ($reuseExisting and $cacheData) { // prevent empty etag $etag = $cacheData['etag']; $propagateETagChange = false; @@ -104,7 +114,6 @@ class Scanner extends BasicEmitter { $etag = $data['etag']; $propagateETagChange = true; } - // only reuse data if the file hasn't explicitly changed if (isset($data['mtime']) && isset($cacheData['mtime']) && $data['mtime'] === $cacheData['mtime']) { if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { @@ -182,7 +191,7 @@ class Scanner extends BasicEmitter { $newChildren = array(); if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) { \OC_DB::beginTransaction(); - if(is_resource($dh)) { + if (is_resource($dh)) { while (($file = readdir($dh)) !== false) { $child = ($path) ? $path . '/' . $file : $file; if (!Filesystem::isIgnoredDir($file)) { diff --git a/tests/lib/files/cache/permissions.php b/tests/lib/files/cache/permissions.php index 7e6e11e2eb2..4b284c2c8e2 100644 --- a/tests/lib/files/cache/permissions.php +++ b/tests/lib/files/cache/permissions.php @@ -8,6 +8,8 @@ namespace Test\Files\Cache; +use OC\Files\Storage\Temporary; + class Permissions extends \PHPUnit_Framework_TestCase { /*** * @var \OC\Files\Cache\Permissions $permissionsCache @@ -55,4 +57,19 @@ class Permissions extends \PHPUnit_Framework_TestCase { $this->permissionsCache->removeMultiple($ids, $user); } + + public function testUpdatePermissionsOnRescan() { + $storage = new Temporary(array()); + $scanner = $storage->getScanner(); + $cache = $storage->getCache(); + $permissionsCache = $storage->getPermissionsCache(); + + $storage->file_put_contents('foo.txt', 'bar'); + $scanner->scan(''); + $id = $cache->getId('foo.txt'); + $permissionsCache->set($id, 'test', 1); + + $scanner->scan(''); + $this->assertEquals(-1, $permissionsCache->get($id, 'test')); + } } -- cgit v1.2.3 From 21299745846eaa87988dcc5acd6f5604b363b03e Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 24 Sep 2013 00:59:23 +0200 Subject: Do not recheck $cacheData. Move if($reuseExisting) under if($cacheData). --- lib/files/cache/scanner.php | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index af819c47c61..96f84609cf2 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -105,39 +105,39 @@ class Scanner extends BasicEmitter { $cacheData = $this->cache->get($file); if ($cacheData) { $this->permissionsCache->remove($cacheData['fileid']); - } - if ($reuseExisting and $cacheData) { - // prevent empty etag - $etag = $cacheData['etag']; - $propagateETagChange = false; - if (empty($etag)) { - $etag = $data['etag']; - $propagateETagChange = true; - } - // only reuse data if the file hasn't explicitly changed - if (isset($data['mtime']) && isset($cacheData['mtime']) && $data['mtime'] === $cacheData['mtime']) { - if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { - $data['size'] = $cacheData['size']; + if ($reuseExisting) { + // prevent empty etag + $etag = $cacheData['etag']; + $propagateETagChange = false; + if (empty($etag)) { + $etag = $data['etag']; + $propagateETagChange = true; } - if ($reuseExisting & self::REUSE_ETAG) { - $data['etag'] = $etag; - if ($propagateETagChange) { - $parent = $file; - while ($parent !== '') { - $parent = dirname($parent); - if ($parent === '.') { - $parent = ''; + // only reuse data if the file hasn't explicitly changed + if (isset($data['mtime']) && isset($cacheData['mtime']) && $data['mtime'] === $cacheData['mtime']) { + if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { + $data['size'] = $cacheData['size']; + } + if ($reuseExisting & self::REUSE_ETAG) { + $data['etag'] = $etag; + if ($propagateETagChange) { + $parent = $file; + while ($parent !== '') { + $parent = dirname($parent); + if ($parent === '.') { + $parent = ''; + } + $parentCacheData = $this->cache->get($parent); + $this->cache->update($parentCacheData['fileid'], array( + 'etag' => $this->storage->getETag($parent), + )); } - $parentCacheData = $this->cache->get($parent); - $this->cache->update($parentCacheData['fileid'], array( - 'etag' => $this->storage->getETag($parent), - )); } } } + // Only update metadata that has changed + $newData = array_diff($data, $cacheData); } - // Only update metadata that has changed - $newData = array_diff($data, $cacheData); } if (!empty($newData)) { $this->cache->put($file, $newData); -- cgit v1.2.3 From 00c998c5bb611ea775f2b1a294ef4f2029a52c89 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Mon, 23 Sep 2013 21:08:58 -0400 Subject: fixing typo Typo in comment "feature" => "future" --- cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cron.php b/cron.php index d39800c8849..8e1a3376d53 100644 --- a/cron.php +++ b/cron.php @@ -79,7 +79,7 @@ try { // We call ownCloud from the CLI (aka cron) if ($appmode != 'cron') { - // Use cron in feature! + // Use cron in future! OC_BackgroundJob::setExecutionType('cron'); } -- cgit v1.2.3 From cd2421c7ee04e6d46481a1d0ae36387757b204fe Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 24 Sep 2013 10:37:58 +0200 Subject: adding PHPDoc comments to getBackend ensure getChildren() is called on an instance of Share_Backend_Collection --- apps/files_sharing/lib/cache.php | 15 ++++++++++----- lib/public/share.php | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 51e8713b97a..123268e240a 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -20,6 +20,7 @@ */ namespace OC\Files\Cache; +use OCP\Share_Backend_Collection; /** * Metadata cache for shared files @@ -320,13 +321,17 @@ class Shared_Cache extends Cache { public function getAll() { $ids = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL); $folderBackend = \OCP\Share::getBackend('folder'); - foreach ($ids as $file) { - $children = $folderBackend->getChildren($file); - foreach ($children as $child) { - $ids[] = (int)$child['source']; + if ($folderBackend instanceof Share_Backend_Collection) { + foreach ($ids as $file) { + /** @var $folderBackend Share_Backend_Collection */ + $children = $folderBackend->getChildren($file); + foreach ($children as $child) { + $ids[] = (int)$child['source']; + } + } - } + return $ids; } diff --git a/lib/public/share.php b/lib/public/share.php index 10922965ea8..41f5ccbf40d 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -745,8 +745,8 @@ class Share { /** * @brief Get the backend class for the specified item type - * @param string Item type - * @return Sharing backend object + * @param string $itemType + * @return Share_Backend */ public static function getBackend($itemType) { if (isset(self::$backends[$itemType])) { -- cgit v1.2.3 From 31d2048eb83d60007183cec43a54d7a112d7a3b2 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 24 Sep 2013 11:00:08 +0200 Subject: add blacklist to txt preview backend --- lib/preview/txt.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/preview/txt.php b/lib/preview/txt.php index a487330691e..77e728eb364 100644 --- a/lib/preview/txt.php +++ b/lib/preview/txt.php @@ -9,11 +9,21 @@ namespace OC\Preview; class TXT extends Provider { + private static $blacklist = array( + 'text/calendar', + 'text/vcard', + ); + public function getMimeType() { return '/text\/.*/'; } public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $mimetype = $fileview->getMimeType($path); + if(in_array($mimetype, self::$blacklist)) { + return false; + } + $content = $fileview->fopen($path, 'r'); $content = stream_get_contents($content); -- cgit v1.2.3 From b693b5085c3da7a3242c1efe9251c2f579027d76 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 24 Sep 2013 13:08:55 +0200 Subject: don't remember login if the encrypion app is enabled because the user needs to log-in again in order to decrypt his private key with his password --- core/templates/login.php | 3 ++- lib/base.php | 1 + lib/util.php | 13 +++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/core/templates/login.php b/core/templates/login.php index ee761f0aa52..3e736f164ec 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -32,9 +32,10 @@ t('Lost your password?')); ?> - + + diff --git a/lib/base.php b/lib/base.php index 395d8486a5e..b4e12bc7ebb 100644 --- a/lib/base.php +++ b/lib/base.php @@ -760,6 +760,7 @@ class OC { || !isset($_COOKIE["oc_token"]) || !isset($_COOKIE["oc_username"]) || !$_COOKIE["oc_remember_login"] + || OC_App::isEnabled('files_encryption') ) { return false; } diff --git a/lib/util.php b/lib/util.php index 41f5f1d16be..ef42ff2aea9 100755 --- a/lib/util.php +++ b/lib/util.php @@ -414,10 +414,10 @@ class OC_Util { $encryptedFiles = true; } } - + return $encryptedFiles; } - + /** * @brief Check for correct file permissions of data directory * @paran string $dataDirectory @@ -467,6 +467,7 @@ class OC_Util { } $parameters['alt_login'] = OC_App::getAlternativeLogIns(); + $parameters['encryption_enabled'] = OC_App::isEnabled('files_encryption'); OC_Template::printGuestPage("", "login", $parameters); } @@ -654,16 +655,16 @@ class OC_Util { } return $value; } - + /** * @brief Public function to encode url parameters * * This function is used to encode path to file before output. * Encoding is done according to RFC 3986 with one exception: - * Character '/' is preserved as is. + * Character '/' is preserved as is. * * @param string $component part of URI to encode - * @return string + * @return string */ public static function encodePath($component) { $encoded = rawurlencode($component); @@ -810,7 +811,7 @@ class OC_Util { } } } - + /** * @brief Check if the connection to the internet is disabled on purpose * @return bool -- cgit v1.2.3 From ee1f627155cad4153f3da3160ca6040c137841d3 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 24 Sep 2013 13:26:12 +0200 Subject: adding privilege check on move and rename operations --- lib/connector/sabre/node.php | 11 +++++++++++ lib/connector/sabre/objecttree.php | 24 +++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php index 0bffa58af78..29b7f9e53a5 100644 --- a/lib/connector/sabre/node.php +++ b/lib/connector/sabre/node.php @@ -78,6 +78,11 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr */ public function setName($name) { + // rename is only allowed if the update privilege is granted + if (!\OC\Files\Filesystem::isUpdatable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path); list(, $newName) = Sabre_DAV_URLUtil::splitPath($name); @@ -135,6 +140,12 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * Even if the modification time is set to a custom value the access time is set to now. */ public function touch($mtime) { + + // touch is only allowed if the update privilege is granted + if (!\OC\Files\Filesystem::isUpdatable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + \OC\Files\Filesystem::touch($this->path, $mtime); } diff --git a/lib/connector/sabre/objecttree.php b/lib/connector/sabre/objecttree.php index acff45ed5e2..7accf98c8e1 100644 --- a/lib/connector/sabre/objecttree.php +++ b/lib/connector/sabre/objecttree.php @@ -64,7 +64,29 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { list($sourceDir,) = \Sabre_DAV_URLUtil::splitPath($sourcePath); list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destinationPath); - Filesystem::rename($sourcePath, $destinationPath); + // check update privileges + if ($sourceDir === $destinationDir) { + // for renaming it's enough to check if the sourcePath can be updated + if (!\OC\Files\Filesystem::isUpdatable($sourcePath)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + } else { + // for a full move we need update privileges on sourcePath and sourceDir as well as destinationDir + if (!\OC\Files\Filesystem::isUpdatable($sourcePath)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + if (!\OC\Files\Filesystem::isUpdatable($sourceDir)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + if (!\OC\Files\Filesystem::isUpdatable($destinationDir)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + } + + $renameOkay = Filesystem::rename($sourcePath, $destinationPath); + if (!$renameOkay) { + throw new \Sabre_DAV_Exception_Forbidden(''); + } $this->markDirty($sourceDir); $this->markDirty($destinationDir); -- cgit v1.2.3 From 52f1d5856dfaa9186a05d529674c2dbab9cc90b7 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 24 Sep 2013 13:26:51 +0200 Subject: add test data for cal and contact preview --- tests/data/testcal.ics | 13 +++++++++++++ tests/data/testcontact.vcf | 6 ++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/data/testcal.ics create mode 100644 tests/data/testcontact.vcf diff --git a/tests/data/testcal.ics b/tests/data/testcal.ics new file mode 100644 index 00000000000..e05f01ba1c2 --- /dev/null +++ b/tests/data/testcal.ics @@ -0,0 +1,13 @@ +BEGIN:VCALENDAR +PRODID:-//some random cal software//EN +VERSION:2.0 +BEGIN:VEVENT +CREATED:20130102T120000Z +LAST-MODIFIED:20130102T120000Z +DTSTAMP:20130102T120000Z +UID:f106ecdf-c716-43ef-9d94-4e6f19f2fcfb +SUMMARY:a test cal file +DTSTART;VALUE=DATE:20130101 +DTEND;VALUE=DATE:20130102 +END:VEVENT +END:VCALENDAR \ No newline at end of file diff --git a/tests/data/testcontact.vcf b/tests/data/testcontact.vcf new file mode 100644 index 00000000000..2af963d6916 --- /dev/null +++ b/tests/data/testcontact.vcf @@ -0,0 +1,6 @@ +BEGIN:VCARD +VERSION:3.0 +PRODID:-//some random contact software//EN +N:def;abc;;; +FN:abc def +END:VCARD \ No newline at end of file -- cgit v1.2.3 From d101ff42f16ef7288b40666eba20c69621481ea4 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Mon, 16 Sep 2013 14:15:35 +0200 Subject: User: move checkPassword from User to Manager to not break API --- lib/public/user.php | 2 +- lib/user.php | 14 +++++--------- lib/user/http.php | 6 +++++- lib/user/manager.php | 17 +++++++++++++++++ lib/user/session.php | 19 ++++++++++--------- lib/user/user.php | 18 ------------------ tests/lib/user/session.php | 32 ++++++++++---------------------- 7 files changed, 48 insertions(+), 60 deletions(-) diff --git a/lib/public/user.php b/lib/public/user.php index 23ff991642d..576a64d7048 100644 --- a/lib/public/user.php +++ b/lib/public/user.php @@ -102,7 +102,7 @@ class User { * @brief Check if the password is correct * @param $uid The username * @param $password The password - * @returns true/false + * @returns mixed username on success, false otherwise * * Check if the password is correct without logging in the user */ diff --git a/lib/user.php b/lib/user.php index 0f6f40aec9a..8868428ce24 100644 --- a/lib/user.php +++ b/lib/user.php @@ -416,16 +416,12 @@ class OC_User { * returns the user id or false */ public static function checkPassword($uid, $password) { - $user = self::getManager()->get($uid); - if ($user) { - if ($user->checkPassword($password)) { - return $user->getUID(); - } else { - return false; - } - } else { - return false; + $manager = self::getManager(); + $username = $manager->checkPassword($uid, $password); + if ($username !== false) { + return $manger->get($username); } + return false; } /** diff --git a/lib/user/http.php b/lib/user/http.php index 1e044ed4188..ea14cb57c93 100644 --- a/lib/user/http.php +++ b/lib/user/http.php @@ -79,7 +79,11 @@ class OC_User_HTTP extends OC_User_Backend { curl_close($ch); - return $status==200; + if($status == 200) { + return $uid; + } + + return false; } /** diff --git a/lib/user/manager.php b/lib/user/manager.php index 8dc9bfe2729..2de694a3d9f 100644 --- a/lib/user/manager.php +++ b/lib/user/manager.php @@ -118,6 +118,23 @@ class Manager extends PublicEmitter { return ($user !== null); } + /** + * Check if the password is valid for the user + * + * @param $loginname + * @param $password + * @return mixed the User object on success, false otherwise + */ + public function checkPassword($loginname, $password) { + foreach ($this->backends as $backend) { + $uid = $backend->checkPassword($loginname, $password); + if ($uid !== false) { + return $this->getUserObject($uid, $backend); + } + } + return null; + } + /** * search by user id * diff --git a/lib/user/session.php b/lib/user/session.php index 9a6c669e935..b5e9385234d 100644 --- a/lib/user/session.php +++ b/lib/user/session.php @@ -121,15 +121,16 @@ class Session implements Emitter { */ public function login($uid, $password) { $this->manager->emit('\OC\User', 'preLogin', array($uid, $password)); - $user = $this->manager->get($uid); - if ($user) { - $result = $user->checkPassword($password); - if ($result and $user->isEnabled()) { - $this->setUser($user); - $this->manager->emit('\OC\User', 'postLogin', array($user, $password)); - return true; - } else { - return false; + $user = $this->manager->checkPassword($uid, $password); + if($user !== false) { + if (!is_null($user)) { + if ($user->isEnabled()) { + $this->setUser($user); + $this->manager->emit('\OC\User', 'postLogin', array($user, $password)); + return true; + } else { + return false; + } } } else { return false; diff --git a/lib/user/user.php b/lib/user/user.php index 8115c43198c..e5f842944f1 100644 --- a/lib/user/user.php +++ b/lib/user/user.php @@ -105,24 +105,6 @@ class User { return !($result === false); } - /** - * Check if the password is valid for the user - * - * @param $password - * @return bool - */ - public function checkPassword($password) { - if ($this->backend->implementsActions(\OC_USER_BACKEND_CHECK_PASSWORD)) { - $result = $this->backend->checkPassword($this->uid, $password); - if ($result !== false) { - $this->uid = $result; - } - return !($result === false); - } else { - return false; - } - } - /** * Set the password of the user * diff --git a/tests/lib/user/session.php b/tests/lib/user/session.php index 274e9e2831e..e457a7bda30 100644 --- a/tests/lib/user/session.php +++ b/tests/lib/user/session.php @@ -61,10 +61,6 @@ class Session extends \PHPUnit_Framework_TestCase { $backend = $this->getMock('OC_User_Dummy'); $user = $this->getMock('\OC\User\User', array(), array('foo', $backend)); - $user->expects($this->once()) - ->method('checkPassword') - ->with('bar') - ->will($this->returnValue(true)); $user->expects($this->once()) ->method('isEnabled') ->will($this->returnValue(true)); @@ -73,8 +69,8 @@ class Session extends \PHPUnit_Framework_TestCase { ->will($this->returnValue('foo')); $manager->expects($this->once()) - ->method('get') - ->with('foo') + ->method('checkPassword') + ->with('foo', 'bar') ->will($this->returnValue($user)); $userSession = new \OC\User\Session($manager, $session); @@ -92,17 +88,13 @@ class Session extends \PHPUnit_Framework_TestCase { $backend = $this->getMock('OC_User_Dummy'); $user = $this->getMock('\OC\User\User', array(), array('foo', $backend)); - $user->expects($this->once()) - ->method('checkPassword') - ->with('bar') - ->will($this->returnValue(true)); $user->expects($this->once()) ->method('isEnabled') ->will($this->returnValue(false)); $manager->expects($this->once()) - ->method('get') - ->with('foo') + ->method('checkPassword') + ->with('foo', 'bar') ->will($this->returnValue($user)); $userSession = new \OC\User\Session($manager, $session); @@ -119,17 +111,13 @@ class Session extends \PHPUnit_Framework_TestCase { $backend = $this->getMock('OC_User_Dummy'); $user = $this->getMock('\OC\User\User', array(), array('foo', $backend)); - $user->expects($this->once()) - ->method('checkPassword') - ->with('bar') - ->will($this->returnValue(false)); $user->expects($this->never()) ->method('isEnabled'); $manager->expects($this->once()) - ->method('get') - ->with('foo') - ->will($this->returnValue($user)); + ->method('checkPassword') + ->with('foo', 'bar') + ->will($this->returnValue(false)); $userSession = new \OC\User\Session($manager, $session); $userSession->login('foo', 'bar'); @@ -145,9 +133,9 @@ class Session extends \PHPUnit_Framework_TestCase { $backend = $this->getMock('OC_User_Dummy'); $manager->expects($this->once()) - ->method('get') - ->with('foo') - ->will($this->returnValue(null)); + ->method('checkPassword') + ->with('foo', 'bar') + ->will($this->returnValue(false)); $userSession = new \OC\User\Session($manager, $session); $userSession->login('foo', 'bar'); -- cgit v1.2.3 From fe88a62d6e9ee4bb138ac4fb0fe81d8fbe082e09 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 24 Sep 2013 13:51:33 +0200 Subject: === not == --- lib/user/http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/user/http.php b/lib/user/http.php index ea14cb57c93..e99afe59ba7 100644 --- a/lib/user/http.php +++ b/lib/user/http.php @@ -79,7 +79,7 @@ class OC_User_HTTP extends OC_User_Backend { curl_close($ch); - if($status == 200) { + if($status === 200) { return $uid; } -- cgit v1.2.3 From 6c5466a540340a22e487d71a2605dcda3498a658 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 24 Sep 2013 13:53:32 +0200 Subject: adding file_exists check just to be on the save side --- lib/connector/sabre/directory.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index 9e0fe5e64e7..a50098df793 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -89,7 +89,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa // rename to correct path $renameOkay = \OC\Files\Filesystem::rename($partpath, $newPath); - if (!$renameOkay) { + $fileExists = \OC\Files\Filesystem::file_exists($newPath); + if ($renameOkay === false || $fileExists === false) { \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); \OC\Files\Filesystem::unlink($partpath); throw new Sabre_DAV_Exception(); -- cgit v1.2.3 From e9eb34f1872a0237b7474496e8c759a4a3ef1156 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 24 Sep 2013 13:54:18 +0200 Subject: duplicate code :sigh: - will fix this in a second pr --- lib/connector/sabre/file.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php index 61bdcd5e0ae..433b1148552 100644 --- a/lib/connector/sabre/file.php +++ b/lib/connector/sabre/file.php @@ -74,7 +74,14 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D } // rename to correct path - \OC\Files\Filesystem::rename($partpath, $this->path); + $renameOkay = \OC\Files\Filesystem::rename($partpath, $this->path); + $fileExists = \OC\Files\Filesystem::file_exists($this->path); + if ($renameOkay === false || $fileExists === false) { + \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + \OC\Files\Filesystem::unlink($partpath); + throw new Sabre_DAV_Exception(); + } + //allow sync clients to send the mtime along in a header $mtime = OC_Request::hasModificationTime(); -- cgit v1.2.3 From 0a7ee7c3f7b6825815a5aae1e41725481dbbfb08 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 24 Sep 2013 14:11:47 +0200 Subject: Fix return value from User object to User ID --- lib/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/user.php b/lib/user.php index 8868428ce24..ba6036bad96 100644 --- a/lib/user.php +++ b/lib/user.php @@ -419,7 +419,7 @@ class OC_User { $manager = self::getManager(); $username = $manager->checkPassword($uid, $password); if ($username !== false) { - return $manger->get($username); + return $manager->get($username)->getUID(); } return false; } -- cgit v1.2.3 From 63324e23472071f34746e2f6132a6246babe7e74 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 24 Sep 2013 14:12:44 +0200 Subject: Fix doc --- lib/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/user.php b/lib/user.php index ba6036bad96..da774ff86f0 100644 --- a/lib/user.php +++ b/lib/user.php @@ -410,7 +410,7 @@ class OC_User { * @brief Check if the password is correct * @param string $uid The username * @param string $password The password - * @return bool + * @return mixed user id a string on success, false otherwise * * Check if the password is correct without logging in the user * returns the user id or false -- cgit v1.2.3 From 14a160e176135cb86191eed46b4cc3b3b0e58f44 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 24 Sep 2013 17:10:01 +0200 Subject: Adjust Tests and satisfy them --- lib/user/manager.php | 10 ++++++---- tests/lib/user/manager.php | 45 +++++++++++++++++++++++++++++++++++++++++++++ tests/lib/user/user.php | 40 ---------------------------------------- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/lib/user/manager.php b/lib/user/manager.php index 2de694a3d9f..13286bc28a4 100644 --- a/lib/user/manager.php +++ b/lib/user/manager.php @@ -127,12 +127,14 @@ class Manager extends PublicEmitter { */ public function checkPassword($loginname, $password) { foreach ($this->backends as $backend) { - $uid = $backend->checkPassword($loginname, $password); - if ($uid !== false) { - return $this->getUserObject($uid, $backend); + if($backend->implementsActions(\OC_USER_BACKEND_CHECK_PASSWORD)) { + $uid = $backend->checkPassword($loginname, $password); + if ($uid !== false) { + return $this->getUserObject($uid, $backend); + } } } - return null; + return false; } /** diff --git a/tests/lib/user/manager.php b/tests/lib/user/manager.php index bc49f6db4b2..00901dd4115 100644 --- a/tests/lib/user/manager.php +++ b/tests/lib/user/manager.php @@ -98,6 +98,51 @@ class Manager extends \PHPUnit_Framework_TestCase { $this->assertTrue($manager->userExists('foo')); } + public function testCheckPassword() { + /** + * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend + */ + $backend = $this->getMock('\OC_User_Dummy'); + $backend->expects($this->once()) + ->method('checkPassword') + ->with($this->equalTo('foo'), $this->equalTo('bar')) + ->will($this->returnValue(true)); + + $backend->expects($this->any()) + ->method('implementsActions') + ->will($this->returnCallback(function ($actions) { + if ($actions === \OC_USER_BACKEND_CHECK_PASSWORD) { + return true; + } else { + return false; + } + })); + + $manager = new \OC\User\Manager(); + $manager->registerBackend($backend); + + $user = $manager->checkPassword('foo', 'bar'); + $this->assertTrue($user instanceof \OC\User\User); + } + + public function testCheckPasswordNotSupported() { + /** + * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend + */ + $backend = $this->getMock('\OC_User_Dummy'); + $backend->expects($this->never()) + ->method('checkPassword'); + + $backend->expects($this->any()) + ->method('implementsActions') + ->will($this->returnValue(false)); + + $manager = new \OC\User\Manager(); + $manager->registerBackend($backend); + + $this->assertFalse($manager->checkPassword('foo', 'bar')); + } + public function testGetOneBackendExists() { /** * @var \OC_User_Dummy | \PHPUnit_Framework_MockObject_MockObject $backend diff --git a/tests/lib/user/user.php b/tests/lib/user/user.php index b0d170cbfc5..de5ccbf38c1 100644 --- a/tests/lib/user/user.php +++ b/tests/lib/user/user.php @@ -100,46 +100,6 @@ class User extends \PHPUnit_Framework_TestCase { $this->assertTrue($user->delete()); } - public function testCheckPassword() { - /** - * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend - */ - $backend = $this->getMock('\OC_User_Dummy'); - $backend->expects($this->once()) - ->method('checkPassword') - ->with($this->equalTo('foo'), $this->equalTo('bar')) - ->will($this->returnValue(true)); - - $backend->expects($this->any()) - ->method('implementsActions') - ->will($this->returnCallback(function ($actions) { - if ($actions === \OC_USER_BACKEND_CHECK_PASSWORD) { - return true; - } else { - return false; - } - })); - - $user = new \OC\User\User('foo', $backend); - $this->assertTrue($user->checkPassword('bar')); - } - - public function testCheckPasswordNotSupported() { - /** - * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend - */ - $backend = $this->getMock('\OC_User_Dummy'); - $backend->expects($this->never()) - ->method('checkPassword'); - - $backend->expects($this->any()) - ->method('implementsActions') - ->will($this->returnValue(false)); - - $user = new \OC\User\User('foo', $backend); - $this->assertFalse($user->checkPassword('bar')); - } - public function testGetHome() { /** * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend -- cgit v1.2.3 From aaed871cee445633cb81f0aa230ba2f65c667803 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 24 Sep 2013 17:10:01 +0200 Subject: Add factory class for the server container. --- lib/public/iservercontainer.php | 3 +- lib/public/itagmanager.php | 48 +++++++++++++++++++++ lib/public/itags.php | 9 ---- lib/server.php | 3 +- lib/tagmanager.php | 68 ++++++++++++++++++++++++++++++ lib/tags.php | 28 +++++++++---- tests/lib/tags.php | 92 +++++++++++++++++++---------------------- 7 files changed, 182 insertions(+), 69 deletions(-) create mode 100644 lib/public/itagmanager.php create mode 100644 lib/tagmanager.php diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 0df746a28ed..f37bdb10f8f 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -58,7 +58,8 @@ interface IServerContainer { /** * Returns the tag manager which can get and set tags for different object types * - * @return \OCP\ITags + * @see \OCP\ITagManager::load() + * @return \OCP\ITagManager */ function getTagManager(); diff --git a/lib/public/itagmanager.php b/lib/public/itagmanager.php new file mode 100644 index 00000000000..07e1d12fc0f --- /dev/null +++ b/lib/public/itagmanager.php @@ -0,0 +1,48 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Factory class creating instances of \OCP\ITags + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OCP; + +interface ITagManager { + + /** + * Create a new \OCP\ITags instance and load tags from db. + * + * @see \OCP\ITags + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function load($type, $defaultTags=array()); + +} \ No newline at end of file diff --git a/lib/public/itags.php b/lib/public/itags.php index 12643400548..5b1ebd189da 100644 --- a/lib/public/itags.php +++ b/lib/public/itags.php @@ -38,15 +38,6 @@ namespace OCP; interface ITags { - /** - * Load tags from db. - * - * @param string $type The type identifier e.g. 'contact' or 'event'. - * @param array $defaultTags An array of default tags to be used if none are stored. - * @return \OCP\ITags - */ - public function loadTagsFor($type, $defaultTags=array()); - /** * Check if any tags are saved for this type and user. * diff --git a/lib/server.php b/lib/server.php index f3c79aa797f..c47f0e2b461 100644 --- a/lib/server.php +++ b/lib/server.php @@ -146,7 +146,8 @@ class Server extends SimpleContainer implements IServerContainer { /** * Returns the tag manager which can get and set tags for different object types * - * @return \OCP\ITags + * @see \OCP\ITagManager::load() + * @return \OCP\ITagManager */ function getTagManager() { return $this->query('TagManager'); diff --git a/lib/tagmanager.php b/lib/tagmanager.php new file mode 100644 index 00000000000..9a371a11253 --- /dev/null +++ b/lib/tagmanager.php @@ -0,0 +1,68 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Factory class creating instances of \OCP\ITags + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class TagManager implements \OCP\ITagManager { + + /** + * User + * + * @var string + */ + private $user = null; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user) { + + $this->user = $user; + + } + + /** + * Create a new \OCP\ITags instance and load tags from db. + * + * @see \OCP\ITags + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function load($type, $defaultTags=array()) { + return new Tags($this->user, $type, $defaultTags); + } + +} \ No newline at end of file diff --git a/lib/tags.php b/lib/tags.php index ff9f35ebc9e..9fdb35a7d6e 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -38,15 +38,30 @@ class Tags implements \OCP\ITags { /** * Tags + * + * @var array */ private $tags = array(); /** * Used for storing objectid/categoryname pairs while rescanning. + * + * @var array */ private static $relations = array(); + /** + * Type + * + * @var string + */ private $type = null; + + /** + * User + * + * @var string + */ private $user = null; const TAG_TABLE = '*PREFIX*vcategory'; @@ -59,10 +74,10 @@ class Tags implements \OCP\ITags { * * @param string $user The user whos data the object will operate on. */ - public function __construct($user) { - + public function __construct($user, $type, $defaultTags = array()) { $this->user = $user; - + $this->type = $type; + $this->loadTags($defaultTags); } /** @@ -70,10 +85,8 @@ class Tags implements \OCP\ITags { * * @param string $type The type identifier e.g. 'contact' or 'event'. * @param array $defaultTags An array of default tags to be used if none are stored. - * @return \OCP\ITags */ - public function loadTagsFor($type, $defaultTags=array()) { - $this->type = $type; + protected function loadTags($defaultTags=array()) { $this->tags = array(); $result = null; $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' @@ -101,7 +114,6 @@ class Tags implements \OCP\ITags { \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), \OCP\Util::DEBUG); - return $this; } /** @@ -345,7 +357,7 @@ class Tags implements \OCP\ITags { } } // reload tags to get the proper ids. - $this->loadTagsFor($this->type); + $this->loadTags(); // Loop through temporarily cached objectid/tagname pairs // and save relations. $tags = $this->tags; diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 75db9f50f72..97e3734cfda 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -34,6 +34,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->objectType = uniqid('type_'); OC_User::createUser($this->user, 'pass'); OC_User::setUserId($this->user); + $this->tagMgr = new OC\TagManager($this->user); } @@ -45,102 +46,95 @@ class Test_Tags extends PHPUnit_Framework_TestCase { public function testInstantiateWithDefaults() { $defaultTags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType, $defaultTags); + $tagger = $this->tagMgr->load($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertEquals(4, count($tagger->getTags())); } public function testAddTags() { $tags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($tags as $tag) { - $result = $tagMgr->add($tag); + $result = $tagger->add($tag); $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); $this->assertTrue((bool)$result); } - $this->assertFalse($tagMgr->add('Family')); - $this->assertFalse($tagMgr->add('fAMILY')); + $this->assertFalse($tagger->add('Family')); + $this->assertFalse($tagger->add('fAMILY')); - $this->assertCount(4, $tagMgr->getTags(), 'Wrong number of added tags'); + $this->assertCount(4, $tagger->getTags(), 'Wrong number of added tags'); } public function testAddMultiple() { $tags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($tags as $tag) { - $this->assertFalse($tagMgr->hasTag($tag)); + $this->assertFalse($tagger->hasTag($tag)); } - $result = $tagMgr->addMultiple($tags); + $result = $tagger->addMultiple($tags); $this->assertTrue((bool)$result); foreach($tags as $tag) { - $this->assertTrue($tagMgr->hasTag($tag)); + $this->assertTrue($tagger->hasTag($tag)); } - $this->assertCount(4, $tagMgr->getTags(), 'Not all tags added'); + $this->assertCount(4, $tagger->getTags(), 'Not all tags added'); } public function testIsEmpty() { - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); - $this->assertEquals(0, count($tagMgr->getTags())); - $this->assertTrue($tagMgr->isEmpty()); + $this->assertEquals(0, count($tagger->getTags())); + $this->assertTrue($tagger->isEmpty()); - $result = $tagMgr->add('Tag'); + $result = $tagger->add('Tag'); $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); $this->assertNotEquals(false, $result, 'add() returned false'); - $this->assertFalse($tagMgr->isEmpty()); + $this->assertFalse($tagger->isEmpty()); } public function testdeleteTags() { $defaultTags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType, $defaultTags); + $tagger = $this->tagMgr->load($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertEquals(4, count($tagger->getTags())); - $tagMgr->delete('family'); - $this->assertEquals(3, count($tagMgr->getTags())); + $tagger->delete('family'); + $this->assertEquals(3, count($tagger->getTags())); - $tagMgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($tagMgr->getTags())); + $tagger->delete(array('Friends', 'Work', 'Other')); + $this->assertEquals(0, count($tagger->getTags())); } public function testRenameTag() { $defaultTags = array('Friends', 'Family', 'Wrok', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType, $defaultTags); + $tagger = $this->tagMgr->load($this->objectType, $defaultTags); - $this->assertTrue($tagMgr->rename('Wrok', 'Work')); - $this->assertTrue($tagMgr->hasTag('Work')); - $this->assertFalse($tagMgr->hastag('Wrok')); - $this->assertFalse($tagMgr->rename('Wrok', 'Work')); + $this->assertTrue($tagger->rename('Wrok', 'Work')); + $this->assertTrue($tagger->hasTag('Work')); + $this->assertFalse($tagger->hastag('Wrok')); + $this->assertFalse($tagger->rename('Wrok', 'Work')); } public function testTagAs() { $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($objids as $id) { - $tagMgr->tagAs($id, 'Family'); + $tagger->tagAs($id, 'Family'); } - $this->assertEquals(1, count($tagMgr->getTags())); - $this->assertEquals(9, count($tagMgr->getIdsForTag('Family'))); + $this->assertEquals(1, count($tagger->getTags())); + $this->assertEquals(9, count($tagger->getIdsForTag('Family'))); } /** @@ -151,24 +145,22 @@ class Test_Tags extends PHPUnit_Framework_TestCase { // Is this "legal"? $this->testTagAs(); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($objIds as $id) { - $this->assertTrue(in_array($id, $tagMgr->getIdsForTag('Family'))); - $tagMgr->unTag($id, 'Family'); - $this->assertFalse(in_array($id, $tagMgr->getIdsForTag('Family'))); + $this->assertTrue(in_array($id, $tagger->getIdsForTag('Family'))); + $tagger->unTag($id, 'Family'); + $this->assertFalse(in_array($id, $tagger->getIdsForTag('Family'))); } - $this->assertEquals(1, count($tagMgr->getTags())); - $this->assertEquals(0, count($tagMgr->getIdsForTag('Family'))); + $this->assertEquals(1, count($tagger->getTags())); + $this->assertEquals(0, count($tagger->getIdsForTag('Family'))); } public function testFavorite() { - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); - $this->assertTrue($tagMgr->addToFavorites(1)); - $this->assertTrue($tagMgr->removeFromFavorites(1)); + $tagger = $this->tagMgr->load($this->objectType); + $this->assertTrue($tagger->addToFavorites(1)); + $this->assertTrue($tagger->removeFromFavorites(1)); } } -- cgit v1.2.3 From c486fc76089ebc0f421a983e0ef62286e36e533c Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 24 Sep 2013 18:01:34 +0200 Subject: introduce OC_Util::rememberLoginAllowed() --- core/templates/login.php | 2 +- lib/base.php | 2 +- lib/util.php | 13 ++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/core/templates/login.php b/core/templates/login.php index 3e736f164ec..06f64d41e39 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -32,7 +32,7 @@ t('Lost your password?')); ?> - + diff --git a/lib/base.php b/lib/base.php index b4e12bc7ebb..d0aed230dd0 100644 --- a/lib/base.php +++ b/lib/base.php @@ -760,7 +760,7 @@ class OC { || !isset($_COOKIE["oc_token"]) || !isset($_COOKIE["oc_username"]) || !$_COOKIE["oc_remember_login"] - || OC_App::isEnabled('files_encryption') + || !OC_Util::rememberLoginAllowed() ) { return false; } diff --git a/lib/util.php b/lib/util.php index ef42ff2aea9..e12f753d5ae 100755 --- a/lib/util.php +++ b/lib/util.php @@ -467,7 +467,7 @@ class OC_Util { } $parameters['alt_login'] = OC_App::getAlternativeLogIns(); - $parameters['encryption_enabled'] = OC_App::isEnabled('files_encryption'); + $parameters['rememberLoginAllowed'] = self::rememberLoginAllowed(); OC_Template::printGuestPage("", "login", $parameters); } @@ -509,6 +509,17 @@ class OC_Util { } } + /** + * Check if it is allowed to remember login. + * E.g. if encryption is enabled the user needs to log-in every time he visites + * ownCloud in order to decrypt the private key. + * + * @return bool + */ + public static function rememberLoginAllowed() { + return !OC_App::isEnabled('files_encryption'); + } + /** * @brief Check if the user is a subadmin, redirects to home if not * @return array $groups where the current user is subadmin -- cgit v1.2.3 From 2d12e52769a30ba37d5760b1194f613bcc71035b Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Tue, 24 Sep 2013 12:59:48 -0400 Subject: [tx-robot] updated from transifex --- apps/files/l10n/ca.php | 5 ++++ apps/files/l10n/en_GB.php | 7 ++++- apps/files/l10n/fr.php | 5 ++++ apps/files/l10n/gl.php | 5 ++++ apps/files/l10n/nn_NO.php | 5 ++++ core/l10n/en_GB.php | 9 ++++++- core/l10n/fr.php | 6 ++++- core/l10n/gl.php | 9 ++++++- core/l10n/nn_NO.php | 16 +++++++++++- l10n/ca/files.po | 18 ++++++------- l10n/da/settings.po | 34 ++++++++++++------------ l10n/en_GB/core.po | 38 +++++++++++++-------------- l10n/en_GB/files.po | 20 +++++++------- l10n/fr/core.po | 32 +++++++++++------------ l10n/fr/files.po | 18 ++++++------- l10n/gl/core.po | 38 +++++++++++++-------------- l10n/gl/files.po | 18 ++++++------- l10n/nn_NO/core.po | 52 ++++++++++++++++++------------------- l10n/nn_NO/files.po | 19 +++++++------- l10n/nn_NO/lib.po | 14 +++++----- l10n/nn_NO/settings.po | 52 ++++++++++++++++++------------------- l10n/templates/core.pot | 16 ++++++------ l10n/templates/files.pot | 2 +- l10n/templates/files_encryption.pot | 2 +- l10n/templates/files_external.pot | 2 +- l10n/templates/files_sharing.pot | 2 +- l10n/templates/files_trashbin.pot | 2 +- l10n/templates/files_versions.pot | 2 +- l10n/templates/lib.pot | 2 +- l10n/templates/settings.pot | 20 +++++++------- l10n/templates/user_ldap.pot | 2 +- l10n/templates/user_webdavauth.pot | 2 +- lib/l10n/nn_NO.php | 2 ++ settings/l10n/da.php | 5 ++++ settings/l10n/nn_NO.php | 14 ++++++++++ 35 files changed, 287 insertions(+), 208 deletions(-) diff --git a/apps/files/l10n/ca.php b/apps/files/l10n/ca.php index 8fd72ac0a68..5c2cade8d63 100644 --- a/apps/files/l10n/ca.php +++ b/apps/files/l10n/ca.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Falta un fitxer temporal", "Failed to write to disk" => "Ha fallat en escriure al disc", "Not enough storage available" => "No hi ha prou espai disponible", +"Upload failed. Could not get file info." => "La pujada ha fallat. No s'ha pogut obtenir informació del fitxer.", +"Upload failed. Could not find uploaded file" => "La pujada ha fallat. El fitxer pujat no s'ha trobat.", "Invalid directory." => "Directori no vàlid.", "Files" => "Fitxers", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "No es pot pujar {filename} perquè és una carpeta o té 0 bytes", "Not enough space available" => "No hi ha prou espai disponible", "Upload cancelled." => "La pujada s'ha cancel·lat.", +"Could not get result from server." => "No hi ha resposta del servidor.", "File upload is in progress. Leaving the page now will cancel the upload." => "Hi ha una pujada en curs. Si abandoneu la pàgina la pujada es cancel·larà.", "URL cannot be empty." => "La URL no pot ser buida", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Nom de carpeta no vàlid. L'ús de 'Shared' està reservat per Owncloud", @@ -42,6 +46,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "El vostre espai d'emmagatzemament és gairebé ple ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "L'encriptació s'ha desactivat però els vostres fitxers segueixen encriptats. Aneu a la vostra configuració personal per desencriptar els vostres fitxers.", "Your download is being prepared. This might take some time if the files are big." => "S'està preparant la baixada. Pot trigar una estona si els fitxers són grans.", +"Error moving file" => "Error en moure el fitxer", "Name" => "Nom", "Size" => "Mida", "Modified" => "Modificat", diff --git a/apps/files/l10n/en_GB.php b/apps/files/l10n/en_GB.php index e67719efba9..c747555e40b 100644 --- a/apps/files/l10n/en_GB.php +++ b/apps/files/l10n/en_GB.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Missing a temporary folder", "Failed to write to disk" => "Failed to write to disk", "Not enough storage available" => "Not enough storage available", +"Upload failed. Could not get file info." => "Upload failed. Could not get file info.", +"Upload failed. Could not find uploaded file" => "Upload failed. Could not find uploaded file", "Invalid directory." => "Invalid directory.", "Files" => "Files", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "Unable to upload {filename} as it is a directory or has 0 bytes", "Not enough space available" => "Not enough space available", "Upload cancelled." => "Upload cancelled.", +"Could not get result from server." => "Could not get result from server.", "File upload is in progress. Leaving the page now will cancel the upload." => "File upload is in progress. Leaving the page now will cancel the upload.", "URL cannot be empty." => "URL cannot be empty.", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Invalid folder name. Usage of 'Shared' is reserved by ownCloud", @@ -37,11 +41,12 @@ $TRANSLATIONS = array( "_Uploading %n file_::_Uploading %n files_" => array("Uploading %n file","Uploading %n files"), "'.' is an invalid file name." => "'.' is an invalid file name.", "File name cannot be empty." => "File name cannot be empty.", -"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Invalid name: '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.", "Your storage is full, files can not be updated or synced anymore!" => "Your storage is full, files can not be updated or synced anymore!", "Your storage is almost full ({usedSpacePercent}%)" => "Your storage is almost full ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files.", "Your download is being prepared. This might take some time if the files are big." => "Your download is being prepared. This might take some time if the files are big.", +"Error moving file" => "Error moving file", "Name" => "Name", "Size" => "Size", "Modified" => "Modified", diff --git a/apps/files/l10n/fr.php b/apps/files/l10n/fr.php index d6470458083..03505a2a269 100644 --- a/apps/files/l10n/fr.php +++ b/apps/files/l10n/fr.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Absence de dossier temporaire.", "Failed to write to disk" => "Erreur d'écriture sur le disque", "Not enough storage available" => "Plus assez d'espace de stockage disponible", +"Upload failed. Could not get file info." => "L'envoi a échoué. Impossible d'obtenir les informations du fichier.", +"Upload failed. Could not find uploaded file" => "L'envoi a échoué. Impossible de trouver le fichier envoyé.", "Invalid directory." => "Dossier invalide.", "Files" => "Fichiers", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "Impossible d'envoyer {filename} car il s'agit d'un répertoire ou d'un fichier de taille nulle", "Not enough space available" => "Espace disponible insuffisant", "Upload cancelled." => "Envoi annulé.", +"Could not get result from server." => "Ne peut recevoir les résultats du serveur.", "File upload is in progress. Leaving the page now will cancel the upload." => "L'envoi du fichier est en cours. Quitter cette page maintenant annulera l'envoi du fichier.", "URL cannot be empty." => "L'URL ne peut-être vide", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Nom de dossier invalide. L'utilisation du mot 'Shared' est réservée à Owncloud", @@ -42,6 +46,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Votre espace de stockage est presque plein ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement était désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos Paramètres personnels pour déchiffrer vos fichiers.", "Your download is being prepared. This might take some time if the files are big." => "Votre téléchargement est cours de préparation. Ceci peut nécessiter un certain temps si les fichiers sont volumineux.", +"Error moving file" => "Erreur lors du déplacement du fichier", "Name" => "Nom", "Size" => "Taille", "Modified" => "Modifié", diff --git a/apps/files/l10n/gl.php b/apps/files/l10n/gl.php index 0eba94f7d60..2766478650a 100644 --- a/apps/files/l10n/gl.php +++ b/apps/files/l10n/gl.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Falta o cartafol temporal", "Failed to write to disk" => "Produciuse un erro ao escribir no disco", "Not enough storage available" => "Non hai espazo de almacenamento abondo", +"Upload failed. Could not get file info." => "O envío fracasou. Non foi posíbel obter información do ficheiro.", +"Upload failed. Could not find uploaded file" => "O envío fracasou. Non foi posíbel atopar o ficheiro enviado", "Invalid directory." => "O directorio é incorrecto.", "Files" => "Ficheiros", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "Non é posíbel enviar {filename}, xa que ou é un directorio ou ten 0 bytes", "Not enough space available" => "O espazo dispoñíbel é insuficiente", "Upload cancelled." => "Envío cancelado.", +"Could not get result from server." => "Non foi posíbel obter o resultado do servidor.", "File upload is in progress. Leaving the page now will cancel the upload." => "O envío do ficheiro está en proceso. Saír agora da páxina cancelará o envío.", "URL cannot be empty." => "O URL non pode quedar baleiro.", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Nome de cartafol incorrecto. O uso de «Compartido» e «Shared» está reservado para o ownClod", @@ -42,6 +46,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "O seu espazo de almacenamento está case cheo ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "O cifrado foi desactivado, mais os ficheiros están cifrados. Vaia á configuración persoal para descifrar os ficheiros.", "Your download is being prepared. This might take some time if the files are big." => "Está a prepararse a súa descarga. Isto pode levar bastante tempo se os ficheiros son grandes.", +"Error moving file" => "Produciuse un erro ao mover o ficheiro", "Name" => "Nome", "Size" => "Tamaño", "Modified" => "Modificado", diff --git a/apps/files/l10n/nn_NO.php b/apps/files/l10n/nn_NO.php index 04c47c31fbb..e29b1d3ad36 100644 --- a/apps/files/l10n/nn_NO.php +++ b/apps/files/l10n/nn_NO.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Manglar ei mellombels mappe", "Failed to write to disk" => "Klarte ikkje skriva til disk", "Not enough storage available" => "Ikkje nok lagringsplass tilgjengeleg", +"Upload failed. Could not get file info." => "Feil ved opplasting. Klarte ikkje å henta filinfo.", +"Upload failed. Could not find uploaded file" => "Feil ved opplasting. Klarte ikkje å finna opplasta fil.", "Invalid directory." => "Ugyldig mappe.", "Files" => "Filer", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "Klarte ikkje å lasta opp {filename} sidan det er ei mappe eller er 0 byte.", "Not enough space available" => "Ikkje nok lagringsplass tilgjengeleg", "Upload cancelled." => "Opplasting avbroten.", +"Could not get result from server." => "Klarte ikkje å henta resultat frå tenaren.", "File upload is in progress. Leaving the page now will cancel the upload." => "Fila lastar no opp. Viss du forlèt sida no vil opplastinga verta avbroten.", "URL cannot be empty." => "Nettadressa kan ikkje vera tom.", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Ugyldig mappenamn. Mappa «Shared» er reservert av ownCloud", @@ -42,6 +46,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Lagringa di er nesten full ({usedSpacePercent} %)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Kryptering er skrudd av, men filene dine er enno krypterte. Du kan dekryptera filene i personlege innstillingar.", "Your download is being prepared. This might take some time if the files are big." => "Gjer klar nedlastinga di. Dette kan ta ei stund viss filene er store.", +"Error moving file" => "Feil ved flytting av fil", "Name" => "Namn", "Size" => "Storleik", "Modified" => "Endra", diff --git a/core/l10n/en_GB.php b/core/l10n/en_GB.php index feeacd481a8..bb26f1469dd 100644 --- a/core/l10n/en_GB.php +++ b/core/l10n/en_GB.php @@ -58,8 +58,15 @@ $TRANSLATIONS = array( "No" => "No", "Ok" => "OK", "Error loading message template: {error}" => "Error loading message template: {error}", -"_{count} file conflict_::_{count} file conflicts_" => array("",""), +"_{count} file conflict_::_{count} file conflicts_" => array("{count} file conflict","{count} file conflicts"), +"One file conflict" => "One file conflict", +"Which files do you want to keep?" => "Which files do you wish to keep?", +"If you select both versions, the copied file will have a number added to its name." => "If you select both versions, the copied file will have a number added to its name.", "Cancel" => "Cancel", +"Continue" => "Continue", +"(all selected)" => "(all selected)", +"({count} selected)" => "({count} selected)", +"Error loading file exists template" => "Error loading file exists template", "The object type is not specified." => "The object type is not specified.", "Error" => "Error", "The app name is not specified." => "The app name is not specified.", diff --git a/core/l10n/fr.php b/core/l10n/fr.php index d3229ddf994..29489e86b7f 100644 --- a/core/l10n/fr.php +++ b/core/l10n/fr.php @@ -56,8 +56,12 @@ $TRANSLATIONS = array( "No" => "Non", "Ok" => "Ok", "Error loading message template: {error}" => "Erreur de chargement du modèle de message : {error}", -"_{count} file conflict_::_{count} file conflicts_" => array("",""), +"_{count} file conflict_::_{count} file conflicts_" => array("{count} fichier en conflit","{count} fichiers en conflit"), +"One file conflict" => "Un conflit de fichier", +"Which files do you want to keep?" => "Quels fichiers désirez-vous garder ?", +"If you select both versions, the copied file will have a number added to its name." => "Si vous sélectionnez les deux versions, un nombre sera ajouté au nom du fichier copié.", "Cancel" => "Annuler", +"({count} selected)" => "({count} sélectionnés)", "The object type is not specified." => "Le type d'objet n'est pas spécifié.", "Error" => "Erreur", "The app name is not specified." => "Le nom de l'application n'est pas spécifié.", diff --git a/core/l10n/gl.php b/core/l10n/gl.php index 9ba5ab645aa..e3be94537e5 100644 --- a/core/l10n/gl.php +++ b/core/l10n/gl.php @@ -58,8 +58,15 @@ $TRANSLATIONS = array( "No" => "Non", "Ok" => "Aceptar", "Error loading message template: {error}" => "Produciuse un erro ao cargar o modelo da mensaxe: {error}", -"_{count} file conflict_::_{count} file conflicts_" => array("",""), +"_{count} file conflict_::_{count} file conflicts_" => array("{count} conflito de ficheiro","{count} conflitos de ficheiros"), +"One file conflict" => "Un conflito de ficheiro", +"Which files do you want to keep?" => "Que ficheiros quere conservar?", +"If you select both versions, the copied file will have a number added to its name." => "Se selecciona ambas versións, o ficheiro copiado terá un número engadido ao nome.", "Cancel" => "Cancelar", +"Continue" => "Continuar", +"(all selected)" => "(todo o seleccionado)", +"({count} selected)" => "({count} seleccionados)", +"Error loading file exists template" => "Produciuse un erro ao cargar o modelo de ficheiro existente", "The object type is not specified." => "Non se especificou o tipo de obxecto.", "Error" => "Erro", "The app name is not specified." => "Non se especificou o nome do aplicativo.", diff --git a/core/l10n/nn_NO.php b/core/l10n/nn_NO.php index 8ec3892a8ac..d596605dbcd 100644 --- a/core/l10n/nn_NO.php +++ b/core/l10n/nn_NO.php @@ -16,6 +16,11 @@ $TRANSLATIONS = array( "Error adding %s to favorites." => "Klarte ikkje leggja til %s i favorittar.", "No categories selected for deletion." => "Ingen kategoriar valt for sletting.", "Error removing %s from favorites." => "Klarte ikkje fjerna %s frå favorittar.", +"No image or file provided" => "Inga bilete eller fil gitt", +"Unknown filetype" => "Ukjend filtype", +"Invalid image" => "Ugyldig bilete", +"No temporary profile picture available, try again" => "Inga midlertidig profilbilete tilgjengeleg, prøv igjen", +"No crop data provided" => "Ingen beskjeringsdata gitt", "Sunday" => "Søndag", "Monday" => "Måndag", "Tuesday" => "Tysdag", @@ -48,11 +53,20 @@ $TRANSLATIONS = array( "last year" => "i fjor", "years ago" => "år sidan", "Choose" => "Vel", +"Error loading file picker template: {error}" => "Klarte ikkje å lasta filplukkarmal: {error}", "Yes" => "Ja", "No" => "Nei", "Ok" => "Greitt", -"_{count} file conflict_::_{count} file conflicts_" => array("",""), +"Error loading message template: {error}" => "Klarte ikkje å lasta meldingsmal: {error}", +"_{count} file conflict_::_{count} file conflicts_" => array("{count} filkonflikt","{count} filkonfliktar"), +"One file conflict" => "Éin filkonflikt", +"Which files do you want to keep?" => "Kva filer vil du spara?", +"If you select both versions, the copied file will have a number added to its name." => "Viss du vel begge utgåvene, vil den kopierte fila få eit tal lagt til namnet.", "Cancel" => "Avbryt", +"Continue" => "Gå vidare", +"(all selected)" => "(alle valte)", +"({count} selected)" => "({count} valte)", +"Error loading file exists template" => "Klarte ikkje å lasta fil-finst-mal", "The object type is not specified." => "Objekttypen er ikkje spesifisert.", "Error" => "Feil", "The app name is not specified." => "Programnamnet er ikkje spesifisert.", diff --git a/l10n/ca/files.po b/l10n/ca/files.po index 173aeb30aca..82091cf75b3 100644 --- a/l10n/ca/files.po +++ b/l10n/ca/files.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-24 15:10+0000\n" +"Last-Translator: rogerc\n" "Language-Team: Catalan (http://www.transifex.com/projects/p/owncloud/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,23 +78,23 @@ msgstr "No hi ha prou espai disponible" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "La pujada ha fallat. No s'ha pogut obtenir informació del fitxer." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "La pujada ha fallat. El fitxer pujat no s'ha trobat." #: ajax/upload.php:160 msgid "Invalid directory." msgstr "Directori no vàlid." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Fitxers" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "No es pot pujar {filename} perquè és una carpeta o té 0 bytes" #: js/file-upload.js:255 msgid "Not enough space available" @@ -106,7 +106,7 @@ msgstr "La pujada s'ha cancel·lat." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "No hi ha resposta del servidor." #: js/file-upload.js:446 msgid "" @@ -223,7 +223,7 @@ msgstr "S'està preparant la baixada. Pot trigar una estona si els fitxers són #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Error en moure el fitxer" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/da/settings.po b/l10n/da/settings.po index accacfac32a..7251a13d4ff 100644 --- a/l10n/da/settings.po +++ b/l10n/da/settings.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-24 16:59+0000\n" +"Last-Translator: Sappe\n" "Language-Team: Danish (http://www.transifex.com/projects/p/owncloud/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -89,28 +89,28 @@ msgstr "Kunne ikke opdatere app'en." #: changepassword/controller.php:20 msgid "Wrong password" -msgstr "" +msgstr "Forkert kodeord" #: changepassword/controller.php:42 msgid "No user supplied" -msgstr "" +msgstr "Intet brugernavn givet" #: changepassword/controller.php:74 msgid "" "Please provide an admin recovery password, otherwise all user data will be " "lost" -msgstr "" +msgstr "Angiv venligst en admininstrator gendannelseskode, ellers vil alt brugerdata gå tabt" #: changepassword/controller.php:79 msgid "" "Wrong admin recovery password. Please check the password and try again." -msgstr "" +msgstr "Forkert admin gendannelseskode. Se venligst koden efter og prøv igen." #: changepassword/controller.php:87 msgid "" "Back-end doesn't support password change, but the users encryption key was " "successfully updated." -msgstr "" +msgstr "Serveren understøtter ikke kodeordsskifte, men brugernes krypteringsnøgle blev opdateret." #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" @@ -120,11 +120,11 @@ msgstr "" msgid "Update to {appversion}" msgstr "Opdatér til {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Deaktiver" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Aktiver" @@ -132,31 +132,31 @@ msgstr "Aktiver" msgid "Please wait...." msgstr "Vent venligst..." -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "Kunne ikke deaktivere app" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "Kunne ikke aktivere app" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Opdaterer...." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Der opstod en fejl under app opgraderingen" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Fejl" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Opdater" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Opdateret" diff --git a/l10n/en_GB/core.po b/l10n/en_GB/core.po index 5ac5d34f566..f9b0f0d24fa 100644 --- a/l10n/en_GB/core.po +++ b/l10n/en_GB/core.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-23 16:10+0000\n" +"Last-Translator: mnestis \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/owncloud/language/en_GB/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -270,22 +270,22 @@ msgstr "Error loading message template: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "{count} file conflict" +msgstr[1] "{count} file conflicts" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "One file conflict" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Which files do you wish to keep?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "If you select both versions, the copied file will have a number added to its name." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -293,19 +293,19 @@ msgstr "Cancel" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Continue" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(all selected)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} selected)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "Error loading file exists template" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 @@ -316,7 +316,7 @@ msgstr "The object type is not specified." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Error" @@ -336,7 +336,7 @@ msgstr "Shared" msgid "Share" msgstr "Share" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Error whilst sharing" @@ -436,23 +436,23 @@ msgstr "delete" msgid "share" msgstr "share" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Password protected" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Error unsetting expiration date" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Error setting expiration date" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Sending ..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "Email sent" diff --git a/l10n/en_GB/files.po b/l10n/en_GB/files.po index fe7922ffe9a..bf8e9374348 100644 --- a/l10n/en_GB/files.po +++ b/l10n/en_GB/files.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-24 16:00+0000\n" +"Last-Translator: mnestis \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/owncloud/language/en_GB/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,23 +77,23 @@ msgstr "Not enough storage available" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "Upload failed. Could not get file info." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "Upload failed. Could not find uploaded file" #: ajax/upload.php:160 msgid "Invalid directory." msgstr "Invalid directory." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Files" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "Unable to upload {filename} as it is a directory or has 0 bytes" #: js/file-upload.js:255 msgid "Not enough space available" @@ -105,7 +105,7 @@ msgstr "Upload cancelled." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "Could not get result from server." #: js/file-upload.js:446 msgid "" @@ -198,7 +198,7 @@ msgstr "File name cannot be empty." msgid "" "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not " "allowed." -msgstr "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." +msgstr "Invalid name: '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." #: js/files.js:51 msgid "Your storage is full, files can not be updated or synced anymore!" @@ -222,7 +222,7 @@ msgstr "Your download is being prepared. This might take some time if the files #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Error moving file" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/fr/core.po b/l10n/fr/core.po index 76dc658c71d..4c7f6be045a 100644 --- a/l10n/fr/core.po +++ b/l10n/fr/core.po @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-23 19:40+0000\n" +"Last-Translator: ogre_sympathique \n" "Language-Team: French (http://www.transifex.com/projects/p/owncloud/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -275,22 +275,22 @@ msgstr "Erreur de chargement du modèle de message : {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "{count} fichier en conflit" +msgstr[1] "{count} fichiers en conflit" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "Un conflit de fichier" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Quels fichiers désirez-vous garder ?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "Si vous sélectionnez les deux versions, un nombre sera ajouté au nom du fichier copié." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -306,7 +306,7 @@ msgstr "" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} sélectionnés)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" @@ -321,7 +321,7 @@ msgstr "Le type d'objet n'est pas spécifié." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Erreur" @@ -341,7 +341,7 @@ msgstr "Partagé" msgid "Share" msgstr "Partager" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Erreur lors de la mise en partage" @@ -441,23 +441,23 @@ msgstr "supprimer" msgid "share" msgstr "partager" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Protégé par un mot de passe" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Une erreur est survenue pendant la suppression de la date d'expiration" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Erreur lors de la spécification de la date d'expiration" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "En cours d'envoi ..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "Email envoyé" diff --git a/l10n/fr/files.po b/l10n/fr/files.po index fcbbbad254e..72963e3573f 100644 --- a/l10n/fr/files.po +++ b/l10n/fr/files.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-23 19:30+0000\n" +"Last-Translator: ogre_sympathique \n" "Language-Team: French (http://www.transifex.com/projects/p/owncloud/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -80,23 +80,23 @@ msgstr "Plus assez d'espace de stockage disponible" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "L'envoi a échoué. Impossible d'obtenir les informations du fichier." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "L'envoi a échoué. Impossible de trouver le fichier envoyé." #: ajax/upload.php:160 msgid "Invalid directory." msgstr "Dossier invalide." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Fichiers" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "Impossible d'envoyer {filename} car il s'agit d'un répertoire ou d'un fichier de taille nulle" #: js/file-upload.js:255 msgid "Not enough space available" @@ -108,7 +108,7 @@ msgstr "Envoi annulé." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "Ne peut recevoir les résultats du serveur." #: js/file-upload.js:446 msgid "" @@ -225,7 +225,7 @@ msgstr "Votre téléchargement est cours de préparation. Ceci peut nécessiter #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Erreur lors du déplacement du fichier" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/gl/core.po b/l10n/gl/core.po index 72986b81c8a..b8bcfd4eea8 100644 --- a/l10n/gl/core.po +++ b/l10n/gl/core.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-23 10:30+0000\n" +"Last-Translator: mbouzada \n" "Language-Team: Galician (http://www.transifex.com/projects/p/owncloud/language/gl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -270,22 +270,22 @@ msgstr "Produciuse un erro ao cargar o modelo da mensaxe: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "{count} conflito de ficheiro" +msgstr[1] "{count} conflitos de ficheiros" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "Un conflito de ficheiro" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Que ficheiros quere conservar?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "Se selecciona ambas versións, o ficheiro copiado terá un número engadido ao nome." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -293,19 +293,19 @@ msgstr "Cancelar" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Continuar" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(todo o seleccionado)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} seleccionados)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "Produciuse un erro ao cargar o modelo de ficheiro existente" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 @@ -316,7 +316,7 @@ msgstr "Non se especificou o tipo de obxecto." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Erro" @@ -336,7 +336,7 @@ msgstr "Compartir" msgid "Share" msgstr "Compartir" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Produciuse un erro ao compartir" @@ -436,23 +436,23 @@ msgstr "eliminar" msgid "share" msgstr "compartir" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Protexido con contrasinal" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Produciuse un erro ao retirar a data de caducidade" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Produciuse un erro ao definir a data de caducidade" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Enviando..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "Correo enviado" diff --git a/l10n/gl/files.po b/l10n/gl/files.po index 45a9129ab2d..33e76e84873 100644 --- a/l10n/gl/files.po +++ b/l10n/gl/files.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-23 10:30+0000\n" +"Last-Translator: mbouzada \n" "Language-Team: Galician (http://www.transifex.com/projects/p/owncloud/language/gl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,23 +77,23 @@ msgstr "Non hai espazo de almacenamento abondo" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "O envío fracasou. Non foi posíbel obter información do ficheiro." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "O envío fracasou. Non foi posíbel atopar o ficheiro enviado" #: ajax/upload.php:160 msgid "Invalid directory." msgstr "O directorio é incorrecto." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Ficheiros" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "Non é posíbel enviar {filename}, xa que ou é un directorio ou ten 0 bytes" #: js/file-upload.js:255 msgid "Not enough space available" @@ -105,7 +105,7 @@ msgstr "Envío cancelado." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "Non foi posíbel obter o resultado do servidor." #: js/file-upload.js:446 msgid "" @@ -222,7 +222,7 @@ msgstr "Está a prepararse a súa descarga. Isto pode levar bastante tempo se os #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Produciuse un erro ao mover o ficheiro" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/nn_NO/core.po b/l10n/nn_NO/core.po index 40a6de51ba5..e16776a0986 100644 --- a/l10n/nn_NO/core.po +++ b/l10n/nn_NO/core.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-24 08:30+0000\n" +"Last-Translator: unhammer \n" "Language-Team: Norwegian Nynorsk (Norway) (http://www.transifex.com/projects/p/owncloud/language/nn_NO/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -95,23 +95,23 @@ msgstr "Klarte ikkje fjerna %s frå favorittar." #: avatar/controller.php:62 msgid "No image or file provided" -msgstr "" +msgstr "Inga bilete eller fil gitt" #: avatar/controller.php:81 msgid "Unknown filetype" -msgstr "" +msgstr "Ukjend filtype" #: avatar/controller.php:85 msgid "Invalid image" -msgstr "" +msgstr "Ugyldig bilete" #: avatar/controller.php:115 avatar/controller.php:142 msgid "No temporary profile picture available, try again" -msgstr "" +msgstr "Inga midlertidig profilbilete tilgjengeleg, prøv igjen" #: avatar/controller.php:135 msgid "No crop data provided" -msgstr "" +msgstr "Ingen beskjeringsdata gitt" #: js/config.php:32 msgid "Sunday" @@ -251,7 +251,7 @@ msgstr "Vel" #: js/oc-dialogs.js:146 msgid "Error loading file picker template: {error}" -msgstr "" +msgstr "Klarte ikkje å lasta filplukkarmal: {error}" #: js/oc-dialogs.js:172 msgid "Yes" @@ -267,27 +267,27 @@ msgstr "Greitt" #: js/oc-dialogs.js:219 msgid "Error loading message template: {error}" -msgstr "" +msgstr "Klarte ikkje å lasta meldingsmal: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "{count} filkonflikt" +msgstr[1] "{count} filkonfliktar" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "Éin filkonflikt" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Kva filer vil du spara?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "Viss du vel begge utgåvene, vil den kopierte fila få eit tal lagt til namnet." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -295,19 +295,19 @@ msgstr "Avbryt" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Gå vidare" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(alle valte)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} valte)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "Klarte ikkje å lasta fil-finst-mal" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 @@ -318,7 +318,7 @@ msgstr "Objekttypen er ikkje spesifisert." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Feil" @@ -338,7 +338,7 @@ msgstr "Delt" msgid "Share" msgstr "Del" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Feil ved deling" @@ -438,23 +438,23 @@ msgstr "slett" msgid "share" msgstr "del" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Passordverna" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Klarte ikkje fjerna utløpsdato" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Klarte ikkje setja utløpsdato" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Sender …" -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "E-post sendt" diff --git a/l10n/nn_NO/files.po b/l10n/nn_NO/files.po index 0573ecf2951..dc82bdca1b7 100644 --- a/l10n/nn_NO/files.po +++ b/l10n/nn_NO/files.po @@ -5,13 +5,14 @@ # Translators: # unhammer , 2013 # unhammer , 2013 +# unhammer , 2013 msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-24 08:20+0000\n" +"Last-Translator: unhammer \n" "Language-Team: Norwegian Nynorsk (Norway) (http://www.transifex.com/projects/p/owncloud/language/nn_NO/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,23 +79,23 @@ msgstr "Ikkje nok lagringsplass tilgjengeleg" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "Feil ved opplasting. Klarte ikkje å henta filinfo." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "Feil ved opplasting. Klarte ikkje å finna opplasta fil." #: ajax/upload.php:160 msgid "Invalid directory." msgstr "Ugyldig mappe." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Filer" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "Klarte ikkje å lasta opp {filename} sidan det er ei mappe eller er 0 byte." #: js/file-upload.js:255 msgid "Not enough space available" @@ -106,7 +107,7 @@ msgstr "Opplasting avbroten." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "Klarte ikkje å henta resultat frå tenaren." #: js/file-upload.js:446 msgid "" @@ -223,7 +224,7 @@ msgstr "Gjer klar nedlastinga di. Dette kan ta ei stund viss filene er store." #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Feil ved flytting av fil" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/nn_NO/lib.po b/l10n/nn_NO/lib.po index dd499893e3c..9e73f6fe6aa 100644 --- a/l10n/nn_NO/lib.po +++ b/l10n/nn_NO/lib.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-16 11:33-0400\n" -"PO-Revision-Date: 2013-09-16 15:34+0000\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-24 08:30+0000\n" "Last-Translator: I Robot \n" "Language-Team: Norwegian Nynorsk (Norway) (http://www.transifex.com/projects/p/owncloud/language/nn_NO/)\n" "MIME-Version: 1.0\n" @@ -61,11 +61,11 @@ msgstr "" #: avatar.php:64 msgid "Unknown filetype" -msgstr "" +msgstr "Ukjend filtype" #: avatar.php:69 msgid "Invalid image" -msgstr "" +msgstr "Ugyldig bilete" #: defaults.php:35 msgid "web services under your control" @@ -166,15 +166,15 @@ msgstr "Feil i autentisering" msgid "Token expired. Please reload page." msgstr "" -#: search/provider/file.php:17 search/provider/file.php:35 +#: search/provider/file.php:18 search/provider/file.php:36 msgid "Files" msgstr "Filer" -#: search/provider/file.php:26 search/provider/file.php:33 +#: search/provider/file.php:27 search/provider/file.php:34 msgid "Text" msgstr "Tekst" -#: search/provider/file.php:29 +#: search/provider/file.php:30 msgid "Images" msgstr "" diff --git a/l10n/nn_NO/settings.po b/l10n/nn_NO/settings.po index 6100216bbda..761b9f46275 100644 --- a/l10n/nn_NO/settings.po +++ b/l10n/nn_NO/settings.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"PO-Revision-Date: 2013-09-24 08:30+0000\n" +"Last-Translator: unhammer \n" "Language-Team: Norwegian Nynorsk (Norway) (http://www.transifex.com/projects/p/owncloud/language/nn_NO/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -89,42 +89,42 @@ msgstr "Klarte ikkje oppdatera programmet." #: changepassword/controller.php:20 msgid "Wrong password" -msgstr "" +msgstr "Feil passord" #: changepassword/controller.php:42 msgid "No user supplied" -msgstr "" +msgstr "Ingen brukar gitt" #: changepassword/controller.php:74 msgid "" "Please provide an admin recovery password, otherwise all user data will be " "lost" -msgstr "" +msgstr "Ver venleg og gi eit admingjenopprettingspassord, elles vil all brukardata gå tapt." #: changepassword/controller.php:79 msgid "" "Wrong admin recovery password. Please check the password and try again." -msgstr "" +msgstr "Feil admingjenopprettingspassord. Ver venleg og sjekk passordet og prøv igjen." #: changepassword/controller.php:87 msgid "" "Back-end doesn't support password change, but the users encryption key was " "successfully updated." -msgstr "" +msgstr "Bakstykket støttar ikkje passordendring, men krypteringsnøkkelen til brukaren blei oppdatert." #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" -msgstr "" +msgstr "Klarte ikkje å endra passordet" #: js/apps.js:43 msgid "Update to {appversion}" msgstr "Oppdater til {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Slå av" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Slå på" @@ -132,37 +132,37 @@ msgstr "Slå på" msgid "Please wait...." msgstr "Ver venleg og vent …" -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "Klarte ikkje å skru av programmet" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "Klarte ikkje å skru på programmet" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Oppdaterer …" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Feil ved oppdatering av app" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Feil" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Oppdater" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Oppdatert" #: js/personal.js:220 msgid "Select a profile picture" -msgstr "" +msgstr "Vel eit profilbilete" #: js/personal.js:265 msgid "Decrypting files... Please wait, this can take some time." @@ -492,31 +492,31 @@ msgstr "Fyll inn e-postadressa di for å gjera passordgjenoppretting mogleg" #: templates/personal.php:86 msgid "Profile picture" -msgstr "" +msgstr "Profilbilete" #: templates/personal.php:90 msgid "Upload new" -msgstr "" +msgstr "Last opp ny" #: templates/personal.php:92 msgid "Select new from Files" -msgstr "" +msgstr "Vel ny frå Filer" #: templates/personal.php:93 msgid "Remove image" -msgstr "" +msgstr "Fjern bilete" #: templates/personal.php:94 msgid "Either png or jpg. Ideally square but you will be able to crop it." -msgstr "" +msgstr "Anten PNG eller JPG. Helst kvadratisk, men du får moglegheita til å beskjera det." #: templates/personal.php:97 msgid "Abort" -msgstr "" +msgstr "Avbryt" #: templates/personal.php:98 msgid "Choose as profile image" -msgstr "" +msgstr "Vel som profilbilete" #: templates/personal.php:106 templates/personal.php:107 msgid "Language" diff --git a/l10n/templates/core.pot b/l10n/templates/core.pot index e3ee79caef9..a57486f5ed2 100644 --- a/l10n/templates/core.pot +++ b/l10n/templates/core.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -316,7 +316,7 @@ msgstr "" #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "" @@ -336,7 +336,7 @@ msgstr "" msgid "Share" msgstr "" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "" @@ -436,23 +436,23 @@ msgstr "" msgid "share" msgstr "" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "" -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "" diff --git a/l10n/templates/files.pot b/l10n/templates/files.pot index 6dd2e8281c0..23d0cd0b17b 100644 --- a/l10n/templates/files.pot +++ b/l10n/templates/files.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:51-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_encryption.pot b/l10n/templates/files_encryption.pot index 17a33f87927..44e17a2fcb2 100644 --- a/l10n/templates/files_encryption.pot +++ b/l10n/templates/files_encryption.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:51-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_external.pot b/l10n/templates/files_external.pot index 5d1b69c53a1..abdd985cfdf 100644 --- a/l10n/templates/files_external.pot +++ b/l10n/templates/files_external.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:54-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_sharing.pot b/l10n/templates/files_sharing.pot index bc0fb489f73..34ed992660b 100644 --- a/l10n/templates/files_sharing.pot +++ b/l10n/templates/files_sharing.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:54-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_trashbin.pot b/l10n/templates/files_trashbin.pot index c0b82eeb690..45fa700a43b 100644 --- a/l10n/templates/files_trashbin.pot +++ b/l10n/templates/files_trashbin.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:54-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_versions.pot b/l10n/templates/files_versions.pot index 42221b00287..2e73cce980a 100644 --- a/l10n/templates/files_versions.pot +++ b/l10n/templates/files_versions.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:54-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/lib.pot b/l10n/templates/lib.pot index 15b4f1c6d06..0733e0c2737 100644 --- a/l10n/templates/lib.pot +++ b/l10n/templates/lib.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:56-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/settings.pot b/l10n/templates/settings.pot index 4602bc52d64..66c00629bd9 100644 --- a/l10n/templates/settings.pot +++ b/l10n/templates/settings.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:56-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -116,11 +116,11 @@ msgstr "" msgid "Update to {appversion}" msgstr "" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "" @@ -128,31 +128,31 @@ msgstr "" msgid "Please wait...." msgstr "" -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "" diff --git a/l10n/templates/user_ldap.pot b/l10n/templates/user_ldap.pot index c27848c3666..919a39b4059 100644 --- a/l10n/templates/user_ldap.pot +++ b/l10n/templates/user_ldap.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:54-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/user_webdavauth.pot b/l10n/templates/user_webdavauth.pot index e23c0a1dc54..dfb732ed0c9 100644 --- a/l10n/templates/user_webdavauth.pot +++ b/l10n/templates/user_webdavauth.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-22 12:54-0400\n" +"POT-Creation-Date: 2013-09-24 12:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/lib/l10n/nn_NO.php b/lib/l10n/nn_NO.php index d5da8c64415..e8bf8dfdef4 100644 --- a/lib/l10n/nn_NO.php +++ b/lib/l10n/nn_NO.php @@ -5,6 +5,8 @@ $TRANSLATIONS = array( "Settings" => "Innstillingar", "Users" => "Brukarar", "Admin" => "Administrer", +"Unknown filetype" => "Ukjend filtype", +"Invalid image" => "Ugyldig bilete", "web services under your control" => "Vev tjenester under din kontroll", "Authentication error" => "Feil i autentisering", "Files" => "Filer", diff --git a/settings/l10n/da.php b/settings/l10n/da.php index 9872d3f5e07..fcff9dbcfd9 100644 --- a/settings/l10n/da.php +++ b/settings/l10n/da.php @@ -16,6 +16,11 @@ $TRANSLATIONS = array( "Unable to add user to group %s" => "Brugeren kan ikke tilføjes til gruppen %s", "Unable to remove user from group %s" => "Brugeren kan ikke fjernes fra gruppen %s", "Couldn't update app." => "Kunne ikke opdatere app'en.", +"Wrong password" => "Forkert kodeord", +"No user supplied" => "Intet brugernavn givet", +"Please provide an admin recovery password, otherwise all user data will be lost" => "Angiv venligst en admininstrator gendannelseskode, ellers vil alt brugerdata gå tabt", +"Wrong admin recovery password. Please check the password and try again." => "Forkert admin gendannelseskode. Se venligst koden efter og prøv igen.", +"Back-end doesn't support password change, but the users encryption key was successfully updated." => "Serveren understøtter ikke kodeordsskifte, men brugernes krypteringsnøgle blev opdateret.", "Update to {appversion}" => "Opdatér til {appversion}", "Disable" => "Deaktiver", "Enable" => "Aktiver", diff --git a/settings/l10n/nn_NO.php b/settings/l10n/nn_NO.php index 822a17e7831..9eb31a887bd 100644 --- a/settings/l10n/nn_NO.php +++ b/settings/l10n/nn_NO.php @@ -16,6 +16,12 @@ $TRANSLATIONS = array( "Unable to add user to group %s" => "Klarte ikkje leggja til brukaren til gruppa %s", "Unable to remove user from group %s" => "Klarte ikkje fjerna brukaren frå gruppa %s", "Couldn't update app." => "Klarte ikkje oppdatera programmet.", +"Wrong password" => "Feil passord", +"No user supplied" => "Ingen brukar gitt", +"Please provide an admin recovery password, otherwise all user data will be lost" => "Ver venleg og gi eit admingjenopprettingspassord, elles vil all brukardata gå tapt.", +"Wrong admin recovery password. Please check the password and try again." => "Feil admingjenopprettingspassord. Ver venleg og sjekk passordet og prøv igjen.", +"Back-end doesn't support password change, but the users encryption key was successfully updated." => "Bakstykket støttar ikkje passordendring, men krypteringsnøkkelen til brukaren blei oppdatert.", +"Unable to change password" => "Klarte ikkje å endra passordet", "Update to {appversion}" => "Oppdater til {appversion}", "Disable" => "Slå av", "Enable" => "Slå på", @@ -27,6 +33,7 @@ $TRANSLATIONS = array( "Error" => "Feil", "Update" => "Oppdater", "Updated" => "Oppdatert", +"Select a profile picture" => "Vel eit profilbilete", "Decrypting files... Please wait, this can take some time." => "Dekrypterer filer … Ver venleg og vent, dette kan ta ei stund.", "Saving..." => "Lagrar …", "deleted" => "sletta", @@ -100,6 +107,13 @@ $TRANSLATIONS = array( "Email" => "E-post", "Your email address" => "Di epost-adresse", "Fill in an email address to enable password recovery" => "Fyll inn e-postadressa di for å gjera passordgjenoppretting mogleg", +"Profile picture" => "Profilbilete", +"Upload new" => "Last opp ny", +"Select new from Files" => "Vel ny frå Filer", +"Remove image" => "Fjern bilete", +"Either png or jpg. Ideally square but you will be able to crop it." => "Anten PNG eller JPG. Helst kvadratisk, men du får moglegheita til å beskjera det.", +"Abort" => "Avbryt", +"Choose as profile image" => "Vel som profilbilete", "Language" => "Språk", "Help translate" => "Hjelp oss å omsetja", "WebDAV" => "WebDAV", -- cgit v1.2.3 From 9e4fe103291133ea78427af18693d93bd78d2bd0 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Wed, 25 Sep 2013 10:20:40 +0200 Subject: add test for txt blacklist --- tests/lib/preview.php | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/lib/preview.php b/tests/lib/preview.php index bebdc12b500..c40b2d03ef9 100644 --- a/tests/lib/preview.php +++ b/tests/lib/preview.php @@ -92,6 +92,44 @@ class Preview extends \PHPUnit_Framework_TestCase { $this->assertEquals($image->height(), $maxY); } + public function testTxtBlacklist() { + $user = $this->initFS(); + + $x = 32; + $y = 32; + + $txt = 'random text file'; + $ics = file_get_contents(__DIR__ . '/../data/testcal.ics'); + $vcf = file_get_contents(__DIR__ . '/../data/testcontact.vcf'); + + $rootView = new \OC\Files\View(''); + $rootView->mkdir('/'.$user); + $rootView->mkdir('/'.$user.'/files'); + + $toTest = array('txt', + 'ics', + 'vcf'); + + foreach($toTest as $test) { + $sample = '/'.$user.'/files/test.'.$test; + $rootView->file_put_contents($sample, ${$test}); + $preview = new \OC\Preview($user, 'files/', 'test.'.$test, $x, $y); + $image = $preview->getPreview(); + $resource = $image->resource(); + + //http://stackoverflow.com/questions/5702953/imagecolorat-and-transparency + $colorIndex = imagecolorat($resource, 1, 1); + $colorInfo = imagecolorsforindex($resource, $colorIndex); + $isTransparent = ($colorInfo['alpha'] === 127); + + if($test === 'txt') { + $this->assertEquals($isTransparent, false); + } else { + $this->assertEquals($isTransparent, true); + } + } + } + private function initFS() { if(\OC\Files\Filesystem::getView()){ $user = \OC_User::getUser(); -- cgit v1.2.3 From b2ef978d1069d5e7e172806a9e2426de2717a1f2 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 10:30:48 +0200 Subject: AppFramework: - get request from the server container - implement registerMiddleWare() - adding getAppName() to app container --- .../dependencyinjection/dicontainer.php | 50 +++++++++++----------- lib/public/appframework/iappcontainer.php | 12 ++++++ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 2ef885d7b2c..54878266939 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -34,6 +34,8 @@ use OC\AppFramework\Utility\SimpleContainer; use OC\AppFramework\Utility\TimeFactory; use OCP\AppFramework\IApi; use OCP\AppFramework\IAppContainer; +use OCP\AppFramework\IMiddleWare; +use OCP\IServerContainer; class DIContainer extends SimpleContainer implements IAppContainer{ @@ -57,31 +59,10 @@ class DIContainer extends SimpleContainer implements IAppContainer{ * Http */ $this['Request'] = $this->share(function($c) { - - $params = array(); - - // we json decode the body only in case of content type json - if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') === true ) { - $params = json_decode(file_get_contents('php://input'), true); - $params = is_array($params) ? $params: array(); - } - - return new Request( - array( - 'get' => $_GET, - 'post' => $_POST, - 'files' => $_FILES, - 'server' => $_SERVER, - 'env' => $_ENV, - 'session' => $_SESSION, - 'cookies' => $_COOKIE, - 'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) - ? $_SERVER['REQUEST_METHOD'] - : null, - 'params' => $params, - 'urlParams' => $c['urlParams'] - ) - ); + /** @var $c SimpleContainer */ + /** @var $server IServerContainer */ + $server = $c->query('ServerContainer'); + return $server->getRequest(); }); $this['Protocol'] = $this->share(function($c){ @@ -138,4 +119,23 @@ class DIContainer extends SimpleContainer implements IAppContainer{ { return $this->query('ServerContainer'); } + + /** + * @param IMiddleWare $middleWare + * @return boolean + */ + function registerMiddleWare(IMiddleWare $middleWare) { + /** @var $dispatcher MiddlewareDispatcher */ + $dispatcher = $this->query('MiddlewareDispatcher'); + $dispatcher->registerMiddleware($middleWare); + + } + + /** + * used to return the appname of the set application + * @return string the name of your application + */ + function getAppName() { + return $this->query('AppName'); + } } diff --git a/lib/public/appframework/iappcontainer.php b/lib/public/appframework/iappcontainer.php index c8f6229dd9e..7d3b4b3bac7 100644 --- a/lib/public/appframework/iappcontainer.php +++ b/lib/public/appframework/iappcontainer.php @@ -33,6 +33,12 @@ use OCP\IContainer; */ interface IAppContainer extends IContainer{ + /** + * used to return the appname of the set application + * @return string the name of your application + */ + function getAppName(); + /** * @return IApi */ @@ -42,4 +48,10 @@ interface IAppContainer extends IContainer{ * @return \OCP\IServerContainer */ function getServer(); + + /** + * @param IMiddleWare $middleWare + * @return boolean + */ + function registerMiddleWare(IMiddleWare $middleWare); } -- cgit v1.2.3 From b168d5aa3b16501e9cb4eaa3b665939dde5de52b Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 11:05:24 +0200 Subject: class API decommissioning part 1 --- lib/appframework/core/api.php | 217 ++++----------------------------------- lib/public/appframework/iapi.php | 89 +--------------- 2 files changed, 21 insertions(+), 285 deletions(-) diff --git a/lib/appframework/core/api.php b/lib/appframework/core/api.php index 337e3b57d6d..39522ee3dd5 100644 --- a/lib/appframework/core/api.php +++ b/lib/appframework/core/api.php @@ -46,24 +46,6 @@ class API implements IApi{ } - /** - * used to return the appname of the set application - * @return string the name of your application - */ - public function getAppName(){ - return $this->appName; - } - - - /** - * Creates a new navigation entry - * @param array $entry containing: id, name, order, icon and href key - */ - public function addNavigationEntry(array $entry){ - \OCP\App::addNavigationEntry($entry); - } - - /** * Gets the userid of the current user * @return string the user id of the current user @@ -73,14 +55,6 @@ class API implements IApi{ } - /** - * Sets the current navigation entry to the currently running app - */ - public function activateNavigationEntry(){ - \OCP\App::setActiveNavigationEntry($this->appName); - } - - /** * Adds a new javascript file * @param string $scriptName the name of the javascript in js/ without the suffix @@ -124,79 +98,6 @@ class API implements IApi{ \OCP\Util::addStyle($this->appName . '/3rdparty', $name); } - /** - * Looks up a systemwide defined value - * @param string $key the key of the value, under which it was saved - * @return string the saved value - */ - public function getSystemValue($key){ - return \OCP\Config::getSystemValue($key, ''); - } - - - /** - * Sets a new systemwide value - * @param string $key the key of the value, under which will be saved - * @param string $value the value that should be stored - */ - public function setSystemValue($key, $value){ - return \OCP\Config::setSystemValue($key, $value); - } - - - /** - * Looks up an appwide defined value - * @param string $key the key of the value, under which it was saved - * @return string the saved value - */ - public function getAppValue($key, $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - return \OCP\Config::getAppValue($appName, $key, ''); - } - - - /** - * Writes a new appwide value - * @param string $key the key of the value, under which will be saved - * @param string $value the value that should be stored - */ - public function setAppValue($key, $value, $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - return \OCP\Config::setAppValue($appName, $key, $value); - } - - - - /** - * Shortcut for setting a user defined value - * @param string $key the key under which the value is being stored - * @param string $value the value that you want to store - * @param string $userId the userId of the user that we want to store the value under, defaults to the current one - */ - public function setUserValue($key, $value, $userId=null){ - if($userId === null){ - $userId = $this->getUserId(); - } - \OCP\Config::setUserValue($userId, $this->appName, $key, $value); - } - - - /** - * Shortcut for getting a user defined value - * @param string $key the key under which the value is being stored - * @param string $userId the userId of the user that we want to store the value under, defaults to the current one - */ - public function getUserValue($key, $userId=null){ - if($userId === null){ - $userId = $this->getUserId(); - } - return \OCP\Config::getUserValue($userId, $this->appName, $key); - } - /** * Returns the translation object @@ -208,28 +109,6 @@ class API implements IApi{ } - /** - * Used to abstract the owncloud database access away - * @param string $sql the sql query with ? placeholder for params - * @param int $limit the maximum number of rows - * @param int $offset from which row we want to start - * @return \OCP\DB a query object - */ - public function prepareQuery($sql, $limit=null, $offset=null){ - return \OCP\DB::prepare($sql, $limit, $offset); - } - - - /** - * Used to get the id of the just inserted element - * @param string $tableName the name of the table where we inserted the item - * @return int the id of the inserted element - */ - public function getInsertId($tableName){ - return \OCP\DB::insertid($tableName); - } - - /** * Returns the URL for a route * @param string $routeName the name of the route @@ -293,37 +172,6 @@ class API implements IApi{ } - /** - * Checks if the current user is logged in - * @return bool true if logged in - */ - public function isLoggedIn(){ - return \OCP\User::isLoggedIn(); - } - - - /** - * Checks if a user is an admin - * @param string $userId the id of the user - * @return bool true if admin - */ - public function isAdminUser($userId){ - # TODO: use public api - return \OC_User::isAdminUser($userId); - } - - - /** - * Checks if a user is an subadmin - * @param string $userId the id of the user - * @return bool true if subadmin - */ - public function isSubAdminUser($userId){ - # TODO: use public api - return \OC_SubAdmin::isSubAdmin($userId); - } - - /** * Checks if the CSRF check was correct * @return bool true if CSRF check passed @@ -371,26 +219,6 @@ class API implements IApi{ } - /** - * Returns a template - * @param string $templateName the name of the template - * @param string $renderAs how it should be rendered - * @param string $appName the name of the app - * @return \OCP\Template a new template - */ - public function getTemplate($templateName, $renderAs='user', $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - - if($renderAs === 'blank'){ - return new \OCP\Template($appName, $templateName); - } else { - return new \OCP\Template($appName, $templateName, $renderAs); - } - } - - /** * turns an owncloud path into a path on the filesystem * @param string path the path to the file on the oc filesystem @@ -467,6 +295,26 @@ class API implements IApi{ \OCP\Backgroundjob::addRegularTask($className, $methodName); } + /** + * Returns a template + * @param string $templateName the name of the template + * @param string $renderAs how it should be rendered + * @param string $appName the name of the app + * @return \OCP\Template a new template + */ + public function getTemplate($templateName, $renderAs='user', $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + + if($renderAs === 'blank'){ + return new \OCP\Template($appName, $templateName); + } else { + return new \OCP\Template($appName, $templateName, $renderAs); + } + } + + /** * Tells ownCloud to include a template in the admin overview * @param string $mainPath the path to the main php file without the php @@ -481,23 +329,6 @@ class API implements IApi{ \OCP\App::registerAdmin($appName, $mainPath); } - /** - * Do a user login - * @param string $user the username - * @param string $password the password - * @return bool true if successful - */ - public function login($user, $password) { - return \OC_User::login($user, $password); - } - - /** - * @brief Loggs the user out including all the session data - * Logout, destroys session - */ - public function logout() { - return \OCP\User::logout(); - } /** * get the filesystem info @@ -514,12 +345,4 @@ class API implements IApi{ return \OC\Files\Filesystem::getFileInfo($path); } - /** - * get the view - * - * @return OC\Files\View instance - */ - public function getView() { - return \OC\Files\Filesystem::getView(); - } } diff --git a/lib/public/appframework/iapi.php b/lib/public/appframework/iapi.php index 5374f0dcaf5..fa6af5f5965 100644 --- a/lib/public/appframework/iapi.php +++ b/lib/public/appframework/iapi.php @@ -30,19 +30,6 @@ namespace OCP\AppFramework; */ interface IApi { - /** - * used to return the appname of the set application - * @return string the name of your application - */ - function getAppName(); - - - /** - * Creates a new navigation entry - * @param array $entry containing: id, name, order, icon and href key - */ - function addNavigationEntry(array $entry); - /** * Gets the userid of the current user @@ -51,12 +38,6 @@ interface IApi { function getUserId(); - /** - * Sets the current navigation entry to the currently running app - */ - function activateNavigationEntry(); - - /** * Adds a new javascript file * @param string $scriptName the name of the javascript in js/ without the suffix @@ -86,53 +67,6 @@ interface IApi { */ function add3rdPartyStyle($name); - /** - * Looks up a system-wide defined value - * @param string $key the key of the value, under which it was saved - * @return string the saved value - */ - function getSystemValue($key); - - /** - * Sets a new system-wide value - * @param string $key the key of the value, under which will be saved - * @param string $value the value that should be stored - */ - function setSystemValue($key, $value); - - - /** - * Looks up an app-specific defined value - * @param string $key the key of the value, under which it was saved - * @return string the saved value - */ - function getAppValue($key, $appName = null); - - - /** - * Writes a new app-specific value - * @param string $key the key of the value, under which will be saved - * @param string $value the value that should be stored - */ - function setAppValue($key, $value, $appName = null); - - - /** - * Shortcut for setting a user defined value - * @param string $key the key under which the value is being stored - * @param string $value the value that you want to store - * @param string $userId the userId of the user that we want to store the value under, defaults to the current one - */ - function setUserValue($key, $value, $userId = null); - - - /** - * Shortcut for getting a user defined value - * @param string $key the key under which the value is being stored - * @param string $userId the userId of the user that we want to store the value under, defaults to the current one - */ - function getUserValue($key, $userId = null); - /** * Returns the translation object * @return \OC_L10N the translation object @@ -142,28 +76,6 @@ interface IApi { function getTrans(); - /** - * Used to abstract the owncloud database access away - * @param string $sql the sql query with ? placeholder for params - * @param int $limit the maximum number of rows - * @param int $offset from which row we want to start - * @return \OCP\DB a query object - * - * FIXME: returns non public interface / object - */ - function prepareQuery($sql, $limit=null, $offset=null); - - - /** - * Used to get the id of the just inserted element - * @param string $tableName the name of the table where we inserted the item - * @return int the id of the inserted element - * - * FIXME: move to db object - */ - function getInsertId($tableName); - - /** * Returns the URL for a route * @param string $routeName the name of the route @@ -235,4 +147,5 @@ interface IApi { * @return \OCP\Template a new template */ function getTemplate($templateName, $renderAs='user', $appName=null); + } -- cgit v1.2.3 From 30286c06ab50a04424c415d1007bac66d452208d Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 11:05:59 +0200 Subject: stripos return value check --- lib/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server.php b/lib/server.php index fccb8fad4d0..9de9f5a0566 100644 --- a/lib/server.php +++ b/lib/server.php @@ -25,7 +25,7 @@ class Server extends SimpleContainer implements IServerContainer { $params = array(); // we json decode the body only in case of content type json - if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') === true ) { + if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') !== false ) { $params = json_decode(file_get_contents('php://input'), true); $params = is_array($params) ? $params: array(); } -- cgit v1.2.3 From 24eb41548eb6fc08849619b9725cbb61679f04f6 Mon Sep 17 00:00:00 2001 From: kondou Date: Wed, 25 Sep 2013 12:57:41 +0200 Subject: Make it possible to have a different color than the username for placeholder --- core/js/placeholder.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core/js/placeholder.js b/core/js/placeholder.js index d63730547d7..3c7b11ef468 100644 --- a/core/js/placeholder.js +++ b/core/js/placeholder.js @@ -36,10 +36,22 @@ * *
T
* + * You may also call it like this, to have a different background, than the seed: + * + * $('#albumart').placeholder('The Album Title', 'Album Title'); + * + * Resulting in: + * + *
A
+ * */ (function ($) { - $.fn.placeholder = function(seed) { + $.fn.placeholder = function(seed, text) { + if (typeof(text) === "undefined") { + text = seed; + } + var hash = md5(seed), maxRange = parseInt('ffffffffffffffffffffffffffffffff', 16), hue = parseInt(hash, 16) / maxRange * 256, @@ -56,7 +68,7 @@ this.css('font-size', (height * 0.55) + 'px'); if(seed !== null && seed.length) { - this.html(seed[0].toUpperCase()); + this.html(text[0].toUpperCase()); } }; }(jQuery)); -- cgit v1.2.3 From 0486dc24adef5caf4582f54da00b8d1ee251aae6 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 14:41:03 +0200 Subject: collect coverage for all databases again - ci.owncloud.org has more RAM available --- autotest.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/autotest.sh b/autotest.sh index a343f6a25ab..83f184fa9c0 100755 --- a/autotest.sh +++ b/autotest.sh @@ -142,12 +142,7 @@ EOF rm -rf coverage-html-$1 mkdir coverage-html-$1 php -f enable_all.php - if [ "$1" == "sqlite" ] ; then - # coverage only with sqlite - causes segfault on ci.tmit.eu - reason unknown - phpunit --configuration phpunit-autotest.xml --log-junit autotest-results-$1.xml --coverage-clover autotest-clover-$1.xml --coverage-html coverage-html-$1 $2 $3 - else - phpunit --configuration phpunit-autotest.xml --log-junit autotest-results-$1.xml $2 $3 - fi + phpunit --configuration phpunit-autotest.xml --log-junit autotest-results-$1.xml --coverage-clover autotest-clover-$1.xml --coverage-html coverage-html-$1 $2 $3 } # -- cgit v1.2.3 From 1c976a7c9bd27f1fe3f2b1834fd3cbdf5f235bc1 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 25 Sep 2013 15:03:22 +0200 Subject: manager checkPassword now returns User object, adjust internal user class accordingly. --- lib/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/user.php b/lib/user.php index da774ff86f0..b5fd418acd6 100644 --- a/lib/user.php +++ b/lib/user.php @@ -419,7 +419,7 @@ class OC_User { $manager = self::getManager(); $username = $manager->checkPassword($uid, $password); if ($username !== false) { - return $manager->get($username)->getUID(); + return $username->getUID(); } return false; } -- cgit v1.2.3 From 09b64535a9099bdf9c71fa96b3aab2e49206ffde Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 17:00:20 +0200 Subject: fixing copyright and add class documentation --- apps/files/appinfo/remote.php | 1 + .../sabre/aborteduploaddetectionplugin.php | 105 +++++++++++++++++++++ lib/connector/sabre/directory.php | 13 --- 3 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 lib/connector/sabre/aborteduploaddetectionplugin.php diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php index 9b114ca2e37..0c1f2e6580c 100644 --- a/apps/files/appinfo/remote.php +++ b/apps/files/appinfo/remote.php @@ -48,6 +48,7 @@ $defaults = new OC_Defaults(); $server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, $defaults->getName())); $server->addPlugin(new Sabre_DAV_Locks_Plugin($lockBackend)); $server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload +$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin()); $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin()); $server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin()); diff --git a/lib/connector/sabre/aborteduploaddetectionplugin.php b/lib/connector/sabre/aborteduploaddetectionplugin.php new file mode 100644 index 00000000000..745c4a9942d --- /dev/null +++ b/lib/connector/sabre/aborteduploaddetectionplugin.php @@ -0,0 +1,105 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class OC_Connector_Sabre_AbortedUploadDetectionPlugin + * + * This plugin will verify if the uploaded data has been stored completely. + * This is done by comparing the content length of the request with the file size on storage. + */ +class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPlugin { + + /** + * Reference to main server object + * + * @var Sabre_DAV_Server + */ + private $server; + + /** + * is kept public to allow overwrite for unit testing + * + * @var \OC\Files\View + */ + public $fileView; + + /** + * This initializes the plugin. + * + * This function is called by Sabre_DAV_Server, after + * addPlugin is called. + * + * This method should set up the requires event subscriptions. + * + * @param Sabre_DAV_Server $server + * @return void + */ + public function initialize(Sabre_DAV_Server $server) { + + $this->server = $server; + + $server->subscribeEvent('afterCreateFile', array($this, 'afterCreateFile'), 10); + $server->subscribeEvent('afterWriteContent', array($this, 'afterWriteContent'), 10); + } + + function afterCreateFile($path, Sabre_DAV_ICollection $parent) { + + $this->verifyContentLength($path); + + } + + function afterWriteContent($path, Sabre_DAV_IFile $node) { + $path = $path .'/'.$node->getName(); + $this->verifyContentLength($path); + } + + function verifyContentLength($filePath) { + + // ownCloud chunked upload will be handled in it's own plugin + $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked'); + if ($chunkHeader) { + return; + } + + // compare expected and actual size + $expected = $this->getLength(); + $actual = $this->getFileView()->filesize($filePath); + if ($actual != $expected) { + $this->getFileView()->unlink($filePath); + throw new Sabre_DAV_Exception_BadRequest('expected filesize ' . $expected . ' got ' . $actual); + } + + } + + /** + * @return string + */ + public function getLength() + { + $req = $this->server->httpRequest; + $length = $req->getHeader('X-Expected-Entity-Length'); + if (!$length) { + $length = $req->getHeader('Content-Length'); + } + + return $length; + } + + /** + * @return \OC\Files\View + */ + public function getFileView() + { + if (is_null($this->fileView)) { + // initialize fileView + $this->fileView = \OC\Files\Filesystem::getView(); + } + + return $this->fileView; + } +} diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index 3181a4b310f..29374f7a6cf 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -74,19 +74,6 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa \OC\Files\Filesystem::file_put_contents($partpath, $data); - //detect aborted upload - if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT' ) { - if (isset($_SERVER['CONTENT_LENGTH'])) { - $expected = $_SERVER['CONTENT_LENGTH']; - $actual = \OC\Files\Filesystem::filesize($partpath); - if ($actual != $expected) { - \OC\Files\Filesystem::unlink($partpath); - throw new Sabre_DAV_Exception_BadRequest( - 'expected filesize ' . $expected . ' got ' . $actual); - } - } - } - // rename to correct path \OC\Files\Filesystem::rename($partpath, $newPath); -- cgit v1.2.3 From 5e27ac4b1ade3a78941ced1eef5aaa2d2df0cedf Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 17:17:29 +0200 Subject: $path already contains the full path to the file --- lib/connector/sabre/aborteduploaddetectionplugin.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/connector/sabre/aborteduploaddetectionplugin.php b/lib/connector/sabre/aborteduploaddetectionplugin.php index 745c4a9942d..1173ff2f9aa 100644 --- a/lib/connector/sabre/aborteduploaddetectionplugin.php +++ b/lib/connector/sabre/aborteduploaddetectionplugin.php @@ -54,7 +54,6 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl } function afterWriteContent($path, Sabre_DAV_IFile $node) { - $path = $path .'/'.$node->getName(); $this->verifyContentLength($path); } -- cgit v1.2.3 From 5e7a7b3f6187365c60e63dfed8699e525be45a0b Mon Sep 17 00:00:00 2001 From: kondou Date: Wed, 25 Sep 2013 17:19:38 +0200 Subject: Shorten optional text-argument processing --- core/js/placeholder.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/js/placeholder.js b/core/js/placeholder.js index 3c7b11ef468..ee2a8ce84c4 100644 --- a/core/js/placeholder.js +++ b/core/js/placeholder.js @@ -48,9 +48,8 @@ (function ($) { $.fn.placeholder = function(seed, text) { - if (typeof(text) === "undefined") { - text = seed; - } + // set optional argument "text" to value of "seed" if undefined + text = text || seed; var hash = md5(seed), maxRange = parseInt('ffffffffffffffffffffffffffffffff', 16), -- cgit v1.2.3 From 0c44cdd4eaa82687bce4dbbb24338b16a3f4ed13 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 17:28:45 +0200 Subject: remove unneccessary code --- .../sabre/aborteduploaddetectionplugin.php | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/connector/sabre/aborteduploaddetectionplugin.php b/lib/connector/sabre/aborteduploaddetectionplugin.php index 1173ff2f9aa..74c26f41b65 100644 --- a/lib/connector/sabre/aborteduploaddetectionplugin.php +++ b/lib/connector/sabre/aborteduploaddetectionplugin.php @@ -43,21 +43,16 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl $this->server = $server; - $server->subscribeEvent('afterCreateFile', array($this, 'afterCreateFile'), 10); - $server->subscribeEvent('afterWriteContent', array($this, 'afterWriteContent'), 10); + $server->subscribeEvent('afterCreateFile', array($this, 'verifyContentLength'), 10); + $server->subscribeEvent('afterWriteContent', array($this, 'verifyContentLength'), 10); } - function afterCreateFile($path, Sabre_DAV_ICollection $parent) { - - $this->verifyContentLength($path); - - } - - function afterWriteContent($path, Sabre_DAV_IFile $node) { - $this->verifyContentLength($path); - } - - function verifyContentLength($filePath) { + /** + * @param $filePath + * @param Sabre_DAV_INode $node + * @throws Sabre_DAV_Exception_BadRequest + */ + public function verifyContentLength($filePath, Sabre_DAV_INode $node = null) { // ownCloud chunked upload will be handled in it's own plugin $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked'); @@ -67,6 +62,9 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl // compare expected and actual size $expected = $this->getLength(); + if (!$expected) { + return; + } $actual = $this->getFileView()->filesize($filePath); if ($actual != $expected) { $this->getFileView()->unlink($filePath); -- cgit v1.2.3 From 3fa5271f10369645564f19a5706e23e0660bbbc8 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 17:34:28 +0200 Subject: adding unit tests --- .../sabre/aborteduploaddetectionplugin.php | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 tests/lib/connector/sabre/aborteduploaddetectionplugin.php diff --git a/tests/lib/connector/sabre/aborteduploaddetectionplugin.php b/tests/lib/connector/sabre/aborteduploaddetectionplugin.php new file mode 100644 index 00000000000..8237bdbd9e3 --- /dev/null +++ b/tests/lib/connector/sabre/aborteduploaddetectionplugin.php @@ -0,0 +1,93 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_OC_Connector_Sabre_AbortedUploadDetectionPlugin extends PHPUnit_Framework_TestCase { + + /** + * @var Sabre_DAV_Server + */ + private $server; + + /** + * @var OC_Connector_Sabre_AbortedUploadDetectionPlugin + */ + private $plugin; + + public function setUp() { + $this->server = new Sabre_DAV_Server(); + $this->plugin = new OC_Connector_Sabre_AbortedUploadDetectionPlugin(); + $this->plugin->initialize($this->server); + } + + /** + * @dataProvider lengthProvider + */ + public function testLength($expected, $headers) + { + $this->server->httpRequest = new Sabre_HTTP_Request($headers); + $length = $this->plugin->getLength(); + $this->assertEquals($expected, $length); + } + + /** + * @dataProvider verifyContentLengthProvider + */ + public function testVerifyContentLength($fileSize, $headers) + { + $this->plugin->fileView = $this->buildFileViewMock($fileSize); + + $this->server->httpRequest = new Sabre_HTTP_Request($headers); + $this->plugin->verifyContentLength('foo.txt'); + $this->assertTrue(true); + } + + /** + * @dataProvider verifyContentLengthFailedProvider + * @expectedException Sabre_DAV_Exception_BadRequest + */ + public function testVerifyContentLengthFailed($fileSize, $headers) + { + $this->plugin->fileView = $this->buildFileViewMock($fileSize); + + $this->server->httpRequest = new Sabre_HTTP_Request($headers); + $this->plugin->verifyContentLength('foo.txt'); + } + + public function verifyContentLengthProvider() { + return array( + array(1024, array()), + array(1024, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')), + array(512, array('HTTP_CONTENT_LENGTH' => '512')), + ); + } + + public function verifyContentLengthFailedProvider() { + return array( + array(1025, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')), + array(525, array('HTTP_CONTENT_LENGTH' => '512')), + ); + } + + public function lengthProvider() { + return array( + array(null, array()), + array(1024, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')), + array(512, array('HTTP_CONTENT_LENGTH' => '512')), + array(2048, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '2048', 'HTTP_CONTENT_LENGTH' => '1024')), + ); + } + + private function buildFileViewMock($fileSize) { + // mock filesysten + $view = $this->getMock('\OC\Files\View', array('filesize', 'unlink'), array(), '', FALSE); + $view->expects($this->any())->method('filesize')->withAnyParameters()->will($this->returnValue($fileSize)); + + return $view; + } + +} -- cgit v1.2.3 From 826c6bec8f9a8137e0a2e7660389c728b59f95d5 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 17:41:16 +0200 Subject: expect unlinkto be called --- tests/lib/connector/sabre/aborteduploaddetectionplugin.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/lib/connector/sabre/aborteduploaddetectionplugin.php b/tests/lib/connector/sabre/aborteduploaddetectionplugin.php index 8237bdbd9e3..bef0e4c4d7d 100644 --- a/tests/lib/connector/sabre/aborteduploaddetectionplugin.php +++ b/tests/lib/connector/sabre/aborteduploaddetectionplugin.php @@ -54,6 +54,10 @@ class Test_OC_Connector_Sabre_AbortedUploadDetectionPlugin extends PHPUnit_Frame { $this->plugin->fileView = $this->buildFileViewMock($fileSize); + // we expect unlink to be called + $this->plugin->fileView->expects($this->once())->method('unlink'); + + $this->server->httpRequest = new Sabre_HTTP_Request($headers); $this->plugin->verifyContentLength('foo.txt'); } -- cgit v1.2.3 From 71bbb2ea8bd76697cc1785fe4324b54973c410b9 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 25 Sep 2013 17:44:05 +0200 Subject: check if key exists before reading it --- apps/files_encryption/lib/keymanager.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 9be3dda7ce3..7143fcff0f6 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -40,11 +40,14 @@ class Keymanager { public static function getPrivateKey(\OC_FilesystemView $view, $user) { $path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key'; + $key = false; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $key = $view->file_get_contents($path); + if ($view->file_exists($path)) { + $key = $view->file_get_contents($path); + } \OC_FileProxy::$enabled = $proxyStatus; -- cgit v1.2.3 From b5ac672864b6d7ac892de0b4c36debd61e4a1588 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 25 Sep 2013 19:15:27 +0200 Subject: Missing Test for the previous commit --- tests/lib/user.php | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/lib/user.php diff --git a/tests/lib/user.php b/tests/lib/user.php new file mode 100644 index 00000000000..66c7f3f0d74 --- /dev/null +++ b/tests/lib/user.php @@ -0,0 +1,43 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test; + +use OC\Hooks\PublicEmitter; + +class User extends \PHPUnit_Framework_TestCase { + + public function testCheckPassword() { + /** + * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend + */ + $backend = $this->getMock('\OC_User_Dummy'); + $backend->expects($this->once()) + ->method('checkPassword') + ->with($this->equalTo('foo'), $this->equalTo('bar')) + ->will($this->returnValue('foo')); + + $backend->expects($this->any()) + ->method('implementsActions') + ->will($this->returnCallback(function ($actions) { + if ($actions === \OC_USER_BACKEND_CHECK_PASSWORD) { + return true; + } else { + return false; + } + })); + + $manager = \OC_User::getManager(); + $manager->registerBackend($backend); + + $uid = \OC_User::checkPassword('foo', 'bar'); + $this->assertEquals($uid, 'foo'); + } + +} \ No newline at end of file -- cgit v1.2.3 From 0b98427536d9ff951577273af096c0a4ab219a83 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 25 Sep 2013 19:23:07 +0200 Subject: fix check if app is enabled --- apps/files_encryption/lib/proxy.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index eb7ba60cb9d..4ec810a5199 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -50,9 +50,8 @@ class Proxy extends \OC_FileProxy { private static function shouldEncrypt($path) { if (is_null(self::$enableEncryption)) { - if ( - \OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') === 'true' + \OCP\App::isEnabled('files_encryption') === true && Crypt::mode() === 'server' ) { @@ -200,7 +199,7 @@ class Proxy extends \OC_FileProxy { */ public function preUnlink($path) { - // let the trashbin handle this + // let the trashbin handle this if (\OCP\App::isEnabled('files_trashbin')) { return true; } @@ -291,7 +290,7 @@ class Proxy extends \OC_FileProxy { // Close the original encrypted file fclose($result); - // Open the file using the crypto stream wrapper + // Open the file using the crypto stream wrapper // protocol and let it do the decryption work instead $result = fopen('crypt://' . $path, $meta['mode']); -- cgit v1.2.3 From b11d8799c17b24e7823de8d8dc171fb78f9b8442 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Thu, 26 Sep 2013 10:50:15 +0200 Subject: adding unit tests for ObjectTree::move() --- lib/connector/sabre/objecttree.php | 44 ++++++++----- tests/lib/connector/sabre/objecttree.php | 104 +++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 tests/lib/connector/sabre/objecttree.php diff --git a/lib/connector/sabre/objecttree.php b/lib/connector/sabre/objecttree.php index 7accf98c8e1..80c3840b99d 100644 --- a/lib/connector/sabre/objecttree.php +++ b/lib/connector/sabre/objecttree.php @@ -11,6 +11,14 @@ namespace OC\Connector\Sabre; use OC\Files\Filesystem; class ObjectTree extends \Sabre_DAV_ObjectTree { + + /** + * keep this public to allow mock injection during unit test + * + * @var \OC\Files\View + */ + public $fileView; + /** * Returns the INode object for the requested path * @@ -21,14 +29,16 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { public function getNodeForPath($path) { $path = trim($path, '/'); - if (isset($this->cache[$path])) return $this->cache[$path]; + if (isset($this->cache[$path])) { + return $this->cache[$path]; + } // Is it the root node? if (!strlen($path)) { return $this->rootNode; } - $info = Filesystem::getFileInfo($path); + $info = $this->getFileView()->getFileInfo($path); if (!$info) { throw new \Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); @@ -65,25 +75,21 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destinationPath); // check update privileges - if ($sourceDir === $destinationDir) { - // for renaming it's enough to check if the sourcePath can be updated - if (!\OC\Files\Filesystem::isUpdatable($sourcePath)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - } else { + $fs = $this->getFileView(); + if (!$fs->isUpdatable($sourcePath)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + if ($sourceDir !== $destinationDir) { // for a full move we need update privileges on sourcePath and sourceDir as well as destinationDir - if (!\OC\Files\Filesystem::isUpdatable($sourcePath)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - if (!\OC\Files\Filesystem::isUpdatable($sourceDir)) { + if (!$fs->isUpdatable($sourceDir)) { throw new \Sabre_DAV_Exception_Forbidden(); } - if (!\OC\Files\Filesystem::isUpdatable($destinationDir)) { + if (!$fs->isUpdatable($destinationDir)) { throw new \Sabre_DAV_Exception_Forbidden(); } } - $renameOkay = Filesystem::rename($sourcePath, $destinationPath); + $renameOkay = $fs->rename($sourcePath, $destinationPath); if (!$renameOkay) { throw new \Sabre_DAV_Exception_Forbidden(''); } @@ -123,4 +129,14 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destination); $this->markDirty($destinationDir); } + + /** + * @return \OC\Files\View + */ + public function getFileView() { + if (is_null($this->fileView)) { + $this->fileView = \OC\Files\Filesystem::getView(); + } + return $this->fileView; + } } diff --git a/tests/lib/connector/sabre/objecttree.php b/tests/lib/connector/sabre/objecttree.php new file mode 100644 index 00000000000..c920441c8b4 --- /dev/null +++ b/tests/lib/connector/sabre/objecttree.php @@ -0,0 +1,104 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\OC\Connector\Sabre; + + +use OC_Connector_Sabre_Directory; +use PHPUnit_Framework_TestCase; +use Sabre_DAV_Exception_Forbidden; + +class TestDoubleFileView extends \OC\Files\View{ + + public function __construct($updatables, $canRename = true) { + $this->updatables = $updatables; + $this->canRename = $canRename; + } + + public function isUpdatable($path) { + return $this->updatables[$path]; + } + + public function rename($path1, $path2) { + return $this->canRename; + } +} + +class ObjectTree extends PHPUnit_Framework_TestCase { + + /** + * @dataProvider moveFailedProvider + * @expectedException Sabre_DAV_Exception_Forbidden + */ + public function testMoveFailed($source, $dest, $updatables) { + $rootDir = new OC_Connector_Sabre_Directory(''); + $objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree', + array('nodeExists', 'getNodeForPath'), + array($rootDir)); + + $objectTree->expects($this->once()) + ->method('getNodeForPath') + ->with($this->identicalTo('a/b')) + ->will($this->returnValue(false)); + + /** @var $objectTree \OC\Connector\Sabre\ObjectTree */ + $objectTree->fileView = new TestDoubleFileView($updatables); + $objectTree->move($source, $dest); + } + + /** + * @dataProvider moveSuccessProvider + */ + public function testMoveSuccess($source, $dest, $updatables) { + $rootDir = new OC_Connector_Sabre_Directory(''); + $objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree', + array('nodeExists', 'getNodeForPath'), + array($rootDir)); + + $objectTree->expects($this->once()) + ->method('getNodeForPath') + ->with($this->identicalTo('a/b')) + ->will($this->returnValue(false)); + + /** @var $objectTree \OC\Connector\Sabre\ObjectTree */ + $objectTree->fileView = new TestDoubleFileView($updatables); + $objectTree->move($source, $dest); + $this->assertTrue(true); + } + + function moveFailedProvider() { + return array( + array('a/b', 'a/c', array('a' => false, 'a/b' => false, 'a/c' => false)), + array('a/b', 'b/b', array('a' => false, 'a/b' => false, 'b' => false, 'b/b' => false)), + array('a/b', 'b/b', array('a' => false, 'a/b' => true, 'b' => false, 'b/b' => false)), + array('a/b', 'b/b', array('a' => true, 'a/b' => true, 'b' => false, 'b/b' => false)), + ); + } + + function moveSuccessProvider() { + return array( + array('a/b', 'a/c', array('a' => false, 'a/b' => true, 'a/c' => false)), + array('a/b', 'b/b', array('a' => true, 'a/b' => true, 'b' => true, 'b/b' => false)), + ); + } + +// private function buildFileViewMock($updatables) { +// // mock filesysten +// $view = $this->getMock('\OC\Files\View', array('isUpdatable'), array(), '', FALSE); +// +// foreach ($updatables as $path => $updatable) { +// $view->expects($this->any()) +// ->method('isUpdatable') +// ->with($this->identicalTo($path)) +// ->will($this->returnValue($updatable)); +// } +// +// return $view; +// } + +} -- cgit v1.2.3 From d1b5d65622122b71dfb46cd5d1addf514552032a Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Thu, 26 Sep 2013 12:02:06 +0200 Subject: run unit tests for apps as well --- tests/bootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index fb667263e45..d273676f4c6 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,7 +1,7 @@ Date: Thu, 26 Sep 2013 13:34:47 +0200 Subject: prelogin apps have to be loaded within setupBackend() otherwise required classes cannot be loaded --- lib/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/user.php b/lib/user.php index da774ff86f0..62c2f318ccc 100644 --- a/lib/user.php +++ b/lib/user.php @@ -177,6 +177,7 @@ class OC_User { * setup the configured backends in config.php */ public static function setupBackends() { + OC_App::loadApps(array('prelogin')); $backends = OC_Config::getValue('user_backends', array()); foreach ($backends as $i => $config) { $class = $config['class']; -- cgit v1.2.3 From f8933eaf922c82c369b48275510ad6920ac70b47 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Thu, 26 Sep 2013 14:03:04 +0200 Subject: Remove $RUNTIME_NOAPPS - setting to false was not enough --- tests/bootstrap.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index d273676f4c6..581cfcff9f3 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,7 +1,5 @@ Date: Thu, 26 Sep 2013 19:05:47 +0200 Subject: phpunit.xml: Port code coverage excludes from autotest to dist. --- tests/phpunit.xml.dist | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/phpunit.xml.dist b/tests/phpunit.xml.dist index 25dfc64cfeb..71a4ff2762c 100644 --- a/tests/phpunit.xml.dist +++ b/tests/phpunit.xml.dist @@ -11,7 +11,21 @@ .. ../3rdparty + ../apps/files/l10n + ../apps/files_external/l10n + ../apps/files_external/3rdparty + ../apps/files_versions/l10n + ../apps/files_encryption/l10n + ../apps/files_encryption/3rdparty + ../apps/files_sharing/l10n + ../apps/files_trashbin/l10n + ../apps/user_ldap/l10n + ../apps/user_webdavauth/l10n ../lib/MDB2 + ../lib/l10n + ../core/l10n + ../settings/l10n + ../tests -- cgit v1.2.3 From 9bb244cc59504b3686b58183315d046084b05fa6 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 26 Sep 2013 19:34:28 +0200 Subject: check every enabled app if the remember login feature needs to be disabled --- lib/util.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/util.php b/lib/util.php index e12f753d5ae..e1bec4aece3 100755 --- a/lib/util.php +++ b/lib/util.php @@ -511,13 +511,23 @@ class OC_Util { /** * Check if it is allowed to remember login. - * E.g. if encryption is enabled the user needs to log-in every time he visites - * ownCloud in order to decrypt the private key. + * + * @note Every app can set 'rememberlogin' to 'false' to disable the remember login feature * * @return bool */ public static function rememberLoginAllowed() { - return !OC_App::isEnabled('files_encryption'); + + $apps = OC_App::getEnabledApps(); + + foreach ($apps as $app) { + $appInfo = OC_App::getAppInfo($app); + if (isset($appInfo['rememberlogin']) && $appInfo['rememberlogin'] === 'false') { + return false; + } + + } + return true; } /** -- cgit v1.2.3 From 7e54e8831e1004575ed9feab9a65f11365e4a473 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 26 Sep 2013 19:34:50 +0200 Subject: set rememberlogin to false for the encryption app --- apps/files_encryption/appinfo/info.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml index 46f1375c987..9d495916d26 100644 --- a/apps/files_encryption/appinfo/info.xml +++ b/apps/files_encryption/appinfo/info.xml @@ -7,6 +7,7 @@ Sam Tuke, Bjoern Schiessle, Florin Peter 4 true + false -- cgit v1.2.3 From f31d31844e0a498ccb0364fa618d55b33cc30236 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Fri, 27 Sep 2013 00:02:30 -0400 Subject: [tx-robot] updated from transifex --- apps/files/l10n/el.php | 1 + apps/files/l10n/hu_HU.php | 13 ++++++++++--- apps/files_trashbin/l10n/hu_HU.php | 4 ++-- apps/user_ldap/l10n/hu_HU.php | 8 ++++++++ core/l10n/cs_CZ.php | 1 + core/l10n/da.php | 2 ++ core/l10n/fr.php | 5 +++++ l10n/cs_CZ/core.po | 22 +++++++++++----------- l10n/da/core.po | 22 +++++++++++----------- l10n/da/lib.po | 18 +++++++++--------- l10n/da/settings.po | 6 +++--- l10n/el/files.po | 11 ++++++----- l10n/fr/core.po | 16 ++++++++-------- l10n/fr/settings.po | 30 +++++++++++++++--------------- l10n/hu_HU/files.po | 34 +++++++++++++++++----------------- l10n/hu_HU/files_trashbin.po | 30 +++++++++++++++--------------- l10n/hu_HU/user_ldap.po | 22 +++++++++++----------- l10n/templates/core.pot | 2 +- l10n/templates/files.pot | 2 +- l10n/templates/files_encryption.pot | 2 +- l10n/templates/files_external.pot | 2 +- l10n/templates/files_sharing.pot | 2 +- l10n/templates/files_trashbin.pot | 2 +- l10n/templates/files_versions.pot | 2 +- l10n/templates/lib.pot | 2 +- l10n/templates/settings.pot | 2 +- l10n/templates/user_ldap.pot | 2 +- l10n/templates/user_webdavauth.pot | 2 +- lib/l10n/da.php | 3 +++ settings/l10n/da.php | 1 + settings/l10n/fr.php | 3 +++ 31 files changed, 153 insertions(+), 121 deletions(-) diff --git a/apps/files/l10n/el.php b/apps/files/l10n/el.php index 37a61c6b956..de524f4dd90 100644 --- a/apps/files/l10n/el.php +++ b/apps/files/l10n/el.php @@ -41,6 +41,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Ο αποθηκευτικός χώρος είναι σχεδόν γεμάτος ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Η κρυπτογράφηση απενεργοποιήθηκε, αλλά τα αρχεία σας είναι ακόμα κρυπτογραφημένα. Παρακαλούμε απενεργοποιήσετε την κρυπτογράφηση αρχείων από τις προσωπικές σας ρυθμίσεις", "Your download is being prepared. This might take some time if the files are big." => "Η λήψη προετοιμάζεται. Αυτό μπορεί να πάρει ώρα εάν τα αρχεία έχουν μεγάλο μέγεθος.", +"Error moving file" => "Σφάλμα κατά τη μετακίνηση του αρχείου", "Name" => "Όνομα", "Size" => "Μέγεθος", "Modified" => "Τροποποιήθηκε", diff --git a/apps/files/l10n/hu_HU.php b/apps/files/l10n/hu_HU.php index 5d313ff2488..4dd6a13d320 100644 --- a/apps/files/l10n/hu_HU.php +++ b/apps/files/l10n/hu_HU.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Hiányzik egy ideiglenes mappa", "Failed to write to disk" => "Nem sikerült a lemezre történő írás", "Not enough storage available" => "Nincs elég szabad hely.", +"Upload failed. Could not get file info." => "A feltöltés nem sikerült. Az állományt leíró információk nem érhetők el.", +"Upload failed. Could not find uploaded file" => "A feltöltés nem sikerült. Nem található a feltöltendő állomány.", "Invalid directory." => "Érvénytelen mappa.", "Files" => "Fájlok", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "A(z) {filename} állomány nem tölthető fel, mert ez vagy egy mappa, vagy pedig 0 bájtból áll.", "Not enough space available" => "Nincs elég szabad hely", "Upload cancelled." => "A feltöltést megszakítottuk.", +"Could not get result from server." => "A kiszolgálótól nem kapható meg az eredmény.", "File upload is in progress. Leaving the page now will cancel the upload." => "Fájlfeltöltés van folyamatban. Az oldal elhagyása megszakítja a feltöltést.", "URL cannot be empty." => "Az URL nem lehet semmi.", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Érvénytelen mappanév. A 'Shared' az ownCloud számára fenntartott elnevezés", @@ -31,15 +35,18 @@ $TRANSLATIONS = array( "cancel" => "mégse", "replaced {new_name} with {old_name}" => "{new_name} fájlt kicseréltük ezzel: {old_name}", "undo" => "visszavonás", -"_%n folder_::_%n folders_" => array("",""), -"_%n file_::_%n files_" => array("",""), -"_Uploading %n file_::_Uploading %n files_" => array("",""), +"_%n folder_::_%n folders_" => array("%n mappa","%n mappa"), +"_%n file_::_%n files_" => array("%n állomány","%n állomány"), +"{dirs} and {files}" => "{dirs} és {files}", +"_Uploading %n file_::_Uploading %n files_" => array("%n állomány feltöltése","%n állomány feltöltése"), "'.' is an invalid file name." => "'.' fájlnév érvénytelen.", "File name cannot be empty." => "A fájlnév nem lehet semmi.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Érvénytelen elnevezés. Ezek a karakterek nem használhatók: '\\', '/', '<', '>', ':', '\"', '|', '?' és '*'", "Your storage is full, files can not be updated or synced anymore!" => "A tároló tele van, a fájlok nem frissíthetőek vagy szinkronizálhatóak a jövőben.", "Your storage is almost full ({usedSpacePercent}%)" => "A tároló majdnem tele van ({usedSpacePercent}%)", +"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "A titkosítási funkciót kikapcsolták, de az Ön állományai még mindig titkosított állapotban vannak. A személyes beállításoknál tudja a titkosítást feloldani.", "Your download is being prepared. This might take some time if the files are big." => "Készül a letöltendő állomány. Ez eltarthat egy ideig, ha nagyok a fájlok.", +"Error moving file" => "Az állomány áthelyezése nem sikerült.", "Name" => "Név", "Size" => "Méret", "Modified" => "Módosítva", diff --git a/apps/files_trashbin/l10n/hu_HU.php b/apps/files_trashbin/l10n/hu_HU.php index aac6cf78000..766ddcbce4d 100644 --- a/apps/files_trashbin/l10n/hu_HU.php +++ b/apps/files_trashbin/l10n/hu_HU.php @@ -8,8 +8,8 @@ $TRANSLATIONS = array( "Delete permanently" => "Végleges törlés", "Name" => "Név", "Deleted" => "Törölve", -"_%n folder_::_%n folders_" => array("",""), -"_%n file_::_%n files_" => array("",""), +"_%n folder_::_%n folders_" => array("","%n mappa"), +"_%n file_::_%n files_" => array("","%n állomány"), "restored" => "visszaállítva", "Nothing in here. Your trash bin is empty!" => "Itt nincs semmi. Az Ön szemetes mappája üres!", "Restore" => "Visszaállítás", diff --git a/apps/user_ldap/l10n/hu_HU.php b/apps/user_ldap/l10n/hu_HU.php index 6961869f3e0..b41cf98e2b9 100644 --- a/apps/user_ldap/l10n/hu_HU.php +++ b/apps/user_ldap/l10n/hu_HU.php @@ -16,6 +16,7 @@ $TRANSLATIONS = array( "Connection test failed" => "A kapcsolatellenőrzés eredménye: nem sikerült", "Do you really want to delete the current Server Configuration?" => "Tényleg törölni szeretné a kiszolgáló beállításait?", "Confirm Deletion" => "A törlés megerősítése", +"Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behavior. Please ask your system administrator to disable one of them." => "Figyelem: a user_ldap és user_webdavauth alkalmazások nem kompatibilisek. Együttes használatuk váratlan eredményekhez vezethet. Kérje meg a rendszergazdát, hogy a kettő közül kapcsolja ki az egyiket.", "Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Figyelmeztetés: Az LDAP PHP modul nincs telepítve, ezért ez az alrendszer nem fog működni. Kérje meg a rendszergazdát, hogy telepítse!", "Server configuration" => "A kiszolgálók beállításai", "Add Server Configuration" => "Új kiszolgáló beállításának hozzáadása", @@ -29,8 +30,11 @@ $TRANSLATIONS = array( "Password" => "Jelszó", "For anonymous access, leave DN and Password empty." => "Bejelentkezés nélküli eléréshez ne töltse ki a DN és Jelszó mezőket!", "User Login Filter" => "Szűrő a bejelentkezéshez", +"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" => "Ez a szűrő érvényes a bejelentkezés megkísérlésekor. Ekkor az %%uid változó helyére a bejelentkezési név kerül. Például: \"uid=%%uid\"", "User List Filter" => "A felhasználók szűrője", +"Defines the filter to apply, when retrieving users (no placeholders). Example: \"objectClass=person\"" => "Ez a szűrő érvényes a felhasználók listázásakor (nincs helyettesíthető változó). Például: \"objectClass=person\"", "Group Filter" => "A csoportok szűrője", +"Defines the filter to apply, when retrieving groups (no placeholders). Example: \"objectClass=posixGroup\"" => "Ez a szűrő érvényes a csoportok listázásakor (nincs helyettesíthető változó). Például: \"objectClass=posixGroup\"", "Connection Settings" => "Kapcsolati beállítások", "Configuration Active" => "A beállítás aktív", "When unchecked, this configuration will be skipped." => "Ha nincs kipipálva, ez a beállítás kihagyódik.", @@ -39,19 +43,23 @@ $TRANSLATIONS = array( "Give an optional backup host. It must be a replica of the main LDAP/AD server." => "Adjon meg egy opcionális másodkiszolgálót. Ez a fő LDAP/AD kiszolgáló szinkron másolata (replikája) kell legyen.", "Backup (Replica) Port" => "A másodkiszolgáló (replika) portszáma", "Disable Main Server" => "A fő szerver kihagyása", +"Only connect to the replica server." => "Csak a másodlagos (másolati) kiszolgálóhoz kapcsolódjunk.", "Use TLS" => "Használjunk TLS-t", "Do not use it additionally for LDAPS connections, it will fail." => "LDAPS kapcsolatok esetén ne kapcsoljuk be, mert nem fog működni.", "Case insensitve LDAP server (Windows)" => "Az LDAP-kiszolgáló nem tesz különbséget a kis- és nagybetűk között (Windows)", "Turn off SSL certificate validation." => "Ne ellenőrizzük az SSL-tanúsítvány érvényességét", +"Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Használata nem javasolt (kivéve tesztelési céllal). Ha a kapcsolat csak ezzel a beállítással működik, akkor importálja az LDAP-kiszolgáló SSL tanúsítványát a(z) %s kiszolgálóra!", "Cache Time-To-Live" => "A gyorsítótár tárolási időtartama", "in seconds. A change empties the cache." => "másodpercben. A változtatás törli a cache tartalmát.", "Directory Settings" => "Címtár beállítások", "User Display Name Field" => "A felhasználónév mezője", +"The LDAP attribute to use to generate the user's display name." => "Ebből az LDAP attribútumból képződik a felhasználó megjelenítendő neve.", "Base User Tree" => "A felhasználói fa gyökere", "One User Base DN per line" => "Soronként egy felhasználói fa gyökerét adhatjuk meg", "User Search Attributes" => "A felhasználók lekérdezett attribútumai", "Optional; one attribute per line" => "Nem kötelező megadni, soronként egy attribútum", "Group Display Name Field" => "A csoport nevének mezője", +"The LDAP attribute to use to generate the groups's display name." => "Ebből az LDAP attribútumból képződik a csoport megjelenítendő neve.", "Base Group Tree" => "A csoportfa gyökere", "One Group Base DN per line" => "Soronként egy csoportfa gyökerét adhatjuk meg", "Group Search Attributes" => "A csoportok lekérdezett attribútumai", diff --git a/core/l10n/cs_CZ.php b/core/l10n/cs_CZ.php index 449a49f5686..abed4a0fdac 100644 --- a/core/l10n/cs_CZ.php +++ b/core/l10n/cs_CZ.php @@ -59,6 +59,7 @@ $TRANSLATIONS = array( "Ok" => "Ok", "Error loading message template: {error}" => "Chyba při nahrávání šablony zprávy: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("","",""), +"One file conflict" => "Jeden konflikt souboru", "Cancel" => "Zrušit", "The object type is not specified." => "Není určen typ objektu.", "Error" => "Chyba", diff --git a/core/l10n/da.php b/core/l10n/da.php index e2399fdc5cc..8938f2107fa 100644 --- a/core/l10n/da.php +++ b/core/l10n/da.php @@ -16,6 +16,8 @@ $TRANSLATIONS = array( "Error adding %s to favorites." => "Fejl ved tilføjelse af %s til favoritter.", "No categories selected for deletion." => "Ingen kategorier valgt", "Error removing %s from favorites." => "Fejl ved fjernelse af %s fra favoritter.", +"Unknown filetype" => "Ukendt filtype", +"Invalid image" => "Ugyldigt billede", "Sunday" => "Søndag", "Monday" => "Mandag", "Tuesday" => "Tirsdag", diff --git a/core/l10n/fr.php b/core/l10n/fr.php index 29489e86b7f..e7cb75e53f0 100644 --- a/core/l10n/fr.php +++ b/core/l10n/fr.php @@ -19,6 +19,8 @@ $TRANSLATIONS = array( "No image or file provided" => "Aucune image ou fichier fourni", "Unknown filetype" => "Type de fichier inconnu", "Invalid image" => "Image invalide", +"No temporary profile picture available, try again" => "Aucune image temporaire disponible pour le profil. Essayez à nouveau.", +"No crop data provided" => "Aucune donnée de culture fournie", "Sunday" => "Dimanche", "Monday" => "Lundi", "Tuesday" => "Mardi", @@ -61,7 +63,10 @@ $TRANSLATIONS = array( "Which files do you want to keep?" => "Quels fichiers désirez-vous garder ?", "If you select both versions, the copied file will have a number added to its name." => "Si vous sélectionnez les deux versions, un nombre sera ajouté au nom du fichier copié.", "Cancel" => "Annuler", +"Continue" => "Poursuivre", +"(all selected)" => "(tous sélectionnés)", "({count} selected)" => "({count} sélectionnés)", +"Error loading file exists template" => "Erreur de chargement du modèle de fichier existant", "The object type is not specified." => "Le type d'objet n'est pas spécifié.", "Error" => "Erreur", "The app name is not specified." => "Le nom de l'application n'est pas spécifié.", diff --git a/l10n/cs_CZ/core.po b/l10n/cs_CZ/core.po index 61a7e861b2a..40b693b988a 100644 --- a/l10n/cs_CZ/core.po +++ b/l10n/cs_CZ/core.po @@ -12,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-25 10:50+0000\n" +"Last-Translator: pstast \n" "Language-Team: Czech (Czech Republic) (http://www.transifex.com/projects/p/owncloud/language/cs_CZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -284,7 +284,7 @@ msgstr[2] "" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "Jeden konflikt souboru" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" @@ -325,7 +325,7 @@ msgstr "Není určen typ objektu." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Chyba" @@ -345,7 +345,7 @@ msgstr "Sdílené" msgid "Share" msgstr "Sdílet" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Chyba při sdílení" @@ -445,23 +445,23 @@ msgstr "smazat" msgid "share" msgstr "sdílet" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Chráněno heslem" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Chyba při odstraňování data vypršení platnosti" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Chyba při nastavení data vypršení platnosti" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Odesílám ..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "E-mail odeslán" diff --git a/l10n/da/core.po b/l10n/da/core.po index 690bb46c211..89530e07456 100644 --- a/l10n/da/core.po +++ b/l10n/da/core.po @@ -11,8 +11,8 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-24 17:20+0000\n" "Last-Translator: I Robot \n" "Language-Team: Danish (http://www.transifex.com/projects/p/owncloud/language/da/)\n" "MIME-Version: 1.0\n" @@ -100,11 +100,11 @@ msgstr "" #: avatar/controller.php:81 msgid "Unknown filetype" -msgstr "" +msgstr "Ukendt filtype" #: avatar/controller.php:85 msgid "Invalid image" -msgstr "" +msgstr "Ugyldigt billede" #: avatar/controller.php:115 avatar/controller.php:142 msgid "No temporary profile picture available, try again" @@ -319,7 +319,7 @@ msgstr "Objekttypen er ikke angivet." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Fejl" @@ -339,7 +339,7 @@ msgstr "Delt" msgid "Share" msgstr "Del" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Fejl under deling" @@ -439,23 +439,23 @@ msgstr "slet" msgid "share" msgstr "del" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Beskyttet med adgangskode" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Fejl ved fjernelse af udløbsdato" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Fejl under sætning af udløbsdato" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Sender ..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "E-mail afsendt" diff --git a/l10n/da/lib.po b/l10n/da/lib.po index 0bacfcf5e8a..7d01d7a9691 100644 --- a/l10n/da/lib.po +++ b/l10n/da/lib.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-16 11:33-0400\n" -"PO-Revision-Date: 2013-09-16 15:34+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-24 17:20+0000\n" +"Last-Translator: Sappe\n" "Language-Team: Danish (http://www.transifex.com/projects/p/owncloud/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -58,15 +58,15 @@ msgstr "Upgradering af \"%s\" fejlede" #: avatar.php:56 msgid "Custom profile pictures don't work with encryption yet" -msgstr "" +msgstr "Personligt profilbillede virker endnu ikke sammen med kryptering" #: avatar.php:64 msgid "Unknown filetype" -msgstr "" +msgstr "Ukendt filtype" #: avatar.php:69 msgid "Invalid image" -msgstr "" +msgstr "Ugyldigt billede" #: defaults.php:35 msgid "web services under your control" @@ -167,15 +167,15 @@ msgstr "Adgangsfejl" msgid "Token expired. Please reload page." msgstr "Adgang er udløbet. Genindlæs siden." -#: search/provider/file.php:17 search/provider/file.php:35 +#: search/provider/file.php:18 search/provider/file.php:36 msgid "Files" msgstr "Filer" -#: search/provider/file.php:26 search/provider/file.php:33 +#: search/provider/file.php:27 search/provider/file.php:34 msgid "Text" msgstr "SMS" -#: search/provider/file.php:29 +#: search/provider/file.php:30 msgid "Images" msgstr "Billeder" diff --git a/l10n/da/settings.po b/l10n/da/settings.po index 7251a13d4ff..e5f2b57e882 100644 --- a/l10n/da/settings.po +++ b/l10n/da/settings.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" -"PO-Revision-Date: 2013-09-24 16:59+0000\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-24 17:00+0000\n" "Last-Translator: Sappe\n" "Language-Team: Danish (http://www.transifex.com/projects/p/owncloud/language/da/)\n" "MIME-Version: 1.0\n" @@ -114,7 +114,7 @@ msgstr "Serveren understøtter ikke kodeordsskifte, men brugernes krypteringsnø #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" -msgstr "" +msgstr "Kunne ikke ændre kodeord" #: js/apps.js:43 msgid "Update to {appversion}" diff --git a/l10n/el/files.po b/l10n/el/files.po index f6b7bcf82a4..87c112acc67 100644 --- a/l10n/el/files.po +++ b/l10n/el/files.po @@ -5,14 +5,15 @@ # Translators: # Efstathios Iosifidis , 2013 # Efstathios Iosifidis , 2013 +# gtsamis , 2013 # frerisp , 2013 msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-25 12:10+0000\n" +"Last-Translator: gtsamis \n" "Language-Team: Greek (http://www.transifex.com/projects/p/owncloud/language/el/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -89,7 +90,7 @@ msgstr "" msgid "Invalid directory." msgstr "Μη έγκυρος φάκελος." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Αρχεία" @@ -224,7 +225,7 @@ msgstr "Η λήψη προετοιμάζεται. Αυτό μπορεί να π #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Σφάλμα κατά τη μετακίνηση του αρχείου" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/fr/core.po b/l10n/fr/core.po index 4c7f6be045a..bce932689a0 100644 --- a/l10n/fr/core.po +++ b/l10n/fr/core.po @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" -"PO-Revision-Date: 2013-09-23 19:40+0000\n" -"Last-Translator: ogre_sympathique \n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-26 15:10+0000\n" +"Last-Translator: Christophe Lherieau \n" "Language-Team: French (http://www.transifex.com/projects/p/owncloud/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -110,11 +110,11 @@ msgstr "Image invalide" #: avatar/controller.php:115 avatar/controller.php:142 msgid "No temporary profile picture available, try again" -msgstr "" +msgstr "Aucune image temporaire disponible pour le profil. Essayez à nouveau." #: avatar/controller.php:135 msgid "No crop data provided" -msgstr "" +msgstr "Aucune donnée de culture fournie" #: js/config.php:32 msgid "Sunday" @@ -298,11 +298,11 @@ msgstr "Annuler" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Poursuivre" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(tous sélectionnés)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" @@ -310,7 +310,7 @@ msgstr "({count} sélectionnés)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "Erreur de chargement du modèle de fichier existant" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 diff --git a/l10n/fr/settings.po b/l10n/fr/settings.po index 529e2e8c356..21918cf68da 100644 --- a/l10n/fr/settings.po +++ b/l10n/fr/settings.po @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-26 15:00+0000\n" +"Last-Translator: Christophe Lherieau \n" "Language-Team: French (http://www.transifex.com/projects/p/owncloud/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -102,18 +102,18 @@ msgstr "Aucun utilisateur fourni" msgid "" "Please provide an admin recovery password, otherwise all user data will be " "lost" -msgstr "" +msgstr "Veuillez fournir un mot de passe administrateur de récupération de données, sinon toutes les données de l'utilisateur seront perdues" #: changepassword/controller.php:79 msgid "" "Wrong admin recovery password. Please check the password and try again." -msgstr "" +msgstr "Mot de passe administrateur de récupération de données invalide. Veuillez vérifier le mot de passe et essayer à nouveau." #: changepassword/controller.php:87 msgid "" "Back-end doesn't support password change, but the users encryption key was " "successfully updated." -msgstr "" +msgstr "L'infrastructure d'arrière-plan ne supporte pas la modification de mot de passe, mais la clef de chiffrement des utilisateurs a été mise à jour avec succès." #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" @@ -123,11 +123,11 @@ msgstr "Impossible de modifier le mot de passe" msgid "Update to {appversion}" msgstr "Mettre à jour vers {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Désactiver" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Activer" @@ -135,31 +135,31 @@ msgstr "Activer" msgid "Please wait...." msgstr "Veuillez patienter…" -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "Erreur lors de la désactivation de l'application" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "Erreur lors de l'activation de l'application" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Mise à jour..." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Erreur lors de la mise à jour de l'application" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Erreur" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Mettre à jour" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Mise à jour effectuée avec succès" diff --git a/l10n/hu_HU/files.po b/l10n/hu_HU/files.po index 51bd0806da3..e61d77e5cb2 100644 --- a/l10n/hu_HU/files.po +++ b/l10n/hu_HU/files.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-24 18:40+0000\n" +"Last-Translator: Laszlo Tornoci \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,23 +77,23 @@ msgstr "Nincs elég szabad hely." #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "A feltöltés nem sikerült. Az állományt leíró információk nem érhetők el." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "A feltöltés nem sikerült. Nem található a feltöltendő állomány." #: ajax/upload.php:160 msgid "Invalid directory." msgstr "Érvénytelen mappa." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Fájlok" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "A(z) {filename} állomány nem tölthető fel, mert ez vagy egy mappa, vagy pedig 0 bájtból áll." #: js/file-upload.js:255 msgid "Not enough space available" @@ -105,7 +105,7 @@ msgstr "A feltöltést megszakítottuk." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "A kiszolgálótól nem kapható meg az eredmény." #: js/file-upload.js:446 msgid "" @@ -167,24 +167,24 @@ msgstr "visszavonás" #: js/filelist.js:533 js/filelist.js:599 js/files.js:576 msgid "%n folder" msgid_plural "%n folders" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%n mappa" +msgstr[1] "%n mappa" #: js/filelist.js:534 js/filelist.js:600 js/files.js:582 msgid "%n file" msgid_plural "%n files" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%n állomány" +msgstr[1] "%n állomány" #: js/filelist.js:541 msgid "{dirs} and {files}" -msgstr "" +msgstr "{dirs} és {files}" #: js/filelist.js:731 js/filelist.js:769 msgid "Uploading %n file" msgid_plural "Uploading %n files" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%n állomány feltöltése" +msgstr[1] "%n állomány feltöltése" #: js/files.js:25 msgid "'.' is an invalid file name." @@ -212,7 +212,7 @@ msgstr "A tároló majdnem tele van ({usedSpacePercent}%)" msgid "" "Encryption was disabled but your files are still encrypted. Please go to " "your personal settings to decrypt your files." -msgstr "" +msgstr "A titkosítási funkciót kikapcsolták, de az Ön állományai még mindig titkosított állapotban vannak. A személyes beállításoknál tudja a titkosítást feloldani." #: js/files.js:296 msgid "" @@ -222,7 +222,7 @@ msgstr "Készül a letöltendő állomány. Ez eltarthat egy ideig, ha nagyok a #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Az állomány áthelyezése nem sikerült." #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/hu_HU/files_trashbin.po b/l10n/hu_HU/files_trashbin.po index 4e5d7207c9f..d0d6f3bc51a 100644 --- a/l10n/hu_HU/files_trashbin.po +++ b/l10n/hu_HU/files_trashbin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-08-15 04:47-0400\n" -"PO-Revision-Date: 2013-08-15 08:48+0000\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-24 18:40+0000\n" "Last-Translator: I Robot \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" @@ -28,43 +28,43 @@ msgstr "Nem sikerült %s végleges törlése" msgid "Couldn't restore %s" msgstr "Nem sikerült %s visszaállítása" -#: js/trash.js:7 js/trash.js:100 +#: js/trash.js:7 js/trash.js:102 msgid "perform restore operation" msgstr "a visszaállítás végrehajtása" -#: js/trash.js:20 js/trash.js:48 js/trash.js:118 js/trash.js:146 +#: js/trash.js:20 js/trash.js:49 js/trash.js:120 js/trash.js:148 msgid "Error" msgstr "Hiba" -#: js/trash.js:36 +#: js/trash.js:37 msgid "delete file permanently" msgstr "az állomány végleges törlése" -#: js/trash.js:127 +#: js/trash.js:129 msgid "Delete permanently" msgstr "Végleges törlés" -#: js/trash.js:182 templates/index.php:17 +#: js/trash.js:190 templates/index.php:21 msgid "Name" msgstr "Név" -#: js/trash.js:183 templates/index.php:27 +#: js/trash.js:191 templates/index.php:31 msgid "Deleted" msgstr "Törölve" -#: js/trash.js:191 +#: js/trash.js:199 msgid "%n folder" msgid_plural "%n folders" msgstr[0] "" -msgstr[1] "" +msgstr[1] "%n mappa" -#: js/trash.js:197 +#: js/trash.js:205 msgid "%n file" msgid_plural "%n files" msgstr[0] "" -msgstr[1] "" +msgstr[1] "%n állomány" -#: lib/trash.php:819 lib/trash.php:821 +#: lib/trashbin.php:814 lib/trashbin.php:816 msgid "restored" msgstr "visszaállítva" @@ -72,11 +72,11 @@ msgstr "visszaállítva" msgid "Nothing in here. Your trash bin is empty!" msgstr "Itt nincs semmi. Az Ön szemetes mappája üres!" -#: templates/index.php:20 templates/index.php:22 +#: templates/index.php:24 templates/index.php:26 msgid "Restore" msgstr "Visszaállítás" -#: templates/index.php:30 templates/index.php:31 +#: templates/index.php:34 templates/index.php:35 msgid "Delete" msgstr "Törlés" diff --git a/l10n/hu_HU/user_ldap.po b/l10n/hu_HU/user_ldap.po index 5b24b22ffd6..87a2b140468 100644 --- a/l10n/hu_HU/user_ldap.po +++ b/l10n/hu_HU/user_ldap.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-07 04:40-0400\n" -"PO-Revision-Date: 2013-09-05 11:51+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"PO-Revision-Date: 2013-09-24 19:00+0000\n" +"Last-Translator: Laszlo Tornoci \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -92,7 +92,7 @@ msgid "" "Warning: Apps user_ldap and user_webdavauth are incompatible. You may" " experience unexpected behavior. Please ask your system administrator to " "disable one of them." -msgstr "" +msgstr "Figyelem: a user_ldap és user_webdavauth alkalmazások nem kompatibilisek. Együttes használatuk váratlan eredményekhez vezethet. Kérje meg a rendszergazdát, hogy a kettő közül kapcsolja ki az egyiket." #: templates/settings.php:12 msgid "" @@ -157,7 +157,7 @@ msgstr "Szűrő a bejelentkezéshez" msgid "" "Defines the filter to apply, when login is attempted. %%uid replaces the " "username in the login action. Example: \"uid=%%uid\"" -msgstr "" +msgstr "Ez a szűrő érvényes a bejelentkezés megkísérlésekor. Ekkor az %%uid változó helyére a bejelentkezési név kerül. Például: \"uid=%%uid\"" #: templates/settings.php:55 msgid "User List Filter" @@ -167,7 +167,7 @@ msgstr "A felhasználók szűrője" msgid "" "Defines the filter to apply, when retrieving users (no placeholders). " "Example: \"objectClass=person\"" -msgstr "" +msgstr "Ez a szűrő érvényes a felhasználók listázásakor (nincs helyettesíthető változó). Például: \"objectClass=person\"" #: templates/settings.php:59 msgid "Group Filter" @@ -177,7 +177,7 @@ msgstr "A csoportok szűrője" msgid "" "Defines the filter to apply, when retrieving groups (no placeholders). " "Example: \"objectClass=posixGroup\"" -msgstr "" +msgstr "Ez a szűrő érvényes a csoportok listázásakor (nincs helyettesíthető változó). Például: \"objectClass=posixGroup\"" #: templates/settings.php:66 msgid "Connection Settings" @@ -215,7 +215,7 @@ msgstr "A fő szerver kihagyása" #: templates/settings.php:72 msgid "Only connect to the replica server." -msgstr "" +msgstr "Csak a másodlagos (másolati) kiszolgálóhoz kapcsolódjunk." #: templates/settings.php:73 msgid "Use TLS" @@ -238,7 +238,7 @@ msgstr "Ne ellenőrizzük az SSL-tanúsítvány érvényességét" msgid "" "Not recommended, use it for testing only! If connection only works with this" " option, import the LDAP server's SSL certificate in your %s server." -msgstr "" +msgstr "Használata nem javasolt (kivéve tesztelési céllal). Ha a kapcsolat csak ezzel a beállítással működik, akkor importálja az LDAP-kiszolgáló SSL tanúsítványát a(z) %s kiszolgálóra!" #: templates/settings.php:76 msgid "Cache Time-To-Live" @@ -258,7 +258,7 @@ msgstr "A felhasználónév mezője" #: templates/settings.php:80 msgid "The LDAP attribute to use to generate the user's display name." -msgstr "" +msgstr "Ebből az LDAP attribútumból képződik a felhasználó megjelenítendő neve." #: templates/settings.php:81 msgid "Base User Tree" @@ -282,7 +282,7 @@ msgstr "A csoport nevének mezője" #: templates/settings.php:83 msgid "The LDAP attribute to use to generate the groups's display name." -msgstr "" +msgstr "Ebből az LDAP attribútumból képződik a csoport megjelenítendő neve." #: templates/settings.php:84 msgid "Base Group Tree" diff --git a/l10n/templates/core.pot b/l10n/templates/core.pot index a57486f5ed2..ba60bef3718 100644 --- a/l10n/templates/core.pot +++ b/l10n/templates/core.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files.pot b/l10n/templates/files.pot index 23d0cd0b17b..601c6633925 100644 --- a/l10n/templates/files.pot +++ b/l10n/templates/files.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_encryption.pot b/l10n/templates/files_encryption.pot index 44e17a2fcb2..52e8feed914 100644 --- a/l10n/templates/files_encryption.pot +++ b/l10n/templates/files_encryption.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_external.pot b/l10n/templates/files_external.pot index abdd985cfdf..a99fbf35c8a 100644 --- a/l10n/templates/files_external.pot +++ b/l10n/templates/files_external.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_sharing.pot b/l10n/templates/files_sharing.pot index 34ed992660b..10bee89c275 100644 --- a/l10n/templates/files_sharing.pot +++ b/l10n/templates/files_sharing.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_trashbin.pot b/l10n/templates/files_trashbin.pot index 45fa700a43b..cfc69f2b2e5 100644 --- a/l10n/templates/files_trashbin.pot +++ b/l10n/templates/files_trashbin.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_versions.pot b/l10n/templates/files_versions.pot index 2e73cce980a..284aca099fd 100644 --- a/l10n/templates/files_versions.pot +++ b/l10n/templates/files_versions.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/lib.pot b/l10n/templates/lib.pot index 0733e0c2737..0103b348e9c 100644 --- a/l10n/templates/lib.pot +++ b/l10n/templates/lib.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/settings.pot b/l10n/templates/settings.pot index 66c00629bd9..c14bb4c3e5b 100644 --- a/l10n/templates/settings.pot +++ b/l10n/templates/settings.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/user_ldap.pot b/l10n/templates/user_ldap.pot index 919a39b4059..822d615af91 100644 --- a/l10n/templates/user_ldap.pot +++ b/l10n/templates/user_ldap.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/user_webdavauth.pot b/l10n/templates/user_webdavauth.pot index dfb732ed0c9..3a0f240e937 100644 --- a/l10n/templates/user_webdavauth.pot +++ b/l10n/templates/user_webdavauth.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-24 12:58-0400\n" +"POT-Creation-Date: 2013-09-27 00:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/lib/l10n/da.php b/lib/l10n/da.php index 26903142763..05a43f42ed9 100644 --- a/lib/l10n/da.php +++ b/lib/l10n/da.php @@ -8,6 +8,9 @@ $TRANSLATIONS = array( "Users" => "Brugere", "Admin" => "Admin", "Failed to upgrade \"%s\"." => "Upgradering af \"%s\" fejlede", +"Custom profile pictures don't work with encryption yet" => "Personligt profilbillede virker endnu ikke sammen med kryptering", +"Unknown filetype" => "Ukendt filtype", +"Invalid image" => "Ugyldigt billede", "web services under your control" => "Webtjenester under din kontrol", "cannot open \"%s\"" => "Kan ikke åbne \"%s\"", "ZIP download is turned off." => "ZIP-download er slået fra.", diff --git a/settings/l10n/da.php b/settings/l10n/da.php index fcff9dbcfd9..f86559d6752 100644 --- a/settings/l10n/da.php +++ b/settings/l10n/da.php @@ -21,6 +21,7 @@ $TRANSLATIONS = array( "Please provide an admin recovery password, otherwise all user data will be lost" => "Angiv venligst en admininstrator gendannelseskode, ellers vil alt brugerdata gå tabt", "Wrong admin recovery password. Please check the password and try again." => "Forkert admin gendannelseskode. Se venligst koden efter og prøv igen.", "Back-end doesn't support password change, but the users encryption key was successfully updated." => "Serveren understøtter ikke kodeordsskifte, men brugernes krypteringsnøgle blev opdateret.", +"Unable to change password" => "Kunne ikke ændre kodeord", "Update to {appversion}" => "Opdatér til {appversion}", "Disable" => "Deaktiver", "Enable" => "Aktiver", diff --git a/settings/l10n/fr.php b/settings/l10n/fr.php index 55c0e7fe9a8..10a7d764bc8 100644 --- a/settings/l10n/fr.php +++ b/settings/l10n/fr.php @@ -18,6 +18,9 @@ $TRANSLATIONS = array( "Couldn't update app." => "Impossible de mettre à jour l'application", "Wrong password" => "Mot de passe incorrect", "No user supplied" => "Aucun utilisateur fourni", +"Please provide an admin recovery password, otherwise all user data will be lost" => "Veuillez fournir un mot de passe administrateur de récupération de données, sinon toutes les données de l'utilisateur seront perdues", +"Wrong admin recovery password. Please check the password and try again." => "Mot de passe administrateur de récupération de données invalide. Veuillez vérifier le mot de passe et essayer à nouveau.", +"Back-end doesn't support password change, but the users encryption key was successfully updated." => "L'infrastructure d'arrière-plan ne supporte pas la modification de mot de passe, mais la clef de chiffrement des utilisateurs a été mise à jour avec succès.", "Unable to change password" => "Impossible de modifier le mot de passe", "Update to {appversion}" => "Mettre à jour vers {appversion}", "Disable" => "Désactiver", -- cgit v1.2.3 From aa8a145ba8fe5a429698ac9c508704952a454358 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 27 Sep 2013 09:59:04 +0200 Subject: use dataProvider for txt blacklist test --- tests/lib/preview.php | 53 +++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/tests/lib/preview.php b/tests/lib/preview.php index c40b2d03ef9..5dc4a93acc5 100644 --- a/tests/lib/preview.php +++ b/tests/lib/preview.php @@ -95,9 +95,6 @@ class Preview extends \PHPUnit_Framework_TestCase { public function testTxtBlacklist() { $user = $this->initFS(); - $x = 32; - $y = 32; - $txt = 'random text file'; $ics = file_get_contents(__DIR__ . '/../data/testcal.ics'); $vcf = file_get_contents(__DIR__ . '/../data/testcontact.vcf'); @@ -106,28 +103,34 @@ class Preview extends \PHPUnit_Framework_TestCase { $rootView->mkdir('/'.$user); $rootView->mkdir('/'.$user.'/files'); - $toTest = array('txt', - 'ics', - 'vcf'); - - foreach($toTest as $test) { - $sample = '/'.$user.'/files/test.'.$test; - $rootView->file_put_contents($sample, ${$test}); - $preview = new \OC\Preview($user, 'files/', 'test.'.$test, $x, $y); - $image = $preview->getPreview(); - $resource = $image->resource(); - - //http://stackoverflow.com/questions/5702953/imagecolorat-and-transparency - $colorIndex = imagecolorat($resource, 1, 1); - $colorInfo = imagecolorsforindex($resource, $colorIndex); - $isTransparent = ($colorInfo['alpha'] === 127); - - if($test === 'txt') { - $this->assertEquals($isTransparent, false); - } else { - $this->assertEquals($isTransparent, true); - } - } + return array( + array('txt', $txt, $user, $rootView, false), + array('ics', $ics, $user, $rootView, true), + array('vcf', $vcf, $user, $rootView, true), + ); + } + + /** + * @dataProvider testTxtBlacklist + */ + public function testIsTransparent($test, $data, $user, $rootView, $expectedResult) { + $x = 32; + $y = 32; + + $sample = '/'.$user.'/files/test.'.$test; + $rootView->file_put_contents($sample, $data); + $preview = new \OC\Preview($user, 'files/', 'test.'.$test, $x, $y); + $image = $preview->getPreview(); + $resource = $image->resource(); + + //http://stackoverflow.com/questions/5702953/imagecolorat-and-transparency + $colorIndex = imagecolorat($resource, 1, 1); + $colorInfo = imagecolorsforindex($resource, $colorIndex); + $this->assertEquals( + $expectedResult, + $colorInfo['alpha'] === 127, + 'Failed asserting that only previews for text files are transparent.' + ); } private function initFS() { -- cgit v1.2.3 From 1b13101096493c0c8f02826e373af761fd5cfac6 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 27 Sep 2013 11:01:47 +0200 Subject: move fileView object initialization to testIsTransparent --- tests/lib/preview.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/lib/preview.php b/tests/lib/preview.php index 5dc4a93acc5..98659a7e887 100644 --- a/tests/lib/preview.php +++ b/tests/lib/preview.php @@ -93,27 +93,27 @@ class Preview extends \PHPUnit_Framework_TestCase { } public function testTxtBlacklist() { - $user = $this->initFS(); - $txt = 'random text file'; $ics = file_get_contents(__DIR__ . '/../data/testcal.ics'); $vcf = file_get_contents(__DIR__ . '/../data/testcontact.vcf'); - $rootView = new \OC\Files\View(''); - $rootView->mkdir('/'.$user); - $rootView->mkdir('/'.$user.'/files'); - return array( - array('txt', $txt, $user, $rootView, false), - array('ics', $ics, $user, $rootView, true), - array('vcf', $vcf, $user, $rootView, true), + array('txt', $txt, false), + array('ics', $ics, true), + array('vcf', $vcf, true), ); } /** * @dataProvider testTxtBlacklist */ - public function testIsTransparent($test, $data, $user, $rootView, $expectedResult) { + public function testIsTransparent($test, $data, $expectedResult) { + $user = $this->initFS(); + + $rootView = new \OC\Files\View(''); + $rootView->mkdir('/'.$user); + $rootView->mkdir('/'.$user.'/files'); + $x = 32; $y = 32; -- cgit v1.2.3 From 4e9296a484fbec0a4c725f32ef47716f9e1b56bc Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 27 Sep 2013 11:33:37 +0200 Subject: rename testTxtBlacklist to txtBlacklist --- tests/lib/preview.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/lib/preview.php b/tests/lib/preview.php index 98659a7e887..01d8a57fc68 100644 --- a/tests/lib/preview.php +++ b/tests/lib/preview.php @@ -92,7 +92,7 @@ class Preview extends \PHPUnit_Framework_TestCase { $this->assertEquals($image->height(), $maxY); } - public function testTxtBlacklist() { + public function txtBlacklist() { $txt = 'random text file'; $ics = file_get_contents(__DIR__ . '/../data/testcal.ics'); $vcf = file_get_contents(__DIR__ . '/../data/testcontact.vcf'); @@ -105,7 +105,7 @@ class Preview extends \PHPUnit_Framework_TestCase { } /** - * @dataProvider testTxtBlacklist + * @dataProvider txtBlacklist */ public function testIsTransparent($test, $data, $expectedResult) { $user = $this->initFS(); @@ -146,4 +146,4 @@ class Preview extends \PHPUnit_Framework_TestCase { return $user; } -} \ No newline at end of file +} -- cgit v1.2.3 From 03d5ea6cec4e88dad36648a931ff0f39a1da23ee Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 27 Sep 2013 13:34:48 +0200 Subject: check not only if the keyfile folder exists but also if it contains keyfiles --- lib/util.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/util.php b/lib/util.php index 41f5f1d16be..dd6c72bfc7f 100755 --- a/lib/util.php +++ b/lib/util.php @@ -410,14 +410,18 @@ class OC_Util { $encryptedFiles = false; if (OC_App::isEnabled('files_encryption') === false) { $view = new OC\Files\View('/' . OCP\User::getUser()); - if ($view->file_exists('/files_encryption/keyfiles')) { - $encryptedFiles = true; + $keyfilePath = '/files_encryption/keyfiles'; + if ($view->is_dir($keyfilePath)) { + $dircontent = $view->getDirectoryContent($keyfilePath); + if (!empty($dircontent)) { + $encryptedFiles = true; + } } } - + return $encryptedFiles; } - + /** * @brief Check for correct file permissions of data directory * @paran string $dataDirectory @@ -654,16 +658,16 @@ class OC_Util { } return $value; } - + /** * @brief Public function to encode url parameters * * This function is used to encode path to file before output. * Encoding is done according to RFC 3986 with one exception: - * Character '/' is preserved as is. + * Character '/' is preserved as is. * * @param string $component part of URI to encode - * @return string + * @return string */ public static function encodePath($component) { $encoded = rawurlencode($component); @@ -810,7 +814,7 @@ class OC_Util { } } } - + /** * @brief Check if the connection to the internet is disabled on purpose * @return bool -- cgit v1.2.3 From 79da35b698a398bef59f83f222de3055ddbb5a92 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 27 Sep 2013 13:41:23 +0200 Subject: code cleanup --- tests/lib/connector/sabre/objecttree.php | 61 ++++++++++++-------------------- 1 file changed, 22 insertions(+), 39 deletions(-) diff --git a/tests/lib/connector/sabre/objecttree.php b/tests/lib/connector/sabre/objecttree.php index c920441c8b4..1d76bb59676 100644 --- a/tests/lib/connector/sabre/objecttree.php +++ b/tests/lib/connector/sabre/objecttree.php @@ -36,38 +36,14 @@ class ObjectTree extends PHPUnit_Framework_TestCase { * @expectedException Sabre_DAV_Exception_Forbidden */ public function testMoveFailed($source, $dest, $updatables) { - $rootDir = new OC_Connector_Sabre_Directory(''); - $objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree', - array('nodeExists', 'getNodeForPath'), - array($rootDir)); - - $objectTree->expects($this->once()) - ->method('getNodeForPath') - ->with($this->identicalTo('a/b')) - ->will($this->returnValue(false)); - - /** @var $objectTree \OC\Connector\Sabre\ObjectTree */ - $objectTree->fileView = new TestDoubleFileView($updatables); - $objectTree->move($source, $dest); + $this->moveTest($source, $dest, $updatables); } /** * @dataProvider moveSuccessProvider */ public function testMoveSuccess($source, $dest, $updatables) { - $rootDir = new OC_Connector_Sabre_Directory(''); - $objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree', - array('nodeExists', 'getNodeForPath'), - array($rootDir)); - - $objectTree->expects($this->once()) - ->method('getNodeForPath') - ->with($this->identicalTo('a/b')) - ->will($this->returnValue(false)); - - /** @var $objectTree \OC\Connector\Sabre\ObjectTree */ - $objectTree->fileView = new TestDoubleFileView($updatables); - $objectTree->move($source, $dest); + $this->moveTest($source, $dest, $updatables); $this->assertTrue(true); } @@ -87,18 +63,25 @@ class ObjectTree extends PHPUnit_Framework_TestCase { ); } -// private function buildFileViewMock($updatables) { -// // mock filesysten -// $view = $this->getMock('\OC\Files\View', array('isUpdatable'), array(), '', FALSE); -// -// foreach ($updatables as $path => $updatable) { -// $view->expects($this->any()) -// ->method('isUpdatable') -// ->with($this->identicalTo($path)) -// ->will($this->returnValue($updatable)); -// } -// -// return $view; -// } + /** + * @param $source + * @param $dest + * @param $updatables + */ + private function moveTest($source, $dest, $updatables) { + $rootDir = new OC_Connector_Sabre_Directory(''); + $objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree', + array('nodeExists', 'getNodeForPath'), + array($rootDir)); + + $objectTree->expects($this->once()) + ->method('getNodeForPath') + ->with($this->identicalTo($source)) + ->will($this->returnValue(false)); + + /** @var $objectTree \OC\Connector\Sabre\ObjectTree */ + $objectTree->fileView = new TestDoubleFileView($updatables); + $objectTree->move($source, $dest); + } } -- cgit v1.2.3 From c5bcefe4dbd5a237693b1a7435a7041c7e85abd4 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 27 Sep 2013 14:55:37 +0200 Subject: rename variable in testIsTransparent --- tests/lib/preview.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/lib/preview.php b/tests/lib/preview.php index 01d8a57fc68..d0cdd2c44fb 100644 --- a/tests/lib/preview.php +++ b/tests/lib/preview.php @@ -107,7 +107,7 @@ class Preview extends \PHPUnit_Framework_TestCase { /** * @dataProvider txtBlacklist */ - public function testIsTransparent($test, $data, $expectedResult) { + public function testIsTransparent($extension, $data, $expectedResult) { $user = $this->initFS(); $rootView = new \OC\Files\View(''); @@ -117,9 +117,9 @@ class Preview extends \PHPUnit_Framework_TestCase { $x = 32; $y = 32; - $sample = '/'.$user.'/files/test.'.$test; + $sample = '/'.$user.'/files/test.'.$extension; $rootView->file_put_contents($sample, $data); - $preview = new \OC\Preview($user, 'files/', 'test.'.$test, $x, $y); + $preview = new \OC\Preview($user, 'files/', 'test.'.$extension, $x, $y); $image = $preview->getPreview(); $resource = $image->resource(); -- cgit v1.2.3 From adff34cb8a7c2e2a6046e4fe28da3a77cd6492ca Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 27 Sep 2013 17:08:48 +0200 Subject: fixing error in initialization of TagManager --- lib/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server.php b/lib/server.php index 2391952ea6b..cabb15324ec 100644 --- a/lib/server.php +++ b/lib/server.php @@ -51,7 +51,7 @@ class Server extends SimpleContainer implements IServerContainer { }); $this->registerService('TagManager', function($c) { $user = \OC_User::getUser(); - return new Tags($user); + return new TagManager($user); }); $this->registerService('RootFolder', function($c) { // TODO: get user and user manager from container as well -- cgit v1.2.3 From 57f37c876b59d11dae8b4325bed5fa57de52ecd4 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 27 Sep 2013 17:15:26 +0200 Subject: delay middleware registrations --- lib/appframework/dependencyinjection/dicontainer.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 54878266939..380a0ee6d4a 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -40,6 +40,10 @@ use OCP\IServerContainer; class DIContainer extends SimpleContainer implements IAppContainer{ + /** + * @var array + */ + private $middleWares; /** * Put your class dependencies in here @@ -89,6 +93,10 @@ class DIContainer extends SimpleContainer implements IAppContainer{ $dispatcher = new MiddlewareDispatcher(); $dispatcher->registerMiddleware($c['SecurityMiddleware']); + foreach($this->middleWares as $middleWare) { + $dispatcher->registerMiddleware($middleWare); + } + return $dispatcher; }); @@ -125,10 +133,7 @@ class DIContainer extends SimpleContainer implements IAppContainer{ * @return boolean */ function registerMiddleWare(IMiddleWare $middleWare) { - /** @var $dispatcher MiddlewareDispatcher */ - $dispatcher = $this->query('MiddlewareDispatcher'); - $dispatcher->registerMiddleware($middleWare); - + array_push($this->middleWares, $middleWare); } /** -- cgit v1.2.3 From 4907685405ead5df56ef0a5ac0b9af7c86885487 Mon Sep 17 00:00:00 2001 From: kondou Date: Sat, 28 Sep 2013 16:46:53 +0200 Subject: Base defaultavatar text on displayname Fix #4876 --- core/avatar/controller.php | 2 +- core/js/jquery.avatar.js | 6 +++++- settings/js/personal.js | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/avatar/controller.php b/core/avatar/controller.php index 9f7c0517c4a..22693824461 100644 --- a/core/avatar/controller.php +++ b/core/avatar/controller.php @@ -33,7 +33,7 @@ class Controller { $image->show(); } else { // Signalizes $.avatar() to display a defaultavatar - \OC_JSON::success(); + \OC_JSON::success(array("data"=> array("displayname"=> \OC_User::getDisplayName($user)) )); } } diff --git a/core/js/jquery.avatar.js b/core/js/jquery.avatar.js index f1382fd7d2d..88a4c25d1ee 100644 --- a/core/js/jquery.avatar.js +++ b/core/js/jquery.avatar.js @@ -69,7 +69,11 @@ var url = OC.Router.generate('core_avatar_get', {user: user, size: size})+'?requesttoken='+oc_requesttoken; $.get(url, function(result) { if (typeof(result) === 'object') { - $div.placeholder(user); + if (result.data && result.data.displayname) { + $div.placeholder(user, result.data.displayname); + } else { + $div.placeholder(user); + } } else { if (ie8fix === true) { $div.html(''); diff --git a/settings/js/personal.js b/settings/js/personal.js index eaaca32f5d8..8944a7afa3c 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -34,6 +34,7 @@ function changeDisplayName(){ $('#oldDisplayName').text($('#displayName').val()); // update displayName on the top right expand button $('#expandDisplayName').text($('#displayName').val()); + updateAvatar(); } else{ $('#newdisplayname').val(data.data.displayName); -- cgit v1.2.3 From 24d092c4ba4264deb2b6b57299da2acc2971cedc Mon Sep 17 00:00:00 2001 From: kondou Date: Sat, 28 Sep 2013 17:49:07 +0200 Subject: Have uniform (wrong) indention --- settings/js/personal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/js/personal.js b/settings/js/personal.js index 8944a7afa3c..a923b475731 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -34,7 +34,7 @@ function changeDisplayName(){ $('#oldDisplayName').text($('#displayName').val()); // update displayName on the top right expand button $('#expandDisplayName').text($('#displayName').val()); - updateAvatar(); + updateAvatar(); } else{ $('#newdisplayname').val(data.data.displayName); -- cgit v1.2.3 From adcb738e47566d94a173116e86e3f5abe249dac1 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 28 Sep 2013 20:40:25 +0200 Subject: initialize $middleWares --- lib/appframework/dependencyinjection/dicontainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 380a0ee6d4a..3755d45fa09 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -43,7 +43,7 @@ class DIContainer extends SimpleContainer implements IAppContainer{ /** * @var array */ - private $middleWares; + private $middleWares = array(); /** * Put your class dependencies in here -- cgit v1.2.3 From 59e4ff7d24b5df96998fbc65676b56d524af5ba6 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Sun, 29 Sep 2013 00:03:26 -0400 Subject: [tx-robot] updated from transifex --- apps/files/l10n/uk.php | 5 ++-- apps/files_encryption/l10n/uk.php | 1 + core/l10n/it.php | 10 +++---- core/l10n/sv.php | 16 ++++++++++- l10n/it/core.po | 30 +++++++++---------- l10n/sv/core.po | 53 +++++++++++++++++----------------- l10n/sv/settings.po | 57 +++++++++++++++++++------------------ l10n/templates/core.pot | 2 +- l10n/templates/files.pot | 2 +- l10n/templates/files_encryption.pot | 2 +- l10n/templates/files_external.pot | 2 +- l10n/templates/files_sharing.pot | 2 +- l10n/templates/files_trashbin.pot | 2 +- l10n/templates/files_versions.pot | 2 +- l10n/templates/lib.pot | 2 +- l10n/templates/settings.pot | 8 +++--- l10n/templates/user_ldap.pot | 2 +- l10n/templates/user_webdavauth.pot | 2 +- l10n/uk/files.po | 18 ++++++------ l10n/uk/files_encryption.po | 6 ++-- l10n/uk/settings.po | 35 ++++++++++++----------- settings/l10n/sv.php | 13 +++++++++ settings/l10n/uk.php | 4 +-- 23 files changed, 154 insertions(+), 122 deletions(-) diff --git a/apps/files/l10n/uk.php b/apps/files/l10n/uk.php index fac7cea529a..4aaeca25542 100644 --- a/apps/files/l10n/uk.php +++ b/apps/files/l10n/uk.php @@ -18,6 +18,7 @@ $TRANSLATIONS = array( "Upload cancelled." => "Завантаження перервано.", "File upload is in progress. Leaving the page now will cancel the upload." => "Виконується завантаження файлу. Закриття цієї сторінки приведе до відміни завантаження.", "URL cannot be empty." => "URL не може бути пустим.", +"Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Неправильне ім'я теки. Використання 'Shared' зарезервовано ownCloud", "Error" => "Помилка", "Share" => "Поділитися", "Delete permanently" => "Видалити назавжди", @@ -29,7 +30,7 @@ $TRANSLATIONS = array( "cancel" => "відміна", "replaced {new_name} with {old_name}" => "замінено {new_name} на {old_name}", "undo" => "відмінити", -"_%n folder_::_%n folders_" => array("","",""), +"_%n folder_::_%n folders_" => array("%n тека","%n тека","%n теки"), "_%n file_::_%n files_" => array("","",""), "_Uploading %n file_::_Uploading %n files_" => array("","",""), "'.' is an invalid file name." => "'.' це невірне ім'я файлу.", @@ -53,7 +54,7 @@ $TRANSLATIONS = array( "Save" => "Зберегти", "New" => "Створити", "Text file" => "Текстовий файл", -"Folder" => "Папка", +"Folder" => "Тека", "From link" => "З посилання", "Deleted files" => "Видалено файлів", "Cancel upload" => "Перервати завантаження", diff --git a/apps/files_encryption/l10n/uk.php b/apps/files_encryption/l10n/uk.php index e4fb053a71a..5260dd3f2f7 100644 --- a/apps/files_encryption/l10n/uk.php +++ b/apps/files_encryption/l10n/uk.php @@ -1,6 +1,7 @@ "Зберігаю...", +"personal settings" => "особисті налаштування", "Encryption" => "Шифрування", "Change Password" => "Змінити Пароль" ); diff --git a/core/l10n/it.php b/core/l10n/it.php index 94395b02261..bd2fad79c87 100644 --- a/core/l10n/it.php +++ b/core/l10n/it.php @@ -53,18 +53,18 @@ $TRANSLATIONS = array( "last year" => "anno scorso", "years ago" => "anni fa", "Choose" => "Scegli", -"Error loading file picker template: {error}" => "Errore nel caricamento del modello del selettore file: {error}", +"Error loading file picker template: {error}" => "Errore durante il caricamento del modello del selettore file: {error}", "Yes" => "Sì", "No" => "No", "Ok" => "Ok", -"Error loading message template: {error}" => "Errore nel caricamento del modello di messaggio: {error}", +"Error loading message template: {error}" => "Errore durante il caricamento del modello di messaggio: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} file in conflitto","{count} file in conflitto"), -"One file conflict" => "Un conflitto tra file", +"One file conflict" => "Un file in conflitto", "Which files do you want to keep?" => "Quali file vuoi mantenere?", -"If you select both versions, the copied file will have a number added to its name." => "Se selezioni entrambe le versioni, verrà aggiunto un numero al nome del file copiato.", +"If you select both versions, the copied file will have a number added to its name." => "Se selezioni entrambe le versioni, sarà aggiunto un numero al nome del file copiato.", "Cancel" => "Annulla", "Continue" => "Continua", -"(all selected)" => "(tutti selezionati)", +"(all selected)" => "(tutti i selezionati)", "({count} selected)" => "({count} selezionati)", "Error loading file exists template" => "Errore durante il caricamento del modello del file esistente", "The object type is not specified." => "Il tipo di oggetto non è specificato.", diff --git a/core/l10n/sv.php b/core/l10n/sv.php index 660cab0a620..0ea3259df68 100644 --- a/core/l10n/sv.php +++ b/core/l10n/sv.php @@ -16,6 +16,11 @@ $TRANSLATIONS = array( "Error adding %s to favorites." => "Fel vid tillägg av %s till favoriter.", "No categories selected for deletion." => "Inga kategorier valda för radering.", "Error removing %s from favorites." => "Fel vid borttagning av %s från favoriter.", +"No image or file provided" => "Ingen bild eller fil har tillhandahållits", +"Unknown filetype" => "Okänd filtyp", +"Invalid image" => "Ogiltig bild", +"No temporary profile picture available, try again" => "Ingen temporär profilbild finns tillgänglig, försök igen", +"No crop data provided" => "Ingen beskärdata har angivits", "Sunday" => "Söndag", "Monday" => "Måndag", "Tuesday" => "Tisdag", @@ -48,11 +53,20 @@ $TRANSLATIONS = array( "last year" => "förra året", "years ago" => "år sedan", "Choose" => "Välj", +"Error loading file picker template: {error}" => "Fel uppstod för filväljarmall: {error}", "Yes" => "Ja", "No" => "Nej", "Ok" => "Ok", -"_{count} file conflict_::_{count} file conflicts_" => array("",""), +"Error loading message template: {error}" => "Fel uppstod under inläsningen av meddelandemallen: {error}", +"_{count} file conflict_::_{count} file conflicts_" => array("{count} filkonflikt","{count} filkonflikter"), +"One file conflict" => "En filkonflikt", +"Which files do you want to keep?" => "Vilken fil vill du behålla?", +"If you select both versions, the copied file will have a number added to its name." => "Om du väljer båda versionerna kommer de kopierade filerna ha nummer tillagda i filnamnet.", "Cancel" => "Avbryt", +"Continue" => "Fortsätt", +"(all selected)" => "(Alla valda)", +"({count} selected)" => "({count} valda)", +"Error loading file exists template" => "Fel uppstod filmall existerar", "The object type is not specified." => "Objekttypen är inte specificerad.", "Error" => "Fel", "The app name is not specified." => " Namnet på appen är inte specificerad.", diff --git a/l10n/it/core.po b/l10n/it/core.po index d587e959539..a5586707e43 100644 --- a/l10n/it/core.po +++ b/l10n/it/core.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-22 13:40+0000\n" -"Last-Translator: nappo \n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"PO-Revision-Date: 2013-09-27 18:30+0000\n" +"Last-Translator: Vincenzo Reale \n" "Language-Team: Italian (http://www.transifex.com/projects/p/owncloud/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -252,7 +252,7 @@ msgstr "Scegli" #: js/oc-dialogs.js:146 msgid "Error loading file picker template: {error}" -msgstr "Errore nel caricamento del modello del selettore file: {error}" +msgstr "Errore durante il caricamento del modello del selettore file: {error}" #: js/oc-dialogs.js:172 msgid "Yes" @@ -268,7 +268,7 @@ msgstr "Ok" #: js/oc-dialogs.js:219 msgid "Error loading message template: {error}" -msgstr "Errore nel caricamento del modello di messaggio: {error}" +msgstr "Errore durante il caricamento del modello di messaggio: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" @@ -278,7 +278,7 @@ msgstr[1] "{count} file in conflitto" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "Un conflitto tra file" +msgstr "Un file in conflitto" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" @@ -288,7 +288,7 @@ msgstr "Quali file vuoi mantenere?" msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "Se selezioni entrambe le versioni, verrà aggiunto un numero al nome del file copiato." +msgstr "Se selezioni entrambe le versioni, sarà aggiunto un numero al nome del file copiato." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -300,7 +300,7 @@ msgstr "Continua" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "(tutti selezionati)" +msgstr "(tutti i selezionati)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" @@ -319,7 +319,7 @@ msgstr "Il tipo di oggetto non è specificato." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Errore" @@ -339,7 +339,7 @@ msgstr "Condivisi" msgid "Share" msgstr "Condividi" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Errore durante la condivisione" @@ -439,23 +439,23 @@ msgstr "elimina" msgid "share" msgstr "condividi" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Protetta da password" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Errore durante la rimozione della data di scadenza" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Errore durante l'impostazione della data di scadenza" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Invio in corso..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "Messaggio inviato" diff --git a/l10n/sv/core.po b/l10n/sv/core.po index 64959498162..3d94872f70d 100644 --- a/l10n/sv/core.po +++ b/l10n/sv/core.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# Daniel Sandman , 2013 # Gunnar Norin , 2013 # medialabs, 2013 # Magnus Höglund , 2013 @@ -11,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"PO-Revision-Date: 2013-09-28 02:02+0000\n" +"Last-Translator: Daniel Sandman \n" "Language-Team: Swedish (http://www.transifex.com/projects/p/owncloud/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -96,23 +97,23 @@ msgstr "Fel vid borttagning av %s från favoriter." #: avatar/controller.php:62 msgid "No image or file provided" -msgstr "" +msgstr "Ingen bild eller fil har tillhandahållits" #: avatar/controller.php:81 msgid "Unknown filetype" -msgstr "" +msgstr "Okänd filtyp" #: avatar/controller.php:85 msgid "Invalid image" -msgstr "" +msgstr "Ogiltig bild" #: avatar/controller.php:115 avatar/controller.php:142 msgid "No temporary profile picture available, try again" -msgstr "" +msgstr "Ingen temporär profilbild finns tillgänglig, försök igen" #: avatar/controller.php:135 msgid "No crop data provided" -msgstr "" +msgstr "Ingen beskärdata har angivits" #: js/config.php:32 msgid "Sunday" @@ -252,7 +253,7 @@ msgstr "Välj" #: js/oc-dialogs.js:146 msgid "Error loading file picker template: {error}" -msgstr "" +msgstr "Fel uppstod för filväljarmall: {error}" #: js/oc-dialogs.js:172 msgid "Yes" @@ -268,27 +269,27 @@ msgstr "Ok" #: js/oc-dialogs.js:219 msgid "Error loading message template: {error}" -msgstr "" +msgstr "Fel uppstod under inläsningen av meddelandemallen: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "{count} filkonflikt" +msgstr[1] "{count} filkonflikter" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "En filkonflikt" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Vilken fil vill du behålla?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "Om du väljer båda versionerna kommer de kopierade filerna ha nummer tillagda i filnamnet." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -296,19 +297,19 @@ msgstr "Avbryt" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Fortsätt" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(Alla valda)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} valda)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "Fel uppstod filmall existerar" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 @@ -319,7 +320,7 @@ msgstr "Objekttypen är inte specificerad." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Fel" @@ -339,7 +340,7 @@ msgstr "Delad" msgid "Share" msgstr "Dela" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Fel vid delning" @@ -439,23 +440,23 @@ msgstr "radera" msgid "share" msgstr "dela" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Lösenordsskyddad" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Fel vid borttagning av utgångsdatum" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Fel vid sättning av utgångsdatum" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Skickar ..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "E-post skickat" diff --git a/l10n/sv/settings.po b/l10n/sv/settings.po index 284b1287a87..a0a193043a0 100644 --- a/l10n/sv/settings.po +++ b/l10n/sv/settings.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# Daniel Sandman , 2013 # Gunnar Norin , 2013 # Jan Busk, 2013 # Jan Busk, 2013 @@ -13,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"PO-Revision-Date: 2013-09-28 01:44+0000\n" +"Last-Translator: Daniel Sandman \n" "Language-Team: Swedish (http://www.transifex.com/projects/p/owncloud/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -92,42 +93,42 @@ msgstr "Kunde inte uppdatera appen." #: changepassword/controller.php:20 msgid "Wrong password" -msgstr "" +msgstr "Fel lösenord" #: changepassword/controller.php:42 msgid "No user supplied" -msgstr "" +msgstr "Ingen användare angiven" #: changepassword/controller.php:74 msgid "" "Please provide an admin recovery password, otherwise all user data will be " "lost" -msgstr "" +msgstr "Ange ett återställningslösenord för administratören. Annars kommer all användardata förloras" #: changepassword/controller.php:79 msgid "" "Wrong admin recovery password. Please check the password and try again." -msgstr "" +msgstr "Felaktigt återställningslösenord för administratör. Kolla lösenordet och prova igen." #: changepassword/controller.php:87 msgid "" "Back-end doesn't support password change, but the users encryption key was " "successfully updated." -msgstr "" +msgstr "Gränssnittet stödjer inte byte av lösenord, men användarnas krypteringsnyckel blev uppdaterad." #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" -msgstr "" +msgstr "Kunde inte ändra lösenord" #: js/apps.js:43 msgid "Update to {appversion}" msgstr "Uppdatera till {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Deaktivera" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Aktivera" @@ -135,43 +136,43 @@ msgstr "Aktivera" msgid "Please wait...." msgstr "Var god vänta..." -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "Fel vid inaktivering av app" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "Fel vid aktivering av app" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Uppdaterar..." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Fel uppstod vid uppdatering av appen" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Fel" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Uppdatera" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Uppdaterad" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" -msgstr "" +msgstr "Välj en profilbild" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." msgstr "Dekrypterar filer... Vänligen vänta, detta kan ta en stund." -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "Sparar..." @@ -499,27 +500,27 @@ msgstr "Profilbild" #: templates/personal.php:90 msgid "Upload new" -msgstr "" +msgstr "Ladda upp ny" #: templates/personal.php:92 msgid "Select new from Files" -msgstr "" +msgstr "Välj ny från filer" #: templates/personal.php:93 msgid "Remove image" -msgstr "" +msgstr "Radera bild" #: templates/personal.php:94 msgid "Either png or jpg. Ideally square but you will be able to crop it." -msgstr "" +msgstr "Antingen png eller jpg. Helst fyrkantig, men du kommer att kunna beskära den." #: templates/personal.php:97 msgid "Abort" -msgstr "" +msgstr "Avbryt" #: templates/personal.php:98 msgid "Choose as profile image" -msgstr "" +msgstr "Välj som profilbild" #: templates/personal.php:106 templates/personal.php:107 msgid "Language" diff --git a/l10n/templates/core.pot b/l10n/templates/core.pot index ba60bef3718..afb3a410c4c 100644 --- a/l10n/templates/core.pot +++ b/l10n/templates/core.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files.pot b/l10n/templates/files.pot index 601c6633925..1e72820c523 100644 --- a/l10n/templates/files.pot +++ b/l10n/templates/files.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_encryption.pot b/l10n/templates/files_encryption.pot index 52e8feed914..aea2b2282e1 100644 --- a/l10n/templates/files_encryption.pot +++ b/l10n/templates/files_encryption.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_external.pot b/l10n/templates/files_external.pot index a99fbf35c8a..ad32cfb2fcf 100644 --- a/l10n/templates/files_external.pot +++ b/l10n/templates/files_external.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_sharing.pot b/l10n/templates/files_sharing.pot index 10bee89c275..e9a596f361c 100644 --- a/l10n/templates/files_sharing.pot +++ b/l10n/templates/files_sharing.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_trashbin.pot b/l10n/templates/files_trashbin.pot index cfc69f2b2e5..044fb375dfc 100644 --- a/l10n/templates/files_trashbin.pot +++ b/l10n/templates/files_trashbin.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_versions.pot b/l10n/templates/files_versions.pot index 284aca099fd..a61952105bd 100644 --- a/l10n/templates/files_versions.pot +++ b/l10n/templates/files_versions.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/lib.pot b/l10n/templates/lib.pot index 0103b348e9c..2f54bdc2335 100644 --- a/l10n/templates/lib.pot +++ b/l10n/templates/lib.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/settings.pot b/l10n/templates/settings.pot index c14bb4c3e5b..a669dad822d 100644 --- a/l10n/templates/settings.pot +++ b/l10n/templates/settings.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -156,15 +156,15 @@ msgstr "" msgid "Updated" msgstr "" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" msgstr "" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." msgstr "" -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "" diff --git a/l10n/templates/user_ldap.pot b/l10n/templates/user_ldap.pot index 822d615af91..0848d993537 100644 --- a/l10n/templates/user_ldap.pot +++ b/l10n/templates/user_ldap.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/user_webdavauth.pot b/l10n/templates/user_webdavauth.pot index 3a0f240e937..ec5a60a6ecb 100644 --- a/l10n/templates/user_webdavauth.pot +++ b/l10n/templates/user_webdavauth.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/uk/files.po b/l10n/uk/files.po index 23349e0800d..d269f620d94 100644 --- a/l10n/uk/files.po +++ b/l10n/uk/files.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"PO-Revision-Date: 2013-09-27 19:42+0000\n" +"Last-Translator: zubr139 \n" "Language-Team: Ukrainian (http://www.transifex.com/projects/p/owncloud/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -87,7 +87,7 @@ msgstr "" msgid "Invalid directory." msgstr "Невірний каталог." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Файли" @@ -118,7 +118,7 @@ msgstr "URL не може бути пустим." #: js/file-upload.js:525 lib/app.php:53 msgid "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" -msgstr "" +msgstr "Неправильне ім'я теки. Використання 'Shared' зарезервовано ownCloud" #: js/file-upload.js:557 js/file-upload.js:573 js/files.js:507 js/files.js:545 msgid "Error" @@ -167,9 +167,9 @@ msgstr "відмінити" #: js/filelist.js:533 js/filelist.js:599 js/files.js:576 msgid "%n folder" msgid_plural "%n folders" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "%n тека" +msgstr[1] "%n тека" +msgstr[2] "%n теки" #: js/filelist.js:534 js/filelist.js:600 js/files.js:582 msgid "%n file" @@ -290,7 +290,7 @@ msgstr "Текстовий файл" #: templates/index.php:11 msgid "Folder" -msgstr "Папка" +msgstr "Тека" #: templates/index.php:13 msgid "From link" diff --git a/l10n/uk/files_encryption.po b/l10n/uk/files_encryption.po index 46c45f13fea..6957679f93f 100644 --- a/l10n/uk/files_encryption.po +++ b/l10n/uk/files_encryption.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-18 11:46-0400\n" -"PO-Revision-Date: 2013-09-17 13:05+0000\n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"PO-Revision-Date: 2013-09-27 19:12+0000\n" "Last-Translator: zubr139 \n" "Language-Team: Ukrainian (http://www.transifex.com/projects/p/owncloud/language/uk/)\n" "MIME-Version: 1.0\n" @@ -93,7 +93,7 @@ msgstr "" #: templates/invalid_private_key.php:7 msgid "personal settings" -msgstr "" +msgstr "особисті налаштування" #: templates/settings-admin.php:5 templates/settings-personal.php:4 msgid "Encryption" diff --git a/l10n/uk/settings.po b/l10n/uk/settings.po index a96bef5878c..912467cac90 100644 --- a/l10n/uk/settings.po +++ b/l10n/uk/settings.po @@ -3,13 +3,14 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# zubr139 , 2013 msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"PO-Revision-Date: 2013-09-27 19:43+0000\n" +"Last-Translator: zubr139 \n" "Language-Team: Ukrainian (http://www.transifex.com/projects/p/owncloud/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -32,7 +33,7 @@ msgstr "" #: ajax/changedisplayname.php:34 msgid "Unable to change display name" -msgstr "Не вдалося змінити зображене ім'я" +msgstr "Не вдалося змінити ім'я" #: ajax/creategroup.php:10 msgid "Group already exists" @@ -117,11 +118,11 @@ msgstr "" msgid "Update to {appversion}" msgstr "Оновити до {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Вимкнути" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Включити" @@ -129,43 +130,43 @@ msgstr "Включити" msgid "Please wait...." msgstr "Зачекайте, будь ласка..." -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Оновлюється..." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Помилка при оновленні програми" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Помилка" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Оновити" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Оновлено" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" msgstr "" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." msgstr "" -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "Зберігаю..." @@ -590,7 +591,7 @@ msgstr "Сховище" #: templates/users.php:108 msgid "change display name" -msgstr "змінити зображене ім'я" +msgstr "змінити ім'я" #: templates/users.php:112 msgid "set new password" diff --git a/settings/l10n/sv.php b/settings/l10n/sv.php index 5f6313f1829..4f8ad376db7 100644 --- a/settings/l10n/sv.php +++ b/settings/l10n/sv.php @@ -16,6 +16,12 @@ $TRANSLATIONS = array( "Unable to add user to group %s" => "Kan inte lägga till användare i gruppen %s", "Unable to remove user from group %s" => "Kan inte radera användare från gruppen %s", "Couldn't update app." => "Kunde inte uppdatera appen.", +"Wrong password" => "Fel lösenord", +"No user supplied" => "Ingen användare angiven", +"Please provide an admin recovery password, otherwise all user data will be lost" => "Ange ett återställningslösenord för administratören. Annars kommer all användardata förloras", +"Wrong admin recovery password. Please check the password and try again." => "Felaktigt återställningslösenord för administratör. Kolla lösenordet och prova igen.", +"Back-end doesn't support password change, but the users encryption key was successfully updated." => "Gränssnittet stödjer inte byte av lösenord, men användarnas krypteringsnyckel blev uppdaterad.", +"Unable to change password" => "Kunde inte ändra lösenord", "Update to {appversion}" => "Uppdatera till {appversion}", "Disable" => "Deaktivera", "Enable" => "Aktivera", @@ -27,6 +33,7 @@ $TRANSLATIONS = array( "Error" => "Fel", "Update" => "Uppdatera", "Updated" => "Uppdaterad", +"Select a profile picture" => "Välj en profilbild", "Decrypting files... Please wait, this can take some time." => "Dekrypterar filer... Vänligen vänta, detta kan ta en stund.", "Saving..." => "Sparar...", "deleted" => "raderad", @@ -101,6 +108,12 @@ $TRANSLATIONS = array( "Your email address" => "Din e-postadress", "Fill in an email address to enable password recovery" => "Fyll i en e-postadress för att aktivera återställning av lösenord", "Profile picture" => "Profilbild", +"Upload new" => "Ladda upp ny", +"Select new from Files" => "Välj ny från filer", +"Remove image" => "Radera bild", +"Either png or jpg. Ideally square but you will be able to crop it." => "Antingen png eller jpg. Helst fyrkantig, men du kommer att kunna beskära den.", +"Abort" => "Avbryt", +"Choose as profile image" => "Välj som profilbild", "Language" => "Språk", "Help translate" => "Hjälp att översätta", "WebDAV" => "WebDAV", diff --git a/settings/l10n/uk.php b/settings/l10n/uk.php index 314b7de6574..adb46e3ee84 100644 --- a/settings/l10n/uk.php +++ b/settings/l10n/uk.php @@ -2,7 +2,7 @@ $TRANSLATIONS = array( "Unable to load list from App Store" => "Не вдалося завантажити список з App Store", "Authentication error" => "Помилка автентифікації", -"Unable to change display name" => "Не вдалося змінити зображене ім'я", +"Unable to change display name" => "Не вдалося змінити ім'я", "Group already exists" => "Група вже існує", "Unable to add group" => "Не вдалося додати групу", "Email saved" => "Адресу збережено", @@ -97,7 +97,7 @@ $TRANSLATIONS = array( "Other" => "Інше", "Username" => "Ім'я користувача", "Storage" => "Сховище", -"change display name" => "змінити зображене ім'я", +"change display name" => "змінити ім'я", "set new password" => "встановити новий пароль", "Default" => "За замовчуванням" ); -- cgit v1.2.3 From 710d3f139f45f7e82991364f561b31e71e4d787f Mon Sep 17 00:00:00 2001 From: Alessandro Cosentino Date: Sun, 29 Sep 2013 01:46:23 -0400 Subject: followup of #4032 - makes the settings-button bigger and adds again padding at bottom of app-navigation --- core/css/apps.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/css/apps.css b/core/css/apps.css index de63495e50e..f6c20e6cc6a 100644 --- a/core/css/apps.css +++ b/core/css/apps.css @@ -16,6 +16,7 @@ -moz-box-sizing: border-box; box-sizing: border-box; background-color: #f8f8f8; border-right: 1px solid #ccc; + padding-bottom: 44px; } #app-navigation > ul { height: 100%; @@ -192,7 +193,7 @@ .settings-button { display: block; - height: 32px; + height: 44px; width: 100%; padding: 0; margin: 0; -- cgit v1.2.3 From b6fc143074ae55bc6f9732d825571681f88f46ed Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Fri, 31 May 2013 18:21:31 +0200 Subject: cURL does not honour default_socket_timeout SabreDAV uses cURL for the requests and as this does not honour default_socket_timeout, setting it is useless and confusing as people will expect the request to timeout faster than it actually will do. One has to use curl_setopt($curl, CURLOPT_TIMEOUT, x) or curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, x) but there is currently no way to make SabreDAV pass this to cURL. --- lib/util.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/util.php b/lib/util.php index 41f5f1d16be..d4f4eed1ca7 100755 --- a/lib/util.php +++ b/lib/util.php @@ -730,12 +730,6 @@ class OC_Util { 'baseUri' => OC_Helper::linkToRemote('webdav'), ); - // save the old timeout so that we can restore it later - $oldTimeout = ini_get("default_socket_timeout"); - - // use a 5 sec timeout for the check. Should be enough for local requests. - ini_set("default_socket_timeout", 5); - $client = new \Sabre_DAV_Client($settings); // for this self test we don't care if the ssl certificate is self signed and the peer cannot be verified. @@ -752,9 +746,6 @@ class OC_Util { $return = false; } - // restore the original timeout - ini_set("default_socket_timeout", $oldTimeout); - return $return; } -- cgit v1.2.3 From aaba0d83b5e9f8b67a739e74172da9464fa562b0 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 30 Sep 2013 10:03:07 +0200 Subject: fixing PHPDoc & typo --- lib/connector/sabre/aborteduploaddetectionplugin.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/connector/sabre/aborteduploaddetectionplugin.php b/lib/connector/sabre/aborteduploaddetectionplugin.php index 74c26f41b65..15dca3a6809 100644 --- a/lib/connector/sabre/aborteduploaddetectionplugin.php +++ b/lib/connector/sabre/aborteduploaddetectionplugin.php @@ -37,7 +37,6 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl * This method should set up the requires event subscriptions. * * @param Sabre_DAV_Server $server - * @return void */ public function initialize(Sabre_DAV_Server $server) { @@ -54,7 +53,7 @@ class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPl */ public function verifyContentLength($filePath, Sabre_DAV_INode $node = null) { - // ownCloud chunked upload will be handled in it's own plugin + // ownCloud chunked upload will be handled in its own plugin $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked'); if ($chunkHeader) { return; -- cgit v1.2.3 From a711399e62d5a9f14d4b748efe4354ee37e61f13 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Mon, 30 Sep 2013 10:19:22 -0400 Subject: [tx-robot] updated from transifex --- apps/files/l10n/cs_CZ.php | 1 + apps/files/l10n/it.php | 6 ++-- apps/files/l10n/ja_JP.php | 5 +++ apps/files/l10n/ko.php | 17 ++++++++-- apps/files/l10n/lt_LT.php | 5 +++ apps/files/l10n/pl.php | 5 +++ apps/files_sharing/l10n/ko.php | 7 ++++ apps/files_trashbin/l10n/ko.php | 14 ++++++-- apps/files_versions/l10n/ko.php | 3 ++ apps/user_ldap/l10n/hu_HU.php | 1 + apps/user_webdavauth/l10n/hu_HU.php | 4 ++- core/l10n/cs_CZ.php | 2 ++ core/l10n/hu_HU.php | 21 ++++++++++++ core/l10n/ja_JP.php | 10 +++++- core/l10n/lt_LT.php | 9 ++++- core/l10n/pl.php | 8 ++++- l10n/cs_CZ/core.po | 11 +++--- l10n/cs_CZ/files.po | 11 +++--- l10n/hu_HU/core.po | 62 ++++++++++++++++----------------- l10n/hu_HU/lib.po | 52 ++++++++++++++-------------- l10n/hu_HU/settings.po | 68 ++++++++++++++++++------------------- l10n/hu_HU/user_ldap.po | 8 ++--- l10n/hu_HU/user_webdavauth.po | 10 +++--- l10n/it/files.po | 12 +++---- l10n/it/settings.po | 30 ++++++++-------- l10n/ja_JP/core.po | 38 ++++++++++----------- l10n/ja_JP/files.po | 18 +++++----- l10n/ja_JP/settings.po | 48 +++++++++++++------------- l10n/ko/files.po | 37 ++++++++++---------- l10n/ko/files_sharing.po | 21 ++++++------ l10n/ko/files_trashbin.po | 49 +++++++++++++------------- l10n/ko/files_versions.po | 15 ++++---- l10n/ko/lib.po | 46 ++++++++++++------------- l10n/lt_LT/core.po | 40 +++++++++++----------- l10n/lt_LT/files.po | 18 +++++----- l10n/lt_LT/settings.po | 42 +++++++++++------------ l10n/pl/core.po | 38 ++++++++++----------- l10n/pl/files.po | 18 +++++----- l10n/pl/lib.po | 44 ++++++++++++------------ l10n/pl/settings.po | 44 ++++++++++++------------ l10n/templates/core.pot | 2 +- l10n/templates/files.pot | 2 +- l10n/templates/files_encryption.pot | 2 +- l10n/templates/files_external.pot | 2 +- l10n/templates/files_sharing.pot | 2 +- l10n/templates/files_trashbin.pot | 2 +- l10n/templates/files_versions.pot | 2 +- l10n/templates/lib.pot | 28 +++++++-------- l10n/templates/settings.pot | 2 +- l10n/templates/user_ldap.pot | 2 +- l10n/templates/user_webdavauth.pot | 2 +- lib/l10n/hu_HU.php | 11 ++++-- lib/l10n/ko.php | 8 +++-- lib/l10n/pl.php | 7 ++-- settings/l10n/hu_HU.php | 19 +++++++++++ settings/l10n/ja_JP.php | 9 +++++ settings/l10n/lt_LT.php | 6 ++++ settings/l10n/pl.php | 7 ++++ 58 files changed, 583 insertions(+), 430 deletions(-) diff --git a/apps/files/l10n/cs_CZ.php b/apps/files/l10n/cs_CZ.php index f67283ec6e8..f1e54ee5fc3 100644 --- a/apps/files/l10n/cs_CZ.php +++ b/apps/files/l10n/cs_CZ.php @@ -42,6 +42,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Vaše úložiště je téměř plné ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Šifrování bylo vypnuto, vaše soubory jsou však stále zašifrované. Běžte prosím do osobního nastavení, kde soubory odšifrujete.", "Your download is being prepared. This might take some time if the files are big." => "Vaše soubory ke stažení se připravují. Pokud jsou velké, může to chvíli trvat.", +"Error moving file" => "Chyba při přesunu souboru", "Name" => "Název", "Size" => "Velikost", "Modified" => "Upraveno", diff --git a/apps/files/l10n/it.php b/apps/files/l10n/it.php index c24d30ae368..44b4e341956 100644 --- a/apps/files/l10n/it.php +++ b/apps/files/l10n/it.php @@ -13,11 +13,11 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Manca una cartella temporanea", "Failed to write to disk" => "Scrittura su disco non riuscita", "Not enough storage available" => "Spazio di archiviazione insufficiente", -"Upload failed. Could not get file info." => "Upload fallito. Impossibile ottenere informazioni sul file", -"Upload failed. Could not find uploaded file" => "Upload fallit. Impossibile trovare file caricato", +"Upload failed. Could not get file info." => "Caricamento non riuscito. Impossibile ottenere informazioni sul file.", +"Upload failed. Could not find uploaded file" => "Caricamento non riuscito. Impossibile trovare il file caricato.", "Invalid directory." => "Cartella non valida.", "Files" => "File", -"Unable to upload {filename} as it is a directory or has 0 bytes" => "Impossibile caricare {filename} poiché è una cartella oppure è di 0 byte", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "Impossibile caricare {filename} poiché è una cartella oppure ha una dimensione di 0 byte.", "Not enough space available" => "Spazio disponibile insufficiente", "Upload cancelled." => "Invio annullato", "Could not get result from server." => "Impossibile ottenere il risultato dal server.", diff --git a/apps/files/l10n/ja_JP.php b/apps/files/l10n/ja_JP.php index 5944b47434d..07ee96f1eb6 100644 --- a/apps/files/l10n/ja_JP.php +++ b/apps/files/l10n/ja_JP.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "一時保存フォルダが見つかりません", "Failed to write to disk" => "ディスクへの書き込みに失敗しました", "Not enough storage available" => "ストレージに十分な空き容量がありません", +"Upload failed. Could not get file info." => "アップロードに失敗。ファイル情報を取得できませんでした。", +"Upload failed. Could not find uploaded file" => "アップロードに失敗。アップロード済みのファイルを見つけることができませんでした。", "Invalid directory." => "無効なディレクトリです。", "Files" => "ファイル", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "ディレクトリもしくは0バイトのため {filename} をアップロードできません", "Not enough space available" => "利用可能なスペースが十分にありません", "Upload cancelled." => "アップロードはキャンセルされました。", +"Could not get result from server." => "サーバから結果を取得できませんでした。", "File upload is in progress. Leaving the page now will cancel the upload." => "ファイル転送を実行中です。今このページから移動するとアップロードが中止されます。", "URL cannot be empty." => "URLは空にできません。", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "無効なフォルダ名です。'Shared' の利用はownCloudで予約済みです", @@ -42,6 +46,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "あなたのストレージはほぼ一杯です({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "暗号化の機能は無効化されましたが、ファイルはすでに暗号化されています。個人設定からファイルを複合を行ってください。", "Your download is being prepared. This might take some time if the files are big." => "ダウンロードの準備中です。ファイルサイズが大きい場合は少し時間がかかるかもしれません。", +"Error moving file" => "ファイルの移動エラー", "Name" => "名前", "Size" => "サイズ", "Modified" => "変更", diff --git a/apps/files/l10n/ko.php b/apps/files/l10n/ko.php index 502acefcf3a..0174f8d0d21 100644 --- a/apps/files/l10n/ko.php +++ b/apps/files/l10n/ko.php @@ -2,6 +2,8 @@ $TRANSLATIONS = array( "Could not move %s - File with this name already exists" => "%s 항목을 이동시키지 못하였음 - 파일 이름이 이미 존재함", "Could not move %s" => "%s 항목을 이딩시키지 못하였음", +"Unable to set upload directory." => "업로드 디렉터리를 정할수 없습니다", +"Invalid Token" => "잘못된 토큰", "No file was uploaded. Unknown error" => "파일이 업로드되지 않았습니다. 알 수 없는 오류입니다", "There is no error, the file uploaded with success" => "파일 업로드에 성공하였습니다.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "업로드한 파일이 php.ini의 upload_max_filesize보다 큽니다:", @@ -11,12 +13,17 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "임시 폴더가 없음", "Failed to write to disk" => "디스크에 쓰지 못했습니다", "Not enough storage available" => "저장소가 용량이 충분하지 않습니다.", +"Upload failed. Could not get file info." => "업로드에 실패했습니다. 파일 정보를 가져올수 없습니다.", +"Upload failed. Could not find uploaded file" => "업로드에 실패했습니다. 업로드할 파일을 찾을수 없습니다", "Invalid directory." => "올바르지 않은 디렉터리입니다.", "Files" => "파일", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "{filename}을 업로드 할수 없습니다. 폴더이거나 0 바이트 파일입니다.", "Not enough space available" => "여유 공간이 부족합니다", "Upload cancelled." => "업로드가 취소되었습니다.", +"Could not get result from server." => "서버에서 결과를 가져올수 없습니다.", "File upload is in progress. Leaving the page now will cancel the upload." => "파일 업로드가 진행 중입니다. 이 페이지를 벗어나면 업로드가 취소됩니다.", "URL cannot be empty." => "URL을 입력해야 합니다.", +"Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "유효하지 않은 폴더명입니다. \"Shared\" 이름의 사용은 OwnCloud 가 이미 예약하고 있습니다.", "Error" => "오류", "Share" => "공유", "Delete permanently" => "영원히 삭제", @@ -28,18 +35,22 @@ $TRANSLATIONS = array( "cancel" => "취소", "replaced {new_name} with {old_name}" => "{old_name}이(가) {new_name}(으)로 대체됨", "undo" => "되돌리기", -"_%n folder_::_%n folders_" => array(""), -"_%n file_::_%n files_" => array(""), -"_Uploading %n file_::_Uploading %n files_" => array(""), +"_%n folder_::_%n folders_" => array("폴더 %n"), +"_%n file_::_%n files_" => array("파일 %n 개"), +"{dirs} and {files}" => "{dirs} 그리고 {files}", +"_Uploading %n file_::_Uploading %n files_" => array("%n 개의 파일을 업로드중"), "'.' is an invalid file name." => "'.' 는 올바르지 않은 파일 이름 입니다.", "File name cannot be empty." => "파일 이름이 비어 있을 수 없습니다.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "폴더 이름이 올바르지 않습니다. 이름에 문자 '\\', '/', '<', '>', ':', '\"', '|', '? ', '*'는 사용할 수 없습니다.", "Your storage is full, files can not be updated or synced anymore!" => "저장 공간이 가득 찼습니다. 파일을 업데이트하거나 동기화할 수 없습니다!", "Your storage is almost full ({usedSpacePercent}%)" => "저장 공간이 거의 가득 찼습니다 ({usedSpacePercent}%)", +"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "암호화는 해제되어 있지만, 파일은 아직 암호화 되어 있습니다. 개인 설저에 가셔서 암호를 해제하십시오", "Your download is being prepared. This might take some time if the files are big." => "다운로드가 준비 중입니다. 파일 크기가 크다면 시간이 오래 걸릴 수도 있습니다.", +"Error moving file" => "파일 이동 오류", "Name" => "이름", "Size" => "크기", "Modified" => "수정됨", +"%s could not be renamed" => "%s 의 이름을 변경할수 없습니다", "Upload" => "업로드", "File handling" => "파일 처리", "Maximum upload size" => "최대 업로드 크기", diff --git a/apps/files/l10n/lt_LT.php b/apps/files/l10n/lt_LT.php index 2b32a129d55..d064b0c6523 100644 --- a/apps/files/l10n/lt_LT.php +++ b/apps/files/l10n/lt_LT.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Nėra laikinojo katalogo", "Failed to write to disk" => "Nepavyko įrašyti į diską", "Not enough storage available" => "Nepakanka vietos serveryje", +"Upload failed. Could not get file info." => "Įkėlimas nepavyko. Nepavyko gauti failo informacijos.", +"Upload failed. Could not find uploaded file" => "Įkėlimas nepavyko. Nepavyko rasti įkelto failo", "Invalid directory." => "Neteisingas aplankas", "Files" => "Failai", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "Nepavyksta įkelti {filename}, nes tai katalogas arba yra 0 baitų dydžio", "Not enough space available" => "Nepakanka vietos", "Upload cancelled." => "Įkėlimas atšauktas.", +"Could not get result from server." => "Nepavyko gauti rezultato iš serverio.", "File upload is in progress. Leaving the page now will cancel the upload." => "Failo įkėlimas pradėtas. Jei paliksite šį puslapį, įkėlimas nutrūks.", "URL cannot be empty." => "URL negali būti tuščias.", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Negalimas aplanko pavadinimas. 'Shared' pavadinimas yra rezervuotas ownCloud", @@ -42,6 +46,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Jūsų vieta serveryje beveik visa užimta ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Šifravimas buvo išjungtas, bet Jūsų failai vis dar užšifruoti. Prašome eiti į asmeninius nustatymus ir iššifruoti savo failus.", "Your download is being prepared. This might take some time if the files are big." => "Jūsų atsisiuntimas yra paruošiamas. tai gali užtrukti jei atsisiunčiamas didelis failas.", +"Error moving file" => "Klaida perkeliant failą", "Name" => "Pavadinimas", "Size" => "Dydis", "Modified" => "Pakeista", diff --git a/apps/files/l10n/pl.php b/apps/files/l10n/pl.php index 3ad80975810..50a247d2e0f 100644 --- a/apps/files/l10n/pl.php +++ b/apps/files/l10n/pl.php @@ -13,10 +13,14 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Brak folderu tymczasowego", "Failed to write to disk" => "Błąd zapisu na dysk", "Not enough storage available" => "Za mało dostępnego miejsca", +"Upload failed. Could not get file info." => "Nieudane przesłanie. Nie można pobrać informacji o pliku.", +"Upload failed. Could not find uploaded file" => "Nieudane przesłanie. Nie można znaleźć przesyłanego pliku", "Invalid directory." => "Zła ścieżka.", "Files" => "Pliki", +"Unable to upload {filename} as it is a directory or has 0 bytes" => "Nie można przesłać {filename} być może jest katalogiem lub posiada 0 bajtów", "Not enough space available" => "Za mało miejsca", "Upload cancelled." => "Wczytywanie anulowane.", +"Could not get result from server." => "Nie można uzyskać wyniku z serwera.", "File upload is in progress. Leaving the page now will cancel the upload." => "Wysyłanie pliku jest w toku. Jeśli opuścisz tę stronę, wysyłanie zostanie przerwane.", "URL cannot be empty." => "URL nie może być pusty.", "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" => "Nieprawidłowa nazwa folderu. Wykorzystanie 'Shared' jest zarezerwowane przez ownCloud", @@ -42,6 +46,7 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Twój magazyn jest prawie pełny ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Szyfrowanie zostało wyłączone, ale nadal pliki są zaszyfrowane. Przejdź do ustawień osobistych i tam odszyfruj pliki.", "Your download is being prepared. This might take some time if the files are big." => "Pobieranie jest przygotowywane. Może to zająć trochę czasu jeśli pliki są duże.", +"Error moving file" => "Błąd prz przenoszeniu pliku", "Name" => "Nazwa", "Size" => "Rozmiar", "Modified" => "Modyfikacja", diff --git a/apps/files_sharing/l10n/ko.php b/apps/files_sharing/l10n/ko.php index f3a94a70979..f7eab1ac550 100644 --- a/apps/files_sharing/l10n/ko.php +++ b/apps/files_sharing/l10n/ko.php @@ -1,7 +1,14 @@ "비밀번호가 틀립니다. 다시 입력해주세요.", "Password" => "암호", "Submit" => "제출", +"Sorry, this link doesn’t seem to work anymore." => "죄송합니다만 이 링크는 더이상 작동되지 않습니다.", +"Reasons might be:" => "이유는 다음과 같을 수 있습니다:", +"the item was removed" => "이 항목은 삭제되었습니다", +"the link expired" => "링크가 만료되었습니다", +"sharing is disabled" => "공유가 비활성되었습니다", +"For more info, please ask the person who sent this link." => "더 자세한 설명은 링크를 보내신 분에게 여쭤보십시오", "%s shared the folder %s with you" => "%s 님이 폴더 %s을(를) 공유하였습니다", "%s shared the file %s with you" => "%s 님이 파일 %s을(를) 공유하였습니다", "Download" => "다운로드", diff --git a/apps/files_trashbin/l10n/ko.php b/apps/files_trashbin/l10n/ko.php index f2e604d7591..9ac5f9802c6 100644 --- a/apps/files_trashbin/l10n/ko.php +++ b/apps/files_trashbin/l10n/ko.php @@ -1,11 +1,19 @@ "%s를 영구적으로 삭제할수 없습니다", +"Couldn't restore %s" => "%s를 복원할수 없습니다", +"perform restore operation" => "복원 작업중", "Error" => "오류", +"delete file permanently" => "영구적으로 파일 삭제하기", "Delete permanently" => "영원히 삭제", "Name" => "이름", -"_%n folder_::_%n folders_" => array(""), -"_%n file_::_%n files_" => array(""), +"Deleted" => "삭제됨", +"_%n folder_::_%n folders_" => array("폴더 %n개"), +"_%n file_::_%n files_" => array("파일 %n개 "), +"restored" => "복원됨", +"Nothing in here. Your trash bin is empty!" => "현재 휴지통은 비어있습니다!", "Restore" => "복원", -"Delete" => "삭제" +"Delete" => "삭제", +"Deleted Files" => "삭제된 파일들" ); $PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/apps/files_versions/l10n/ko.php b/apps/files_versions/l10n/ko.php index 365adc25115..ba951c4107a 100644 --- a/apps/files_versions/l10n/ko.php +++ b/apps/files_versions/l10n/ko.php @@ -2,6 +2,9 @@ $TRANSLATIONS = array( "Could not revert: %s" => "되돌릴 수 없습니다: %s", "Versions" => "버전", +"Failed to revert {file} to revision {timestamp}." => "{timestamp} 판의 {file}로 돌리는데 실패했습니다.", +"More versions..." => "더 많은 버전들...", +"No other versions available" => "다른 버전을 사용할수 없습니다", "Restore" => "복원" ); $PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/apps/user_ldap/l10n/hu_HU.php b/apps/user_ldap/l10n/hu_HU.php index b41cf98e2b9..b43dcbc2c87 100644 --- a/apps/user_ldap/l10n/hu_HU.php +++ b/apps/user_ldap/l10n/hu_HU.php @@ -72,6 +72,7 @@ $TRANSLATIONS = array( "User Home Folder Naming Rule" => "A home könyvtár elérési útvonala", "Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "Hagyja üresen, ha a felhasználónevet kívánja használni. Ellenkező esetben adjon meg egy LDAP/AD attribútumot!", "Internal Username" => "Belső felhasználónév", +"By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users." => "Alapértelmezetten a belső felhasználónév az UUID tulajdonságból jön létre. Ez biztosítja a felhasználónév egyediségét és hogy a nem kell konvertálni a karaktereket benne. A belső felhasználónévnél a megkötés az, hogy csak a következő karakterek engdélyezettek benne: [ a-zA-Z0-9_.@- ]. Ezeken a karaktereken kivül minden karakter le lesz cserélve az adott karakter ASCII kódtáblában használható párjára vagy ha ilyen nincs akkor egyszerűen ki lesz hagyva. Ha így mégis ütköznének a nevek akkor hozzá lesz füzve egy folyamatosan növekvő számláló rész. A belső felhasználónevet lehet használni a felhasználó azonosítására a programon belül. Illetve ez lesz az alapáértelmezett neve a felhasználó kezdő könyvtárának az ownCloud-ban. Illetve...............................", "Internal Username Attribute:" => "A belső felhasználónév attribútuma:", "Override UUID detection" => "Az UUID-felismerés felülbírálása", "UUID Attribute:" => "UUID attribútum:", diff --git a/apps/user_webdavauth/l10n/hu_HU.php b/apps/user_webdavauth/l10n/hu_HU.php index 63fc084ff4c..0b946e25e70 100644 --- a/apps/user_webdavauth/l10n/hu_HU.php +++ b/apps/user_webdavauth/l10n/hu_HU.php @@ -1,5 +1,7 @@ "WebDAV hitelesítés" +"WebDAV Authentication" => "WebDAV hitelesítés", +"Address: " => "Címek:", +"The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "A felhasználói hitelesítő adatai el lesznek küldve erre a címre. Ez a bővítőmodul leellenőrzi a választ és ha a HTTP hibakód nem 401 vagy 403 azaz érvénytelen a hitelesítő adat, akkor minden más válasz érvényes lesz." ); $PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/core/l10n/cs_CZ.php b/core/l10n/cs_CZ.php index abed4a0fdac..8b63079c87a 100644 --- a/core/l10n/cs_CZ.php +++ b/core/l10n/cs_CZ.php @@ -60,7 +60,9 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Chyba při nahrávání šablony zprávy: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("","",""), "One file conflict" => "Jeden konflikt souboru", +"Which files do you want to keep?" => "Které soubory chcete ponechat?", "Cancel" => "Zrušit", +"Continue" => "Pokračovat", "The object type is not specified." => "Není určen typ objektu.", "Error" => "Chyba", "The app name is not specified." => "Není určen název aplikace.", diff --git a/core/l10n/hu_HU.php b/core/l10n/hu_HU.php index d893269ee81..107a5f04c05 100644 --- a/core/l10n/hu_HU.php +++ b/core/l10n/hu_HU.php @@ -2,6 +2,12 @@ $TRANSLATIONS = array( "%s shared »%s« with you" => "%s megosztotta Önnel ezt: »%s«", "group" => "csoport", +"Turned on maintenance mode" => "A karbantartási mód bekapcsolva", +"Turned off maintenance mode" => "A karbantartási mód kikapcsolva", +"Updated database" => "Frissítet adatbázis", +"Updating filecache, this may take really long..." => "A filecache frissítése folyamatban, ez a folyamat hosszabb ideig is eltarthat...", +"Updated filecache" => "Filecache frissítve", +"... %d%% done ..." => "... %d%% kész ...", "Category type not provided." => "Nincs megadva a kategória típusa.", "No category to add?" => "Nincs hozzáadandó kategória?", "This category already exists: %s" => "Ez a kategória már létezik: %s", @@ -10,6 +16,11 @@ $TRANSLATIONS = array( "Error adding %s to favorites." => "Nem sikerült a kedvencekhez adni ezt: %s", "No categories selected for deletion." => "Nincs törlésre jelölt kategória", "Error removing %s from favorites." => "Nem sikerült a kedvencekből törölni ezt: %s", +"No image or file provided" => "Nincs kép vagy file megadva", +"Unknown filetype" => "Ismeretlen file tipús", +"Invalid image" => "Hibás kép", +"No temporary profile picture available, try again" => "Az átmeneti profil kép nem elérhető, próbáld újra", +"No crop data provided" => "Vágáshoz nincs adat megadva", "Sunday" => "vasárnap", "Monday" => "hétfő", "Tuesday" => "kedd", @@ -42,11 +53,20 @@ $TRANSLATIONS = array( "last year" => "tavaly", "years ago" => "több éve", "Choose" => "Válasszon", +"Error loading file picker template: {error}" => "Nem sikerült betölteni a fájlkiválasztó sablont: {error}", "Yes" => "Igen", "No" => "Nem", "Ok" => "Ok", +"Error loading message template: {error}" => "Nem sikerült betölteni az üzenet sablont: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("",""), +"One file conflict" => "Egy file ütközik", +"Which files do you want to keep?" => "Melyik file-okat akarod megtartani?", +"If you select both versions, the copied file will have a number added to its name." => "Ha kiválasztod mindazokaz a verziókat, a másolt fileok neve sorszámozva lesz.", "Cancel" => "Mégsem", +"Continue" => "Folytatás", +"(all selected)" => "(all selected)", +"({count} selected)" => "({count} kiválasztva)", +"Error loading file exists template" => "Hiba a létező sablon betöltésekor", "The object type is not specified." => "Az objektum típusa nincs megadva.", "Error" => "Hiba", "The app name is not specified." => "Az alkalmazás neve nincs megadva.", @@ -85,6 +105,7 @@ $TRANSLATIONS = array( "Email sent" => "Az emailt elküldtük", "The update was unsuccessful. Please report this issue to the ownCloud community." => "A frissítés nem sikerült. Kérem értesítse erről a problémáról az ownCloud közösséget.", "The update was successful. Redirecting you to ownCloud now." => "A frissítés sikeres volt. Visszairányítjuk az ownCloud szolgáltatáshoz.", +"%s password reset" => "%s jelszó visszaállítás", "Use the following link to reset your password: {link}" => "Használja ezt a linket a jelszó ismételt beállításához: {link}", "The link to reset your password has been sent to your email.
If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator ." => "Emailben fog kapni egy linket, amivel új jelszót tud majd beállítani magának.
Ha a levél nem jött meg, holott úgy érzi, hogy már meg kellett volna érkeznie, akkor ellenőrizze a spam/levélszemét mappáját.
Ha ott sincsen, akkor érdeklődjön a rendszergazdánál.", "Request failed!
Did you make sure your email/username was right?" => "A kérést nem sikerült teljesíteni!
Biztos, hogy jó emailcímet/felhasználónevet adott meg?", diff --git a/core/l10n/ja_JP.php b/core/l10n/ja_JP.php index 0baab441f95..110e5b21201 100644 --- a/core/l10n/ja_JP.php +++ b/core/l10n/ja_JP.php @@ -20,6 +20,7 @@ $TRANSLATIONS = array( "Unknown filetype" => "不明なファイルタイプ", "Invalid image" => "無効な画像", "No temporary profile picture available, try again" => "一時的なプロファイル用画像が利用できません。もう一度試して下さい", +"No crop data provided" => "クロップデータは提供されません", "Sunday" => "日", "Monday" => "月", "Tuesday" => "火", @@ -57,8 +58,15 @@ $TRANSLATIONS = array( "No" => "いいえ", "Ok" => "OK", "Error loading message template: {error}" => "メッセージテンプレートの読み込みエラー: {error}", -"_{count} file conflict_::_{count} file conflicts_" => array(""), +"_{count} file conflict_::_{count} file conflicts_" => array("{count} ファイルが競合"), +"One file conflict" => "1ファイルが競合", +"Which files do you want to keep?" => "どちらのファイルを保持したいですか?", +"If you select both versions, the copied file will have a number added to its name." => "両方のバージョンを選択した場合は、ファイル名の後ろに数字を追加したファイルのコピーを作成します。", "Cancel" => "キャンセル", +"Continue" => "続ける", +"(all selected)" => "(全て選択)", +"({count} selected)" => "({count} 選択)", +"Error loading file exists template" => "既存ファイルのテンプレートの読み込みエラー", "The object type is not specified." => "オブジェクタイプが指定されていません。", "Error" => "エラー", "The app name is not specified." => "アプリ名がしていされていません。", diff --git a/core/l10n/lt_LT.php b/core/l10n/lt_LT.php index 492aee12c1d..610e7aeadeb 100644 --- a/core/l10n/lt_LT.php +++ b/core/l10n/lt_LT.php @@ -58,8 +58,15 @@ $TRANSLATIONS = array( "No" => "Ne", "Ok" => "Gerai", "Error loading message template: {error}" => "Klaida įkeliant žinutės ruošinį: {error}", -"_{count} file conflict_::_{count} file conflicts_" => array("","",""), +"_{count} file conflict_::_{count} file conflicts_" => array("{count} failas konfliktuoja","{count} failai konfliktuoja","{count} failų konfliktų"), +"One file conflict" => "Vienas failo konfliktas", +"Which files do you want to keep?" => "Kuriuos failus norite laikyti?", +"If you select both versions, the copied file will have a number added to its name." => "Jei pasirenkate abi versijas, nukopijuotas failas turės pridėtą numerį pavadinime.", "Cancel" => "Atšaukti", +"Continue" => "Tęsti", +"(all selected)" => "(visi pažymėti)", +"({count} selected)" => "({count} pažymėtų)", +"Error loading file exists template" => "Klaida įkeliant esančių failų ruošinį", "The object type is not specified." => "Objekto tipas nenurodytas.", "Error" => "Klaida", "The app name is not specified." => "Nenurodytas programos pavadinimas.", diff --git a/core/l10n/pl.php b/core/l10n/pl.php index 621038f79f7..ad467fe100e 100644 --- a/core/l10n/pl.php +++ b/core/l10n/pl.php @@ -16,6 +16,8 @@ $TRANSLATIONS = array( "Error adding %s to favorites." => "Błąd podczas dodawania %s do ulubionych.", "No categories selected for deletion." => "Nie zaznaczono kategorii do usunięcia.", "Error removing %s from favorites." => "Błąd podczas usuwania %s z ulubionych.", +"Unknown filetype" => "Nieznany typ pliku", +"Invalid image" => "Nieprawidłowe zdjęcie", "Sunday" => "Niedziela", "Monday" => "Poniedziałek", "Tuesday" => "Wtorek", @@ -51,8 +53,12 @@ $TRANSLATIONS = array( "Yes" => "Tak", "No" => "Nie", "Ok" => "OK", -"_{count} file conflict_::_{count} file conflicts_" => array("","",""), +"_{count} file conflict_::_{count} file conflicts_" => array("{count} konfliktów plików","{count} konfliktów plików","{count} konfliktów plików"), +"One file conflict" => "Konflikt pliku", "Cancel" => "Anuluj", +"Continue" => "Kontynuuj ", +"(all selected)" => "(wszystkie zaznaczone)", +"({count} selected)" => "({count} zaznaczonych)", "The object type is not specified." => "Nie określono typu obiektu.", "Error" => "Błąd", "The app name is not specified." => "Nie określono nazwy aplikacji.", diff --git a/l10n/cs_CZ/core.po b/l10n/cs_CZ/core.po index 40b693b988a..914c6bcc207 100644 --- a/l10n/cs_CZ/core.po +++ b/l10n/cs_CZ/core.po @@ -4,6 +4,7 @@ # # Translators: # janinko , 2013 +# dibalaj , 2013 # Honza K. , 2013 # Martin , 2013 # pstast , 2013 @@ -12,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" -"PO-Revision-Date: 2013-09-25 10:50+0000\n" -"Last-Translator: pstast \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-29 16:57+0000\n" +"Last-Translator: dibalaj \n" "Language-Team: Czech (Czech Republic) (http://www.transifex.com/projects/p/owncloud/language/cs_CZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -288,7 +289,7 @@ msgstr "Jeden konflikt souboru" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Které soubory chcete ponechat?" #: js/oc-dialogs.js:368 msgid "" @@ -302,7 +303,7 @@ msgstr "Zrušit" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Pokračovat" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" diff --git a/l10n/cs_CZ/files.po b/l10n/cs_CZ/files.po index 7ce4b330521..5cff84e574f 100644 --- a/l10n/cs_CZ/files.po +++ b/l10n/cs_CZ/files.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# dibalaj , 2013 # Honza K. , 2013 # cvanca , 2013 # pstast , 2013 @@ -11,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:14-0400\n" +"PO-Revision-Date: 2013-09-29 16:54+0000\n" +"Last-Translator: dibalaj \n" "Language-Team: Czech (Czech Republic) (http://www.transifex.com/projects/p/owncloud/language/cs_CZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -90,7 +91,7 @@ msgstr "" msgid "Invalid directory." msgstr "Neplatný adresář" -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Soubory" @@ -228,7 +229,7 @@ msgstr "Vaše soubory ke stažení se připravují. Pokud jsou velké, může to #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Chyba při přesunu souboru" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/hu_HU/core.po b/l10n/hu_HU/core.po index 7b484995d4b..9a7a4428b56 100644 --- a/l10n/hu_HU/core.po +++ b/l10n/hu_HU/core.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-30 00:42+0000\n" +"Last-Translator: ebela \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,28 +30,28 @@ msgstr "csoport" #: ajax/update.php:11 msgid "Turned on maintenance mode" -msgstr "" +msgstr "A karbantartási mód bekapcsolva" #: ajax/update.php:14 msgid "Turned off maintenance mode" -msgstr "" +msgstr "A karbantartási mód kikapcsolva" #: ajax/update.php:17 msgid "Updated database" -msgstr "" +msgstr "Frissítet adatbázis" #: ajax/update.php:20 msgid "Updating filecache, this may take really long..." -msgstr "" +msgstr "A filecache frissítése folyamatban, ez a folyamat hosszabb ideig is eltarthat..." #: ajax/update.php:23 msgid "Updated filecache" -msgstr "" +msgstr "Filecache frissítve" #: ajax/update.php:26 #, php-format msgid "... %d%% done ..." -msgstr "" +msgstr "... %d%% kész ..." #: ajax/vcategories/add.php:26 ajax/vcategories/edit.php:25 msgid "Category type not provided." @@ -94,23 +94,23 @@ msgstr "Nem sikerült a kedvencekből törölni ezt: %s" #: avatar/controller.php:62 msgid "No image or file provided" -msgstr "" +msgstr "Nincs kép vagy file megadva" #: avatar/controller.php:81 msgid "Unknown filetype" -msgstr "" +msgstr "Ismeretlen file tipús" #: avatar/controller.php:85 msgid "Invalid image" -msgstr "" +msgstr "Hibás kép" #: avatar/controller.php:115 avatar/controller.php:142 msgid "No temporary profile picture available, try again" -msgstr "" +msgstr "Az átmeneti profil kép nem elérhető, próbáld újra" #: avatar/controller.php:135 msgid "No crop data provided" -msgstr "" +msgstr "Vágáshoz nincs adat megadva" #: js/config.php:32 msgid "Sunday" @@ -250,7 +250,7 @@ msgstr "Válasszon" #: js/oc-dialogs.js:146 msgid "Error loading file picker template: {error}" -msgstr "" +msgstr "Nem sikerült betölteni a fájlkiválasztó sablont: {error}" #: js/oc-dialogs.js:172 msgid "Yes" @@ -266,7 +266,7 @@ msgstr "Ok" #: js/oc-dialogs.js:219 msgid "Error loading message template: {error}" -msgstr "" +msgstr "Nem sikerült betölteni az üzenet sablont: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" @@ -276,17 +276,17 @@ msgstr[1] "" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "Egy file ütközik" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Melyik file-okat akarod megtartani?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "Ha kiválasztod mindazokaz a verziókat, a másolt fileok neve sorszámozva lesz." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -294,19 +294,19 @@ msgstr "Mégsem" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Folytatás" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(all selected)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} kiválasztva)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "Hiba a létező sablon betöltésekor" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 @@ -317,7 +317,7 @@ msgstr "Az objektum típusa nincs megadva." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Hiba" @@ -337,7 +337,7 @@ msgstr "Megosztott" msgid "Share" msgstr "Megosztás" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Nem sikerült létrehozni a megosztást" @@ -437,23 +437,23 @@ msgstr "töröl" msgid "share" msgstr "megoszt" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Jelszóval van védve" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Nem sikerült a lejárati időt törölni" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Nem sikerült a lejárati időt beállítani" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Küldés ..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "Az emailt elküldtük" @@ -471,7 +471,7 @@ msgstr "A frissítés sikeres volt. Visszairányítjuk az ownCloud szolgáltatá #: lostpassword/controller.php:62 #, php-format msgid "%s password reset" -msgstr "" +msgstr "%s jelszó visszaállítás" #: lostpassword/templates/email.php:2 msgid "Use the following link to reset your password: {link}" diff --git a/l10n/hu_HU/lib.po b/l10n/hu_HU/lib.po index 6cd771a9024..57212087ee5 100644 --- a/l10n/hu_HU/lib.po +++ b/l10n/hu_HU/lib.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-16 11:33-0400\n" -"PO-Revision-Date: 2013-09-16 15:34+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-30 00:50+0000\n" +"Last-Translator: ebela \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,38 +19,38 @@ msgstr "" "Language: hu_HU\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: app.php:239 +#: app.php:237 #, php-format msgid "" "App \"%s\" can't be installed because it is not compatible with this version" " of ownCloud." msgstr "" -#: app.php:250 +#: app.php:248 msgid "No app name specified" -msgstr "" +msgstr "Nincs az alkalmazás név megadva." -#: app.php:361 +#: app.php:352 msgid "Help" msgstr "Súgó" -#: app.php:374 +#: app.php:365 msgid "Personal" msgstr "Személyes" -#: app.php:385 +#: app.php:376 msgid "Settings" msgstr "Beállítások" -#: app.php:397 +#: app.php:388 msgid "Users" msgstr "Felhasználók" -#: app.php:410 +#: app.php:401 msgid "Admin" msgstr "Adminsztráció" -#: app.php:839 +#: app.php:832 #, php-format msgid "Failed to upgrade \"%s\"." msgstr "Sikertelen Frissítés \"%s\"." @@ -61,11 +61,11 @@ msgstr "" #: avatar.php:64 msgid "Unknown filetype" -msgstr "" +msgstr "Ismeretlen file tipús" #: avatar.php:69 msgid "Invalid image" -msgstr "" +msgstr "Hibás kép" #: defaults.php:35 msgid "web services under your control" @@ -121,7 +121,7 @@ msgstr "" #: installer.php:125 msgid "App does not provide an info.xml file" -msgstr "" +msgstr "Az alkalmazás nem szolgáltatott info.xml file-t" #: installer.php:131 msgid "App can't be installed because of not allowed code in the App" @@ -131,7 +131,7 @@ msgstr "" msgid "" "App can't be installed because it is not compatible with this version of " "ownCloud" -msgstr "" +msgstr "Az alalmazás nem telepíthető, mert nem kompatibilis az ownClod ezzel a verziójával." #: installer.php:146 msgid "" @@ -147,12 +147,12 @@ msgstr "" #: installer.php:162 msgid "App directory already exists" -msgstr "" +msgstr "Az alkalmazás mappája már létezik" #: installer.php:175 #, php-format msgid "Can't create app folder. Please fix permissions. %s" -msgstr "" +msgstr "Nem lehetett létrehozni az alkalmzás mappáját. Kérlek ellenőrizd a jogosultásgokat. %s" #: json.php:28 msgid "Application is not enabled" @@ -166,15 +166,15 @@ msgstr "Azonosítási hiba" msgid "Token expired. Please reload page." msgstr "A token lejárt. Frissítse az oldalt." -#: search/provider/file.php:17 search/provider/file.php:35 +#: search/provider/file.php:18 search/provider/file.php:36 msgid "Files" msgstr "Fájlok" -#: search/provider/file.php:26 search/provider/file.php:33 +#: search/provider/file.php:27 search/provider/file.php:34 msgid "Text" msgstr "Szöveg" -#: search/provider/file.php:29 +#: search/provider/file.php:30 msgid "Images" msgstr "Képek" @@ -278,6 +278,11 @@ msgstr "Az Ön webkiszolgálója nincs megfelelően beállítva az állományok msgid "Please double check the installation guides." msgstr "Kérjük tüzetesen tanulmányozza át a telepítési útmutatót." +#: tags.php:194 +#, php-format +msgid "Could not find category \"%s\"" +msgstr "Ez a kategória nem található: \"%s\"" + #: template/functions.php:96 msgid "seconds ago" msgstr "pár másodperce" @@ -329,8 +334,3 @@ msgstr "több éve" #: template.php:297 msgid "Caused by:" msgstr "Okozta:" - -#: vcategories.php:188 vcategories.php:249 -#, php-format -msgid "Could not find category \"%s\"" -msgstr "Ez a kategória nem található: \"%s\"" diff --git a/l10n/hu_HU/settings.po b/l10n/hu_HU/settings.po index 7ef4a07d1ae..f1bb5c03cfe 100644 --- a/l10n/hu_HU/settings.po +++ b/l10n/hu_HU/settings.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:17-0400\n" +"PO-Revision-Date: 2013-09-30 00:21+0000\n" +"Last-Translator: ebela \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -89,42 +89,42 @@ msgstr "A program frissítése nem sikerült." #: changepassword/controller.php:20 msgid "Wrong password" -msgstr "" +msgstr "Hibás jelszó" #: changepassword/controller.php:42 msgid "No user supplied" -msgstr "" +msgstr "Nincs felhasználó által mellékelve" #: changepassword/controller.php:74 msgid "" "Please provide an admin recovery password, otherwise all user data will be " "lost" -msgstr "" +msgstr "Add meg az admin helyreállító jelszót, máskülönben az összes felhasználói adat elveszik." #: changepassword/controller.php:79 msgid "" "Wrong admin recovery password. Please check the password and try again." -msgstr "" +msgstr "Hibás admin helyreállítási jelszó. Ellenörizd a jelszót és próbáld újra." #: changepassword/controller.php:87 msgid "" "Back-end doesn't support password change, but the users encryption key was " "successfully updated." -msgstr "" +msgstr "A back-end nem támogatja a jelszó módosítást, de felhasználó titkosítási kulcsa sikeresen frissítve lett." #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" -msgstr "" +msgstr "Nem sikerült megváltoztatni a jelszót" #: js/apps.js:43 msgid "Update to {appversion}" msgstr "Frissítés erre a verzióra: {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Letiltás" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "engedélyezve" @@ -132,43 +132,43 @@ msgstr "engedélyezve" msgid "Please wait...." msgstr "Kérem várjon..." -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" -msgstr "" +msgstr "Hiba az alkalmazás kikapcsolása közben" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" -msgstr "" +msgstr "Hiba az alalmazás engedélyezése közben" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Frissítés folyamatban..." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Hiba történt a programfrissítés közben" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Hiba" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Frissítés" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Frissítve" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" -msgstr "" +msgstr "Válassz profil képet" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." -msgstr "" +msgstr "File-ok kititkosítása folyamatban... Kérlek várj, ez hosszabb ideig is eltarthat ..." -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "Mentés..." @@ -496,27 +496,27 @@ msgstr "Profilkép" #: templates/personal.php:90 msgid "Upload new" -msgstr "" +msgstr "Új feltöltése" #: templates/personal.php:92 msgid "Select new from Files" -msgstr "" +msgstr "Új kiválasztása Fileokból" #: templates/personal.php:93 msgid "Remove image" -msgstr "" +msgstr "Kép eltávolítása" #: templates/personal.php:94 msgid "Either png or jpg. Ideally square but you will be able to crop it." -msgstr "" +msgstr "Egyaránt png vagy jpg. Az ideális ha négyzet alaku, de késöbb még átszabható" #: templates/personal.php:97 msgid "Abort" -msgstr "" +msgstr "Megszakítás" #: templates/personal.php:98 msgid "Choose as profile image" -msgstr "" +msgstr "Válassz profil képet" #: templates/personal.php:106 templates/personal.php:107 msgid "Language" @@ -543,15 +543,15 @@ msgstr "Titkosítás" #: templates/personal.php:140 msgid "The encryption app is no longer enabled, decrypt all your file" -msgstr "" +msgstr "A titkosító alkalmzás a továbbiakban nincs engedélyezve, kititkosítja az összes fileodat" #: templates/personal.php:146 msgid "Log-in password" -msgstr "" +msgstr "Bejelentkezési jelszó" #: templates/personal.php:151 msgid "Decrypt all Files" -msgstr "" +msgstr "Kititkosítja az összes file-t" #: templates/users.php:21 msgid "Login Name" diff --git a/l10n/hu_HU/user_ldap.po b/l10n/hu_HU/user_ldap.po index 87a2b140468..b1d5e5391c8 100644 --- a/l10n/hu_HU/user_ldap.po +++ b/l10n/hu_HU/user_ldap.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-27 00:01-0400\n" -"PO-Revision-Date: 2013-09-24 19:00+0000\n" -"Last-Translator: Laszlo Tornoci \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-30 00:22+0000\n" +"Last-Translator: ebela \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -348,7 +348,7 @@ msgid "" "behavior as before ownCloud 5 enter the user display name attribute in the " "following field. Leave it empty for default behavior. Changes will have " "effect only on newly mapped (added) LDAP users." -msgstr "" +msgstr "Alapértelmezetten a belső felhasználónév az UUID tulajdonságból jön létre. Ez biztosítja a felhasználónév egyediségét és hogy a nem kell konvertálni a karaktereket benne. A belső felhasználónévnél a megkötés az, hogy csak a következő karakterek engdélyezettek benne: [ a-zA-Z0-9_.@- ]. Ezeken a karaktereken kivül minden karakter le lesz cserélve az adott karakter ASCII kódtáblában használható párjára vagy ha ilyen nincs akkor egyszerűen ki lesz hagyva. Ha így mégis ütköznének a nevek akkor hozzá lesz füzve egy folyamatosan növekvő számláló rész. A belső felhasználónevet lehet használni a felhasználó azonosítására a programon belül. Illetve ez lesz az alapáértelmezett neve a felhasználó kezdő könyvtárának az ownCloud-ban. Illetve..............................." #: templates/settings.php:100 msgid "Internal Username Attribute:" diff --git a/l10n/hu_HU/user_webdavauth.po b/l10n/hu_HU/user_webdavauth.po index fd49829f9c5..35d7f6c9136 100644 --- a/l10n/hu_HU/user_webdavauth.po +++ b/l10n/hu_HU/user_webdavauth.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-07-27 01:56-0400\n" -"PO-Revision-Date: 2013-07-27 05:57+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-30 00:32+0000\n" +"Last-Translator: ebela \n" "Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/owncloud/language/hu_HU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,11 +25,11 @@ msgstr "WebDAV hitelesítés" #: templates/settings.php:4 msgid "Address: " -msgstr "" +msgstr "Címek:" #: templates/settings.php:7 msgid "" "The user credentials will be sent to this address. This plugin checks the " "response and will interpret the HTTP statuscodes 401 and 403 as invalid " "credentials, and all other responses as valid credentials." -msgstr "" +msgstr "A felhasználói hitelesítő adatai el lesznek küldve erre a címre. Ez a bővítőmodul leellenőrzi a választ és ha a HTTP hibakód nem 401 vagy 403 azaz érvénytelen a hitelesítő adat, akkor minden más válasz érvényes lesz." diff --git a/l10n/it/files.po b/l10n/it/files.po index 4711aa723a8..3b8b0f65394 100644 --- a/l10n/it/files.po +++ b/l10n/it/files.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:51-0400\n" -"PO-Revision-Date: 2013-09-21 17:50+0000\n" -"Last-Translator: polxmod \n" +"POT-Creation-Date: 2013-09-30 10:14-0400\n" +"PO-Revision-Date: 2013-09-30 12:15+0000\n" +"Last-Translator: Vincenzo Reale \n" "Language-Team: Italian (http://www.transifex.com/projects/p/owncloud/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,11 +78,11 @@ msgstr "Spazio di archiviazione insufficiente" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "Upload fallito. Impossibile ottenere informazioni sul file" +msgstr "Caricamento non riuscito. Impossibile ottenere informazioni sul file." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "Upload fallit. Impossibile trovare file caricato" +msgstr "Caricamento non riuscito. Impossibile trovare il file caricato." #: ajax/upload.php:160 msgid "Invalid directory." @@ -94,7 +94,7 @@ msgstr "File" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "Impossibile caricare {filename} poiché è una cartella oppure è di 0 byte" +msgstr "Impossibile caricare {filename} poiché è una cartella oppure ha una dimensione di 0 byte." #: js/file-upload.js:255 msgid "Not enough space available" diff --git a/l10n/it/settings.po b/l10n/it/settings.po index 0e5f28a4d15..8248b45ef24 100644 --- a/l10n/it/settings.po +++ b/l10n/it/settings.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:17-0400\n" +"PO-Revision-Date: 2013-09-30 12:15+0000\n" +"Last-Translator: Vincenzo Reale \n" "Language-Team: Italian (http://www.transifex.com/projects/p/owncloud/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -121,11 +121,11 @@ msgstr "Impossibile cambiare la password" msgid "Update to {appversion}" msgstr "Aggiorna a {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Disabilita" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Abilita" @@ -133,43 +133,43 @@ msgstr "Abilita" msgid "Please wait...." msgstr "Attendere..." -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "Errore durante la disattivazione" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "Errore durante l'attivazione" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Aggiornamento in corso..." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Errore durante l'aggiornamento" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Errore" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Aggiorna" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Aggiornato" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" msgstr "Seleziona un'immagine del profilo" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." msgstr "Decifratura dei file in corso... Attendi, potrebbe richiedere del tempo." -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "Salvataggio in corso..." diff --git a/l10n/ja_JP/core.po b/l10n/ja_JP/core.po index 0e8b19b17e3..73ad535aee2 100644 --- a/l10n/ja_JP/core.po +++ b/l10n/ja_JP/core.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-30 06:25+0000\n" +"Last-Translator: Daisuke Deguchi \n" "Language-Team: Japanese (Japan) (http://www.transifex.com/projects/p/owncloud/language/ja_JP/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -112,7 +112,7 @@ msgstr "一時的なプロファイル用画像が利用できません。もう #: avatar/controller.php:135 msgid "No crop data provided" -msgstr "" +msgstr "クロップデータは提供されません" #: js/config.php:32 msgid "Sunday" @@ -269,21 +269,21 @@ msgstr "メッセージテンプレートの読み込みエラー: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" +msgstr[0] "{count} ファイルが競合" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "1ファイルが競合" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "どちらのファイルを保持したいですか?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "両方のバージョンを選択した場合は、ファイル名の後ろに数字を追加したファイルのコピーを作成します。" #: js/oc-dialogs.js:376 msgid "Cancel" @@ -291,19 +291,19 @@ msgstr "キャンセル" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "続ける" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(全て選択)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} 選択)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "既存ファイルのテンプレートの読み込みエラー" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 @@ -314,7 +314,7 @@ msgstr "オブジェクタイプが指定されていません。" #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "エラー" @@ -334,7 +334,7 @@ msgstr "共有中" msgid "Share" msgstr "共有" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "共有でエラー発生" @@ -434,23 +434,23 @@ msgstr "削除" msgid "share" msgstr "共有" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "パスワード保護" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "有効期限の未設定エラー" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "有効期限の設定でエラー発生" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "送信中..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "メールを送信しました" diff --git a/l10n/ja_JP/files.po b/l10n/ja_JP/files.po index b712c8b95a9..23062b05965 100644 --- a/l10n/ja_JP/files.po +++ b/l10n/ja_JP/files.po @@ -12,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:14-0400\n" +"PO-Revision-Date: 2013-09-30 06:27+0000\n" +"Last-Translator: Daisuke Deguchi \n" "Language-Team: Japanese (Japan) (http://www.transifex.com/projects/p/owncloud/language/ja_JP/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -81,23 +81,23 @@ msgstr "ストレージに十分な空き容量がありません" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "アップロードに失敗。ファイル情報を取得できませんでした。" #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "アップロードに失敗。アップロード済みのファイルを見つけることができませんでした。" #: ajax/upload.php:160 msgid "Invalid directory." msgstr "無効なディレクトリです。" -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "ファイル" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "ディレクトリもしくは0バイトのため {filename} をアップロードできません" #: js/file-upload.js:255 msgid "Not enough space available" @@ -109,7 +109,7 @@ msgstr "アップロードはキャンセルされました。" #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "サーバから結果を取得できませんでした。" #: js/file-upload.js:446 msgid "" @@ -223,7 +223,7 @@ msgstr "ダウンロードの準備中です。ファイルサイズが大きい #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "ファイルの移動エラー" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/ja_JP/settings.po b/l10n/ja_JP/settings.po index c9851b54dea..9414aa1720c 100644 --- a/l10n/ja_JP/settings.po +++ b/l10n/ja_JP/settings.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:17-0400\n" +"PO-Revision-Date: 2013-09-30 06:33+0000\n" +"Last-Translator: Daisuke Deguchi \n" "Language-Team: Japanese (Japan) (http://www.transifex.com/projects/p/owncloud/language/ja_JP/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -89,42 +89,42 @@ msgstr "アプリを更新出来ませんでした。" #: changepassword/controller.php:20 msgid "Wrong password" -msgstr "" +msgstr "無効なパスワード" #: changepassword/controller.php:42 msgid "No user supplied" -msgstr "" +msgstr "ユーザが指定されていません" #: changepassword/controller.php:74 msgid "" "Please provide an admin recovery password, otherwise all user data will be " "lost" -msgstr "" +msgstr "復元用の管理者パスワードを入力してください。そうでない場合は、全ユーザのデータが失われます。" #: changepassword/controller.php:79 msgid "" "Wrong admin recovery password. Please check the password and try again." -msgstr "" +msgstr "無効な復元用の管理者パスワード。パスワードを確認して再度実行してください。" #: changepassword/controller.php:87 msgid "" "Back-end doesn't support password change, but the users encryption key was " "successfully updated." -msgstr "" +msgstr "バックエンドはパスワード変更をサポートしていませんが、ユーザの暗号化キーは正常に更新されました。" #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" -msgstr "" +msgstr "パスワードを変更できません" #: js/apps.js:43 msgid "Update to {appversion}" msgstr "{appversion} に更新" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "無効" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "有効化" @@ -132,43 +132,43 @@ msgstr "有効化" msgid "Please wait...." msgstr "しばらくお待ちください。" -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "アプリ無効化中にエラーが発生" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "アプリ有効化中にエラーが発生" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "更新中...." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "アプリの更新中にエラーが発生" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "エラー" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "更新" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "更新済み" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" msgstr "プロファイル画像を選択" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." msgstr "ファイルを複合中... しばらくお待ちください、この処理には少し時間がかかるかもしれません。" -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "保存中..." @@ -496,11 +496,11 @@ msgstr "プロフィール写真" #: templates/personal.php:90 msgid "Upload new" -msgstr "" +msgstr "新規にアップロード" #: templates/personal.php:92 msgid "Select new from Files" -msgstr "" +msgstr "ファイルから新規に選択" #: templates/personal.php:93 msgid "Remove image" @@ -508,7 +508,7 @@ msgstr "画像を削除" #: templates/personal.php:94 msgid "Either png or jpg. Ideally square but you will be able to crop it." -msgstr "" +msgstr "png と jpg のいずれか。正方形が理想ですが、切り取って加工することも可能です。" #: templates/personal.php:97 msgid "Abort" diff --git a/l10n/ko/files.po b/l10n/ko/files.po index b2497ad3499..d3f72518cc7 100644 --- a/l10n/ko/files.po +++ b/l10n/ko/files.po @@ -5,13 +5,14 @@ # Translators: # ujuc Gang , 2013 # ujuc Gang , 2013 +# smallsnail , 2013 msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:14-0400\n" +"PO-Revision-Date: 2013-09-29 10:06+0000\n" +"Last-Translator: smallsnail \n" "Language-Team: Korean (http://www.transifex.com/projects/p/owncloud/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,11 +32,11 @@ msgstr "%s 항목을 이딩시키지 못하였음" #: ajax/upload.php:16 ajax/upload.php:45 msgid "Unable to set upload directory." -msgstr "" +msgstr "업로드 디렉터리를 정할수 없습니다" #: ajax/upload.php:22 msgid "Invalid Token" -msgstr "" +msgstr "잘못된 토큰" #: ajax/upload.php:59 msgid "No file was uploaded. Unknown error" @@ -78,23 +79,23 @@ msgstr "저장소가 용량이 충분하지 않습니다." #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "업로드에 실패했습니다. 파일 정보를 가져올수 없습니다." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "업로드에 실패했습니다. 업로드할 파일을 찾을수 없습니다" #: ajax/upload.php:160 msgid "Invalid directory." msgstr "올바르지 않은 디렉터리입니다." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "파일" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "{filename}을 업로드 할수 없습니다. 폴더이거나 0 바이트 파일입니다." #: js/file-upload.js:255 msgid "Not enough space available" @@ -106,7 +107,7 @@ msgstr "업로드가 취소되었습니다." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "서버에서 결과를 가져올수 없습니다." #: js/file-upload.js:446 msgid "" @@ -119,7 +120,7 @@ msgstr "URL을 입력해야 합니다." #: js/file-upload.js:525 lib/app.php:53 msgid "Invalid folder name. Usage of 'Shared' is reserved by ownCloud" -msgstr "" +msgstr "유효하지 않은 폴더명입니다. \"Shared\" 이름의 사용은 OwnCloud 가 이미 예약하고 있습니다." #: js/file-upload.js:557 js/file-upload.js:573 js/files.js:507 js/files.js:545 msgid "Error" @@ -168,21 +169,21 @@ msgstr "되돌리기" #: js/filelist.js:533 js/filelist.js:599 js/files.js:576 msgid "%n folder" msgid_plural "%n folders" -msgstr[0] "" +msgstr[0] "폴더 %n" #: js/filelist.js:534 js/filelist.js:600 js/files.js:582 msgid "%n file" msgid_plural "%n files" -msgstr[0] "" +msgstr[0] "파일 %n 개" #: js/filelist.js:541 msgid "{dirs} and {files}" -msgstr "" +msgstr "{dirs} 그리고 {files}" #: js/filelist.js:731 js/filelist.js:769 msgid "Uploading %n file" msgid_plural "Uploading %n files" -msgstr[0] "" +msgstr[0] "%n 개의 파일을 업로드중" #: js/files.js:25 msgid "'.' is an invalid file name." @@ -210,7 +211,7 @@ msgstr "저장 공간이 거의 가득 찼습니다 ({usedSpacePercent}%)" msgid "" "Encryption was disabled but your files are still encrypted. Please go to " "your personal settings to decrypt your files." -msgstr "" +msgstr "암호화는 해제되어 있지만, 파일은 아직 암호화 되어 있습니다. 개인 설저에 가셔서 암호를 해제하십시오" #: js/files.js:296 msgid "" @@ -220,7 +221,7 @@ msgstr "다운로드가 준비 중입니다. 파일 크기가 크다면 시간 #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "파일 이동 오류" #: js/files.js:558 templates/index.php:61 msgid "Name" @@ -237,7 +238,7 @@ msgstr "수정됨" #: lib/app.php:73 #, php-format msgid "%s could not be renamed" -msgstr "" +msgstr "%s 의 이름을 변경할수 없습니다" #: lib/helper.php:11 templates/index.php:17 msgid "Upload" diff --git a/l10n/ko/files_sharing.po b/l10n/ko/files_sharing.po index 434e19ca27a..da94ad32110 100644 --- a/l10n/ko/files_sharing.po +++ b/l10n/ko/files_sharing.po @@ -3,13 +3,14 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# smallsnail , 2013 msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-13 21:46-0400\n" -"PO-Revision-Date: 2013-09-14 00:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-29 10:14+0000\n" +"Last-Translator: smallsnail \n" "Language-Team: Korean (http://www.transifex.com/projects/p/owncloud/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,7 +20,7 @@ msgstr "" #: templates/authenticate.php:4 msgid "The password is wrong. Try again." -msgstr "" +msgstr "비밀번호가 틀립니다. 다시 입력해주세요." #: templates/authenticate.php:7 msgid "Password" @@ -31,27 +32,27 @@ msgstr "제출" #: templates/part.404.php:3 msgid "Sorry, this link doesn’t seem to work anymore." -msgstr "" +msgstr "죄송합니다만 이 링크는 더이상 작동되지 않습니다." #: templates/part.404.php:4 msgid "Reasons might be:" -msgstr "" +msgstr "이유는 다음과 같을 수 있습니다:" #: templates/part.404.php:6 msgid "the item was removed" -msgstr "" +msgstr "이 항목은 삭제되었습니다" #: templates/part.404.php:7 msgid "the link expired" -msgstr "" +msgstr "링크가 만료되었습니다" #: templates/part.404.php:8 msgid "sharing is disabled" -msgstr "" +msgstr "공유가 비활성되었습니다" #: templates/part.404.php:10 msgid "For more info, please ask the person who sent this link." -msgstr "" +msgstr "더 자세한 설명은 링크를 보내신 분에게 여쭤보십시오" #: templates/public.php:15 #, php-format diff --git a/l10n/ko/files_trashbin.po b/l10n/ko/files_trashbin.po index 3e48f534a18..4d39e2d9acd 100644 --- a/l10n/ko/files_trashbin.po +++ b/l10n/ko/files_trashbin.po @@ -3,13 +3,14 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# smallsnail , 2013 msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-08-15 04:47-0400\n" -"PO-Revision-Date: 2013-08-15 08:48+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-29 07:38+0000\n" +"Last-Translator: smallsnail \n" "Language-Team: Korean (http://www.transifex.com/projects/p/owncloud/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,63 +21,63 @@ msgstr "" #: ajax/delete.php:42 #, php-format msgid "Couldn't delete %s permanently" -msgstr "" +msgstr "%s를 영구적으로 삭제할수 없습니다" #: ajax/undelete.php:42 #, php-format msgid "Couldn't restore %s" -msgstr "" +msgstr "%s를 복원할수 없습니다" -#: js/trash.js:7 js/trash.js:100 +#: js/trash.js:7 js/trash.js:102 msgid "perform restore operation" -msgstr "" +msgstr "복원 작업중" -#: js/trash.js:20 js/trash.js:48 js/trash.js:118 js/trash.js:146 +#: js/trash.js:20 js/trash.js:49 js/trash.js:120 js/trash.js:148 msgid "Error" msgstr "오류" -#: js/trash.js:36 +#: js/trash.js:37 msgid "delete file permanently" -msgstr "" +msgstr "영구적으로 파일 삭제하기" -#: js/trash.js:127 +#: js/trash.js:129 msgid "Delete permanently" msgstr "영원히 삭제" -#: js/trash.js:182 templates/index.php:17 +#: js/trash.js:190 templates/index.php:21 msgid "Name" msgstr "이름" -#: js/trash.js:183 templates/index.php:27 +#: js/trash.js:191 templates/index.php:31 msgid "Deleted" -msgstr "" +msgstr "삭제됨" -#: js/trash.js:191 +#: js/trash.js:199 msgid "%n folder" msgid_plural "%n folders" -msgstr[0] "" +msgstr[0] "폴더 %n개" -#: js/trash.js:197 +#: js/trash.js:205 msgid "%n file" msgid_plural "%n files" -msgstr[0] "" +msgstr[0] "파일 %n개 " -#: lib/trash.php:819 lib/trash.php:821 +#: lib/trashbin.php:814 lib/trashbin.php:816 msgid "restored" -msgstr "" +msgstr "복원됨" #: templates/index.php:9 msgid "Nothing in here. Your trash bin is empty!" -msgstr "" +msgstr "현재 휴지통은 비어있습니다!" -#: templates/index.php:20 templates/index.php:22 +#: templates/index.php:24 templates/index.php:26 msgid "Restore" msgstr "복원" -#: templates/index.php:30 templates/index.php:31 +#: templates/index.php:34 templates/index.php:35 msgid "Delete" msgstr "삭제" #: templates/part.breadcrumb.php:9 msgid "Deleted Files" -msgstr "" +msgstr "삭제된 파일들" diff --git a/l10n/ko/files_versions.po b/l10n/ko/files_versions.po index 19ec188ee6c..1a9375ae400 100644 --- a/l10n/ko/files_versions.po +++ b/l10n/ko/files_versions.po @@ -4,13 +4,14 @@ # # Translators: # Shinjo Park , 2013 +# smallsnail , 2013 msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-07-28 01:56-0400\n" -"PO-Revision-Date: 2013-07-27 06:10+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-29 10:18+0000\n" +"Last-Translator: smallsnail \n" "Language-Team: Korean (http://www.transifex.com/projects/p/owncloud/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -29,16 +30,16 @@ msgstr "버전" #: js/versions.js:53 msgid "Failed to revert {file} to revision {timestamp}." -msgstr "" +msgstr "{timestamp} 판의 {file}로 돌리는데 실패했습니다." #: js/versions.js:79 msgid "More versions..." -msgstr "" +msgstr "더 많은 버전들..." #: js/versions.js:116 msgid "No other versions available" -msgstr "" +msgstr "다른 버전을 사용할수 없습니다" -#: js/versions.js:149 +#: js/versions.js:145 msgid "Restore" msgstr "복원" diff --git a/l10n/ko/lib.po b/l10n/ko/lib.po index 06627a79781..ca05c5e1330 100644 --- a/l10n/ko/lib.po +++ b/l10n/ko/lib.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-16 11:33-0400\n" -"PO-Revision-Date: 2013-09-16 15:34+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-29 07:46+0000\n" +"Last-Translator: smallsnail \n" "Language-Team: Korean (http://www.transifex.com/projects/p/owncloud/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,53 +19,53 @@ msgstr "" "Language: ko\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: app.php:239 +#: app.php:237 #, php-format msgid "" "App \"%s\" can't be installed because it is not compatible with this version" " of ownCloud." msgstr "현재 ownCloud 버전과 호환되지 않기 때문에 \"%s\" 앱을 설치할 수 없습니다." -#: app.php:250 +#: app.php:248 msgid "No app name specified" msgstr "앱 이름이 지정되지 않았습니다." -#: app.php:361 +#: app.php:352 msgid "Help" msgstr "도움말" -#: app.php:374 +#: app.php:365 msgid "Personal" msgstr "개인" -#: app.php:385 +#: app.php:376 msgid "Settings" msgstr "설정" -#: app.php:397 +#: app.php:388 msgid "Users" msgstr "사용자" -#: app.php:410 +#: app.php:401 msgid "Admin" msgstr "관리자" -#: app.php:839 +#: app.php:832 #, php-format msgid "Failed to upgrade \"%s\"." msgstr "\"%s\" 업그레이드에 실패했습니다." #: avatar.php:56 msgid "Custom profile pictures don't work with encryption yet" -msgstr "" +msgstr "개개인의 프로필 사진은 아직은 암호화 되지 않습니다" #: avatar.php:64 msgid "Unknown filetype" -msgstr "" +msgstr "알수없는 파일형식" #: avatar.php:69 msgid "Invalid image" -msgstr "" +msgstr "잘못된 그림" #: defaults.php:35 msgid "web services under your control" @@ -96,7 +96,7 @@ msgstr "선택한 파일들은 ZIP 파일을 생성하기에 너무 큽니다." msgid "" "Download the files in smaller chunks, seperately or kindly ask your " "administrator." -msgstr "" +msgstr "작은 조각들 안에 들어있는 파일들을 받고자 하신다면, 나누어서 받으시거나 혹은 시스템 관리자에게 정중하게 물어보십시오" #: installer.php:63 msgid "No source specified when installing app" @@ -166,15 +166,15 @@ msgstr "인증 오류" msgid "Token expired. Please reload page." msgstr "토큰이 만료되었습니다. 페이지를 새로 고치십시오." -#: search/provider/file.php:17 search/provider/file.php:35 +#: search/provider/file.php:18 search/provider/file.php:36 msgid "Files" msgstr "파일" -#: search/provider/file.php:26 search/provider/file.php:33 +#: search/provider/file.php:27 search/provider/file.php:34 msgid "Text" msgstr "텍스트" -#: search/provider/file.php:29 +#: search/provider/file.php:30 msgid "Images" msgstr "그림" @@ -278,6 +278,11 @@ msgstr "WebDAV 인터페이스가 제대로 작동하지 않습니다. 웹 서 msgid "Please double check the installation guides." msgstr "설치 가이드를 다시 한 번 확인하십시오." +#: tags.php:194 +#, php-format +msgid "Could not find category \"%s\"" +msgstr "분류 \"%s\"을(를) 찾을 수 없습니다." + #: template/functions.php:96 msgid "seconds ago" msgstr "초 전" @@ -325,8 +330,3 @@ msgstr "년 전" #: template.php:297 msgid "Caused by:" msgstr "원인: " - -#: vcategories.php:188 vcategories.php:249 -#, php-format -msgid "Could not find category \"%s\"" -msgstr "분류 \"%s\"을(를) 찾을 수 없습니다." diff --git a/l10n/lt_LT/core.po b/l10n/lt_LT/core.po index f340c7a46db..4a22a7c9482 100644 --- a/l10n/lt_LT/core.po +++ b/l10n/lt_LT/core.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-29 07:58+0000\n" +"Last-Translator: Liudas Ališauskas \n" "Language-Team: Lithuanian (Lithuania) (http://www.transifex.com/projects/p/owncloud/language/lt_LT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -277,23 +277,23 @@ msgstr "Klaida įkeliant žinutės ruošinį: {error}" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "{count} failas konfliktuoja" +msgstr[1] "{count} failai konfliktuoja" +msgstr[2] "{count} failų konfliktų" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "Vienas failo konfliktas" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" -msgstr "" +msgstr "Kuriuos failus norite laikyti?" #: js/oc-dialogs.js:368 msgid "" "If you select both versions, the copied file will have a number added to its" " name." -msgstr "" +msgstr "Jei pasirenkate abi versijas, nukopijuotas failas turės pridėtą numerį pavadinime." #: js/oc-dialogs.js:376 msgid "Cancel" @@ -301,19 +301,19 @@ msgstr "Atšaukti" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Tęsti" #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(visi pažymėti)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} pažymėtų)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" -msgstr "" +msgstr "Klaida įkeliant esančių failų ruošinį" #: js/oc-vcategories.js:5 js/oc-vcategories.js:85 js/oc-vcategories.js:102 #: js/oc-vcategories.js:117 js/oc-vcategories.js:132 js/oc-vcategories.js:162 @@ -324,7 +324,7 @@ msgstr "Objekto tipas nenurodytas." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Klaida" @@ -344,7 +344,7 @@ msgstr "Dalinamasi" msgid "Share" msgstr "Dalintis" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Klaida, dalijimosi metu" @@ -444,23 +444,23 @@ msgstr "ištrinti" msgid "share" msgstr "dalintis" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Apsaugota slaptažodžiu" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Klaida nuimant galiojimo laiką" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Klaida nustatant galiojimo laiką" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Siunčiama..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "Laiškas išsiųstas" diff --git a/l10n/lt_LT/files.po b/l10n/lt_LT/files.po index da69b0a419b..829d61188a3 100644 --- a/l10n/lt_LT/files.po +++ b/l10n/lt_LT/files.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:14-0400\n" +"PO-Revision-Date: 2013-09-29 08:46+0000\n" +"Last-Translator: Liudas Ališauskas \n" "Language-Team: Lithuanian (Lithuania) (http://www.transifex.com/projects/p/owncloud/language/lt_LT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,23 +78,23 @@ msgstr "Nepakanka vietos serveryje" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "Įkėlimas nepavyko. Nepavyko gauti failo informacijos." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "Įkėlimas nepavyko. Nepavyko rasti įkelto failo" #: ajax/upload.php:160 msgid "Invalid directory." msgstr "Neteisingas aplankas" -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Failai" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "Nepavyksta įkelti {filename}, nes tai katalogas arba yra 0 baitų dydžio" #: js/file-upload.js:255 msgid "Not enough space available" @@ -106,7 +106,7 @@ msgstr "Įkėlimas atšauktas." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "Nepavyko gauti rezultato iš serverio." #: js/file-upload.js:446 msgid "" @@ -226,7 +226,7 @@ msgstr "Jūsų atsisiuntimas yra paruošiamas. tai gali užtrukti jei atsisiunč #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Klaida perkeliant failą" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/lt_LT/settings.po b/l10n/lt_LT/settings.po index 14592409dd9..ff719fb19fe 100644 --- a/l10n/lt_LT/settings.po +++ b/l10n/lt_LT/settings.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:17-0400\n" +"PO-Revision-Date: 2013-09-29 08:49+0000\n" +"Last-Translator: Liudas Ališauskas \n" "Language-Team: Lithuanian (Lithuania) (http://www.transifex.com/projects/p/owncloud/language/lt_LT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -90,42 +90,42 @@ msgstr "Nepavyko atnaujinti programos." #: changepassword/controller.php:20 msgid "Wrong password" -msgstr "" +msgstr "Neteisingas slaptažodis" #: changepassword/controller.php:42 msgid "No user supplied" -msgstr "" +msgstr "Nepateiktas naudotojas" #: changepassword/controller.php:74 msgid "" "Please provide an admin recovery password, otherwise all user data will be " "lost" -msgstr "" +msgstr "Prašome įvesti administratoriaus atkūrimo slaptažodį, kitaip visi naudotojo suomenys bus prarasti" #: changepassword/controller.php:79 msgid "" "Wrong admin recovery password. Please check the password and try again." -msgstr "" +msgstr "Netinkamas administratoriau atkūrimo slaptažodis. Prašome pasitikrinti ir bandyti vėl." #: changepassword/controller.php:87 msgid "" "Back-end doesn't support password change, but the users encryption key was " "successfully updated." -msgstr "" +msgstr "Sistema nepalaiko slaptažodžio keitimo, bet naudotojo šifravimo raktas buvo sėkmingai atnaujintas." #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" -msgstr "" +msgstr "Nepavyksta pakeisti slaptažodžio" #: js/apps.js:43 msgid "Update to {appversion}" msgstr "Atnaujinti iki {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Išjungti" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Įjungti" @@ -133,43 +133,43 @@ msgstr "Įjungti" msgid "Please wait...." msgstr "Prašome palaukti..." -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "Klaida išjungiant programą" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "Klaida įjungiant programą" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Atnaujinama..." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Įvyko klaida atnaujinant programą" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Klaida" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Atnaujinti" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Atnaujinta" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" msgstr "Pažymėkite profilio paveikslėlį" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." msgstr "Iššifruojami failai... Prašome palaukti, tai gali užtrukti." -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "Saugoma..." diff --git a/l10n/pl/core.po b/l10n/pl/core.po index 3d7aae83bae..d3f781b0e4d 100644 --- a/l10n/pl/core.po +++ b/l10n/pl/core.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-22 12:55-0400\n" -"PO-Revision-Date: 2013-09-20 15:01+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-30 12:27+0000\n" +"Last-Translator: Cyryl Sochacki \n" "Language-Team: Polish (http://www.transifex.com/projects/p/owncloud/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -98,11 +98,11 @@ msgstr "" #: avatar/controller.php:81 msgid "Unknown filetype" -msgstr "" +msgstr "Nieznany typ pliku" #: avatar/controller.php:85 msgid "Invalid image" -msgstr "" +msgstr "Nieprawidłowe zdjęcie" #: avatar/controller.php:115 avatar/controller.php:142 msgid "No temporary profile picture available, try again" @@ -275,13 +275,13 @@ msgstr "" #: js/oc-dialogs.js:347 msgid "{count} file conflict" msgid_plural "{count} file conflicts" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "{count} konfliktów plików" +msgstr[1] "{count} konfliktów plików" +msgstr[2] "{count} konfliktów plików" #: js/oc-dialogs.js:361 msgid "One file conflict" -msgstr "" +msgstr "Konflikt pliku" #: js/oc-dialogs.js:367 msgid "Which files do you want to keep?" @@ -299,15 +299,15 @@ msgstr "Anuluj" #: js/oc-dialogs.js:386 msgid "Continue" -msgstr "" +msgstr "Kontynuuj " #: js/oc-dialogs.js:433 js/oc-dialogs.js:446 msgid "(all selected)" -msgstr "" +msgstr "(wszystkie zaznaczone)" #: js/oc-dialogs.js:436 js/oc-dialogs.js:449 msgid "({count} selected)" -msgstr "" +msgstr "({count} zaznaczonych)" #: js/oc-dialogs.js:457 msgid "Error loading file exists template" @@ -322,7 +322,7 @@ msgstr "Nie określono typu obiektu." #: js/oc-vcategories.js:110 js/oc-vcategories.js:125 js/oc-vcategories.js:136 #: js/oc-vcategories.js:172 js/oc-vcategories.js:189 js/oc-vcategories.js:195 #: js/oc-vcategories.js:199 js/share.js:129 js/share.js:142 js/share.js:149 -#: js/share.js:645 js/share.js:657 +#: js/share.js:656 js/share.js:668 msgid "Error" msgstr "Błąd" @@ -342,7 +342,7 @@ msgstr "Udostępniono" msgid "Share" msgstr "Udostępnij" -#: js/share.js:131 js/share.js:685 +#: js/share.js:131 js/share.js:696 msgid "Error while sharing" msgstr "Błąd podczas współdzielenia" @@ -442,23 +442,23 @@ msgstr "usuń" msgid "share" msgstr "współdziel" -#: js/share.js:400 js/share.js:632 +#: js/share.js:400 js/share.js:643 msgid "Password protected" msgstr "Zabezpieczone hasłem" -#: js/share.js:645 +#: js/share.js:656 msgid "Error unsetting expiration date" msgstr "Błąd podczas usuwania daty wygaśnięcia" -#: js/share.js:657 +#: js/share.js:668 msgid "Error setting expiration date" msgstr "Błąd podczas ustawiania daty wygaśnięcia" -#: js/share.js:672 +#: js/share.js:683 msgid "Sending ..." msgstr "Wysyłanie..." -#: js/share.js:683 +#: js/share.js:694 msgid "Email sent" msgstr "E-mail wysłany" diff --git a/l10n/pl/files.po b/l10n/pl/files.po index b94335006bb..a88ee97ad7e 100644 --- a/l10n/pl/files.po +++ b/l10n/pl/files.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:44-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:14-0400\n" +"PO-Revision-Date: 2013-09-30 12:24+0000\n" +"Last-Translator: Cyryl Sochacki \n" "Language-Team: Polish (http://www.transifex.com/projects/p/owncloud/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -79,23 +79,23 @@ msgstr "Za mało dostępnego miejsca" #: ajax/upload.php:120 ajax/upload.php:143 msgid "Upload failed. Could not get file info." -msgstr "" +msgstr "Nieudane przesłanie. Nie można pobrać informacji o pliku." #: ajax/upload.php:136 msgid "Upload failed. Could not find uploaded file" -msgstr "" +msgstr "Nieudane przesłanie. Nie można znaleźć przesyłanego pliku" #: ajax/upload.php:160 msgid "Invalid directory." msgstr "Zła ścieżka." -#: appinfo/app.php:12 +#: appinfo/app.php:11 msgid "Files" msgstr "Pliki" #: js/file-upload.js:244 msgid "Unable to upload {filename} as it is a directory or has 0 bytes" -msgstr "" +msgstr "Nie można przesłać {filename} być może jest katalogiem lub posiada 0 bajtów" #: js/file-upload.js:255 msgid "Not enough space available" @@ -107,7 +107,7 @@ msgstr "Wczytywanie anulowane." #: js/file-upload.js:356 msgid "Could not get result from server." -msgstr "" +msgstr "Nie można uzyskać wyniku z serwera." #: js/file-upload.js:446 msgid "" @@ -227,7 +227,7 @@ msgstr "Pobieranie jest przygotowywane. Może to zająć trochę czasu jeśli pl #: js/files.js:507 js/files.js:545 msgid "Error moving file" -msgstr "" +msgstr "Błąd prz przenoszeniu pliku" #: js/files.js:558 templates/index.php:61 msgid "Name" diff --git a/l10n/pl/lib.po b/l10n/pl/lib.po index beae34e5803..9e29c51c5a9 100644 --- a/l10n/pl/lib.po +++ b/l10n/pl/lib.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-16 11:33-0400\n" -"PO-Revision-Date: 2013-09-16 15:34+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" +"PO-Revision-Date: 2013-09-30 12:26+0000\n" +"Last-Translator: Cyryl Sochacki \n" "Language-Team: Polish (http://www.transifex.com/projects/p/owncloud/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,53 +18,53 @@ msgstr "" "Language: pl\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: app.php:239 +#: app.php:237 #, php-format msgid "" "App \"%s\" can't be installed because it is not compatible with this version" " of ownCloud." msgstr "Aplikacja \"%s\" nie może zostać zainstalowana, ponieważ nie jest zgodna z tą wersją ownCloud." -#: app.php:250 +#: app.php:248 msgid "No app name specified" msgstr "Nie określono nazwy aplikacji" -#: app.php:361 +#: app.php:352 msgid "Help" msgstr "Pomoc" -#: app.php:374 +#: app.php:365 msgid "Personal" msgstr "Osobiste" -#: app.php:385 +#: app.php:376 msgid "Settings" msgstr "Ustawienia" -#: app.php:397 +#: app.php:388 msgid "Users" msgstr "Użytkownicy" -#: app.php:410 +#: app.php:401 msgid "Admin" msgstr "Administrator" -#: app.php:839 +#: app.php:832 #, php-format msgid "Failed to upgrade \"%s\"." msgstr "Błąd przy aktualizacji \"%s\"." #: avatar.php:56 msgid "Custom profile pictures don't work with encryption yet" -msgstr "" +msgstr "Domyślny profil zdjęć nie działa z szyfrowaniem jeszcze" #: avatar.php:64 msgid "Unknown filetype" -msgstr "" +msgstr "Nieznany typ pliku" #: avatar.php:69 msgid "Invalid image" -msgstr "" +msgstr "Błędne zdjęcie" #: defaults.php:35 msgid "web services under your control" @@ -165,15 +165,15 @@ msgstr "Błąd uwierzytelniania" msgid "Token expired. Please reload page." msgstr "Token wygasł. Proszę ponownie załadować stronę." -#: search/provider/file.php:17 search/provider/file.php:35 +#: search/provider/file.php:18 search/provider/file.php:36 msgid "Files" msgstr "Pliki" -#: search/provider/file.php:26 search/provider/file.php:33 +#: search/provider/file.php:27 search/provider/file.php:34 msgid "Text" msgstr "Połączenie tekstowe" -#: search/provider/file.php:29 +#: search/provider/file.php:30 msgid "Images" msgstr "Obrazy" @@ -277,6 +277,11 @@ msgstr "Serwer internetowy nie jest jeszcze poprawnie skonfigurowany, aby umożl msgid "Please double check the installation guides." msgstr "Sprawdź ponownie przewodniki instalacji." +#: tags.php:194 +#, php-format +msgid "Could not find category \"%s\"" +msgstr "Nie można odnaleźć kategorii \"%s\"" + #: template/functions.php:96 msgid "seconds ago" msgstr "sekund temu" @@ -332,8 +337,3 @@ msgstr "lat temu" #: template.php:297 msgid "Caused by:" msgstr "Spowodowane przez:" - -#: vcategories.php:188 vcategories.php:249 -#, php-format -msgid "Could not find category \"%s\"" -msgstr "Nie można odnaleźć kategorii \"%s\"" diff --git a/l10n/pl/settings.po b/l10n/pl/settings.po index 5b5e435ef1c..830b2045a3f 100644 --- a/l10n/pl/settings.po +++ b/l10n/pl/settings.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud\n" "Report-Msgid-Bugs-To: http://bugs.owncloud.org/\n" -"POT-Creation-Date: 2013-09-20 10:45-0400\n" -"PO-Revision-Date: 2013-09-20 14:45+0000\n" -"Last-Translator: I Robot \n" +"POT-Creation-Date: 2013-09-30 10:17-0400\n" +"PO-Revision-Date: 2013-09-30 12:15+0000\n" +"Last-Translator: Cyryl Sochacki \n" "Language-Team: Polish (http://www.transifex.com/projects/p/owncloud/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -88,7 +88,7 @@ msgstr "Nie można uaktualnić aplikacji." #: changepassword/controller.php:20 msgid "Wrong password" -msgstr "" +msgstr "Złe hasło" #: changepassword/controller.php:42 msgid "No user supplied" @@ -113,17 +113,17 @@ msgstr "" #: changepassword/controller.php:92 changepassword/controller.php:103 msgid "Unable to change password" -msgstr "" +msgstr "Nie można zmienić hasła" #: js/apps.js:43 msgid "Update to {appversion}" msgstr "Aktualizacja do {appversion}" -#: js/apps.js:49 js/apps.js:82 js/apps.js:108 +#: js/apps.js:49 js/apps.js:82 js/apps.js:110 msgid "Disable" msgstr "Wyłącz" -#: js/apps.js:49 js/apps.js:89 js/apps.js:102 js/apps.js:117 +#: js/apps.js:49 js/apps.js:90 js/apps.js:103 js/apps.js:119 msgid "Enable" msgstr "Włącz" @@ -131,43 +131,43 @@ msgstr "Włącz" msgid "Please wait...." msgstr "Proszę czekać..." -#: js/apps.js:79 js/apps.js:80 js/apps.js:100 +#: js/apps.js:79 js/apps.js:80 js/apps.js:101 msgid "Error while disabling app" msgstr "Błąd podczas wyłączania aplikacji" -#: js/apps.js:99 js/apps.js:112 js/apps.js:113 +#: js/apps.js:100 js/apps.js:114 js/apps.js:115 msgid "Error while enabling app" msgstr "Błąd podczas włączania aplikacji" -#: js/apps.js:123 +#: js/apps.js:125 msgid "Updating...." msgstr "Aktualizacja w toku..." -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error while updating app" msgstr "Błąd podczas aktualizacji aplikacji" -#: js/apps.js:126 +#: js/apps.js:128 msgid "Error" msgstr "Błąd" -#: js/apps.js:127 templates/apps.php:43 +#: js/apps.js:129 templates/apps.php:43 msgid "Update" msgstr "Aktualizuj" -#: js/apps.js:130 +#: js/apps.js:132 msgid "Updated" msgstr "Zaktualizowano" -#: js/personal.js:220 +#: js/personal.js:221 msgid "Select a profile picture" -msgstr "" +msgstr "Wybierz zdjęcie profilu" -#: js/personal.js:265 +#: js/personal.js:266 msgid "Decrypting files... Please wait, this can take some time." msgstr "Odszyfrowuje pliki... Proszę czekać, to może zająć jakiś czas." -#: js/personal.js:287 +#: js/personal.js:288 msgid "Saving..." msgstr "Zapisywanie..." @@ -495,15 +495,15 @@ msgstr "Zdjęcie profilu" #: templates/personal.php:90 msgid "Upload new" -msgstr "" +msgstr "Wczytaj nowe" #: templates/personal.php:92 msgid "Select new from Files" -msgstr "" +msgstr "Wybierz nowe z plików" #: templates/personal.php:93 msgid "Remove image" -msgstr "" +msgstr "Usuń zdjęcie" #: templates/personal.php:94 msgid "Either png or jpg. Ideally square but you will be able to crop it." @@ -515,7 +515,7 @@ msgstr "Anuluj" #: templates/personal.php:98 msgid "Choose as profile image" -msgstr "" +msgstr "Wybierz zdjęcie profilu" #: templates/personal.php:106 templates/personal.php:107 msgid "Language" diff --git a/l10n/templates/core.pot b/l10n/templates/core.pot index afb3a410c4c..687b168209c 100644 --- a/l10n/templates/core.pot +++ b/l10n/templates/core.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files.pot b/l10n/templates/files.pot index 1e72820c523..5a5cf056beb 100644 --- a/l10n/templates/files.pot +++ b/l10n/templates/files.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:14-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_encryption.pot b/l10n/templates/files_encryption.pot index aea2b2282e1..312f7f29bb0 100644 --- a/l10n/templates/files_encryption.pot +++ b/l10n/templates/files_encryption.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:15-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_external.pot b/l10n/templates/files_external.pot index ad32cfb2fcf..0ec2c070912 100644 --- a/l10n/templates/files_external.pot +++ b/l10n/templates/files_external.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_sharing.pot b/l10n/templates/files_sharing.pot index e9a596f361c..77c296c9a7c 100644 --- a/l10n/templates/files_sharing.pot +++ b/l10n/templates/files_sharing.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_trashbin.pot b/l10n/templates/files_trashbin.pot index 044fb375dfc..b379edf9e93 100644 --- a/l10n/templates/files_trashbin.pot +++ b/l10n/templates/files_trashbin.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/files_versions.pot b/l10n/templates/files_versions.pot index a61952105bd..4d7bff6e8b6 100644 --- a/l10n/templates/files_versions.pot +++ b/l10n/templates/files_versions.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/lib.pot b/l10n/templates/lib.pot index 2f54bdc2335..cdaf465ab30 100644 --- a/l10n/templates/lib.pot +++ b/l10n/templates/lib.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,38 +18,38 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -#: app.php:239 +#: app.php:237 #, php-format msgid "" "App \"%s\" can't be installed because it is not compatible with this version " "of ownCloud." msgstr "" -#: app.php:250 +#: app.php:248 msgid "No app name specified" msgstr "" -#: app.php:361 +#: app.php:352 msgid "Help" msgstr "" -#: app.php:374 +#: app.php:365 msgid "Personal" msgstr "" -#: app.php:385 +#: app.php:376 msgid "Settings" msgstr "" -#: app.php:397 +#: app.php:388 msgid "Users" msgstr "" -#: app.php:410 +#: app.php:401 msgid "Admin" msgstr "" -#: app.php:839 +#: app.php:832 #, php-format msgid "Failed to upgrade \"%s\"." msgstr "" @@ -277,6 +277,11 @@ msgstr "" msgid "Please double check the installation guides." msgstr "" +#: tags.php:194 +#, php-format +msgid "Could not find category \"%s\"" +msgstr "" + #: template/functions.php:96 msgid "seconds ago" msgstr "" @@ -328,8 +333,3 @@ msgstr "" #: template.php:297 msgid "Caused by:" msgstr "" - -#: vcategories.php:188 vcategories.php:249 -#, php-format -msgid "Could not find category \"%s\"" -msgstr "" diff --git a/l10n/templates/settings.pot b/l10n/templates/settings.pot index a669dad822d..af2b7236802 100644 --- a/l10n/templates/settings.pot +++ b/l10n/templates/settings.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/user_ldap.pot b/l10n/templates/user_ldap.pot index 0848d993537..ca738710f5c 100644 --- a/l10n/templates/user_ldap.pot +++ b/l10n/templates/user_ldap.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/l10n/templates/user_webdavauth.pot b/l10n/templates/user_webdavauth.pot index ec5a60a6ecb..d3a899a1fe5 100644 --- a/l10n/templates/user_webdavauth.pot +++ b/l10n/templates/user_webdavauth.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: ownCloud Core 5.0.0\n" "Report-Msgid-Bugs-To: translations@owncloud.org\n" -"POT-Creation-Date: 2013-09-29 00:02-0400\n" +"POT-Creation-Date: 2013-09-30 10:16-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/lib/l10n/hu_HU.php b/lib/l10n/hu_HU.php index 7ec7621a655..e944291caee 100644 --- a/lib/l10n/hu_HU.php +++ b/lib/l10n/hu_HU.php @@ -1,11 +1,14 @@ "Nincs az alkalmazás név megadva.", "Help" => "Súgó", "Personal" => "Személyes", "Settings" => "Beállítások", "Users" => "Felhasználók", "Admin" => "Adminsztráció", "Failed to upgrade \"%s\"." => "Sikertelen Frissítés \"%s\".", +"Unknown filetype" => "Ismeretlen file tipús", +"Invalid image" => "Hibás kép", "web services under your control" => "webszolgáltatások saját kézben", "cannot open \"%s\"" => "nem sikerült megnyitni \"%s\"", "ZIP download is turned off." => "A ZIP-letöltés nincs engedélyezve.", @@ -13,6 +16,10 @@ $TRANSLATIONS = array( "Back to Files" => "Vissza a Fájlokhoz", "Selected files too large to generate zip file." => "A kiválasztott fájlok túl nagyok a zip tömörítéshez.", "Download the files in smaller chunks, seperately or kindly ask your administrator." => "Tölts le a fileokat kisebb chunkokban, kölün vagy kérj segitséget a rendszergazdádtól.", +"App does not provide an info.xml file" => "Az alkalmazás nem szolgáltatott info.xml file-t", +"App can't be installed because it is not compatible with this version of ownCloud" => "Az alalmazás nem telepíthető, mert nem kompatibilis az ownClod ezzel a verziójával.", +"App directory already exists" => "Az alkalmazás mappája már létezik", +"Can't create app folder. Please fix permissions. %s" => "Nem lehetett létrehozni az alkalmzás mappáját. Kérlek ellenőrizd a jogosultásgokat. %s", "Application is not enabled" => "Az alkalmazás nincs engedélyezve", "Authentication error" => "Azonosítási hiba", "Token expired. Please reload page." => "A token lejárt. Frissítse az oldalt.", @@ -39,6 +46,7 @@ $TRANSLATIONS = array( "Set an admin password." => "Állítson be egy jelszót az adminisztrációhoz.", "Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Az Ön webkiszolgálója nincs megfelelően beállítva az állományok szinkronizálásához, mert a WebDAV-elérés úgy tűnik, nem működik.", "Please double check the installation guides." => "Kérjük tüzetesen tanulmányozza át a telepítési útmutatót.", +"Could not find category \"%s\"" => "Ez a kategória nem található: \"%s\"", "seconds ago" => "pár másodperce", "_%n minute ago_::_%n minutes ago_" => array("",""), "_%n hour ago_::_%n hours ago_" => array("",""), @@ -49,7 +57,6 @@ $TRANSLATIONS = array( "_%n month ago_::_%n months ago_" => array("",""), "last year" => "tavaly", "years ago" => "több éve", -"Caused by:" => "Okozta:", -"Could not find category \"%s\"" => "Ez a kategória nem található: \"%s\"" +"Caused by:" => "Okozta:" ); $PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ko.php b/lib/l10n/ko.php index eec5be65abd..3ef39fefa60 100644 --- a/lib/l10n/ko.php +++ b/lib/l10n/ko.php @@ -8,12 +8,16 @@ $TRANSLATIONS = array( "Users" => "사용자", "Admin" => "관리자", "Failed to upgrade \"%s\"." => "\"%s\" 업그레이드에 실패했습니다.", +"Custom profile pictures don't work with encryption yet" => "개개인의 프로필 사진은 아직은 암호화 되지 않습니다", +"Unknown filetype" => "알수없는 파일형식", +"Invalid image" => "잘못된 그림", "web services under your control" => "내가 관리하는 웹 서비스", "cannot open \"%s\"" => "\"%s\"을(를) 열 수 없습니다.", "ZIP download is turned off." => "ZIP 다운로드가 비활성화되었습니다.", "Files need to be downloaded one by one." => "파일을 개별적으로 다운로드해야 합니다.", "Back to Files" => "파일로 돌아가기", "Selected files too large to generate zip file." => "선택한 파일들은 ZIP 파일을 생성하기에 너무 큽니다.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "작은 조각들 안에 들어있는 파일들을 받고자 하신다면, 나누어서 받으시거나 혹은 시스템 관리자에게 정중하게 물어보십시오", "No source specified when installing app" => "앱을 설치할 때 소스가 지정되지 않았습니다.", "No href specified when installing app from http" => "http에서 앱을 설치할 대 href가 지정되지 않았습니다.", "No path specified when installing app from local file" => "로컬 파일에서 앱을 설치할 때 경로가 지정되지 않았습니다.", @@ -52,6 +56,7 @@ $TRANSLATIONS = array( "Set an admin password." => "관리자 비밀번호 설정", "Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "WebDAV 인터페이스가 제대로 작동하지 않습니다. 웹 서버에서 파일 동기화를 사용할 수 있도록 설정이 제대로 되지 않은 것 같습니다.", "Please double check the installation guides." => "설치 가이드를 다시 한 번 확인하십시오.", +"Could not find category \"%s\"" => "분류 \"%s\"을(를) 찾을 수 없습니다.", "seconds ago" => "초 전", "_%n minute ago_::_%n minutes ago_" => array("%n분 전 "), "_%n hour ago_::_%n hours ago_" => array("%n시간 전 "), @@ -62,7 +67,6 @@ $TRANSLATIONS = array( "_%n month ago_::_%n months ago_" => array("%n달 전 "), "last year" => "작년", "years ago" => "년 전", -"Caused by:" => "원인: ", -"Could not find category \"%s\"" => "분류 \"%s\"을(를) 찾을 수 없습니다." +"Caused by:" => "원인: " ); $PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/pl.php b/lib/l10n/pl.php index 4acd735d692..270559b4e50 100644 --- a/lib/l10n/pl.php +++ b/lib/l10n/pl.php @@ -8,6 +8,9 @@ $TRANSLATIONS = array( "Users" => "Użytkownicy", "Admin" => "Administrator", "Failed to upgrade \"%s\"." => "Błąd przy aktualizacji \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Domyślny profil zdjęć nie działa z szyfrowaniem jeszcze", +"Unknown filetype" => "Nieznany typ pliku", +"Invalid image" => "Błędne zdjęcie", "web services under your control" => "Kontrolowane serwisy", "cannot open \"%s\"" => "Nie można otworzyć \"%s\"", "ZIP download is turned off." => "Pobieranie ZIP jest wyłączone.", @@ -53,6 +56,7 @@ $TRANSLATIONS = array( "Set an admin password." => "Ustaw hasło administratora.", "Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serwer internetowy nie jest jeszcze poprawnie skonfigurowany, aby umożliwić synchronizację plików, ponieważ interfejs WebDAV wydaje się być uszkodzony.", "Please double check the installation guides." => "Sprawdź ponownie przewodniki instalacji.", +"Could not find category \"%s\"" => "Nie można odnaleźć kategorii \"%s\"", "seconds ago" => "sekund temu", "_%n minute ago_::_%n minutes ago_" => array("%n minute temu","%n minut temu","%n minut temu"), "_%n hour ago_::_%n hours ago_" => array("%n godzinę temu","%n godzin temu","%n godzin temu"), @@ -63,7 +67,6 @@ $TRANSLATIONS = array( "_%n month ago_::_%n months ago_" => array("%n miesiąc temu","%n miesięcy temu","%n miesięcy temu"), "last year" => "w zeszłym roku", "years ago" => "lat temu", -"Caused by:" => "Spowodowane przez:", -"Could not find category \"%s\"" => "Nie można odnaleźć kategorii \"%s\"" +"Caused by:" => "Spowodowane przez:" ); $PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/settings/l10n/hu_HU.php b/settings/l10n/hu_HU.php index f31826c149f..cba844e7818 100644 --- a/settings/l10n/hu_HU.php +++ b/settings/l10n/hu_HU.php @@ -16,15 +16,25 @@ $TRANSLATIONS = array( "Unable to add user to group %s" => "A felhasználó nem adható hozzá ehhez a csoporthoz: %s", "Unable to remove user from group %s" => "A felhasználó nem távolítható el ebből a csoportból: %s", "Couldn't update app." => "A program frissítése nem sikerült.", +"Wrong password" => "Hibás jelszó", +"No user supplied" => "Nincs felhasználó által mellékelve", +"Please provide an admin recovery password, otherwise all user data will be lost" => "Add meg az admin helyreállító jelszót, máskülönben az összes felhasználói adat elveszik.", +"Wrong admin recovery password. Please check the password and try again." => "Hibás admin helyreállítási jelszó. Ellenörizd a jelszót és próbáld újra.", +"Back-end doesn't support password change, but the users encryption key was successfully updated." => "A back-end nem támogatja a jelszó módosítást, de felhasználó titkosítási kulcsa sikeresen frissítve lett.", +"Unable to change password" => "Nem sikerült megváltoztatni a jelszót", "Update to {appversion}" => "Frissítés erre a verzióra: {appversion}", "Disable" => "Letiltás", "Enable" => "engedélyezve", "Please wait...." => "Kérem várjon...", +"Error while disabling app" => "Hiba az alkalmazás kikapcsolása közben", +"Error while enabling app" => "Hiba az alalmazás engedélyezése közben", "Updating...." => "Frissítés folyamatban...", "Error while updating app" => "Hiba történt a programfrissítés közben", "Error" => "Hiba", "Update" => "Frissítés", "Updated" => "Frissítve", +"Select a profile picture" => "Válassz profil képet", +"Decrypting files... Please wait, this can take some time." => "File-ok kititkosítása folyamatban... Kérlek várj, ez hosszabb ideig is eltarthat ...", "Saving..." => "Mentés...", "deleted" => "törölve", "undo" => "visszavonás", @@ -98,11 +108,20 @@ $TRANSLATIONS = array( "Your email address" => "Az Ön email címe", "Fill in an email address to enable password recovery" => "Adja meg az email címét, hogy jelszó-emlékeztetőt kérhessen, ha elfelejtette a jelszavát!", "Profile picture" => "Profilkép", +"Upload new" => "Új feltöltése", +"Select new from Files" => "Új kiválasztása Fileokból", +"Remove image" => "Kép eltávolítása", +"Either png or jpg. Ideally square but you will be able to crop it." => "Egyaránt png vagy jpg. Az ideális ha négyzet alaku, de késöbb még átszabható", +"Abort" => "Megszakítás", +"Choose as profile image" => "Válassz profil képet", "Language" => "Nyelv", "Help translate" => "Segítsen a fordításban!", "WebDAV" => "WebDAV", "Use this address to access your Files via WebDAV" => "Ezt a címet használja, ha WebDAV-on keresztül szeretné elérni az állományait", "Encryption" => "Titkosítás", +"The encryption app is no longer enabled, decrypt all your file" => "A titkosító alkalmzás a továbbiakban nincs engedélyezve, kititkosítja az összes fileodat", +"Log-in password" => "Bejelentkezési jelszó", +"Decrypt all Files" => "Kititkosítja az összes file-t", "Login Name" => "Bejelentkezési név", "Create" => "Létrehozás", "Admin Recovery Password" => "A jelszóvisszaállítás adminisztrációja", diff --git a/settings/l10n/ja_JP.php b/settings/l10n/ja_JP.php index 12784e3f537..bfaa9827b21 100644 --- a/settings/l10n/ja_JP.php +++ b/settings/l10n/ja_JP.php @@ -16,6 +16,12 @@ $TRANSLATIONS = array( "Unable to add user to group %s" => "ユーザをグループ %s に追加できません", "Unable to remove user from group %s" => "ユーザをグループ %s から削除できません", "Couldn't update app." => "アプリを更新出来ませんでした。", +"Wrong password" => "無効なパスワード", +"No user supplied" => "ユーザが指定されていません", +"Please provide an admin recovery password, otherwise all user data will be lost" => "復元用の管理者パスワードを入力してください。そうでない場合は、全ユーザのデータが失われます。", +"Wrong admin recovery password. Please check the password and try again." => "無効な復元用の管理者パスワード。パスワードを確認して再度実行してください。", +"Back-end doesn't support password change, but the users encryption key was successfully updated." => "バックエンドはパスワード変更をサポートしていませんが、ユーザの暗号化キーは正常に更新されました。", +"Unable to change password" => "パスワードを変更できません", "Update to {appversion}" => "{appversion} に更新", "Disable" => "無効", "Enable" => "有効化", @@ -102,7 +108,10 @@ $TRANSLATIONS = array( "Your email address" => "あなたのメールアドレス", "Fill in an email address to enable password recovery" => "※パスワード回復を有効にするにはメールアドレスの入力が必要です", "Profile picture" => "プロフィール写真", +"Upload new" => "新規にアップロード", +"Select new from Files" => "ファイルから新規に選択", "Remove image" => "画像を削除", +"Either png or jpg. Ideally square but you will be able to crop it." => "png と jpg のいずれか。正方形が理想ですが、切り取って加工することも可能です。", "Abort" => "中止", "Choose as profile image" => "プロファイル画像として選択", "Language" => "言語", diff --git a/settings/l10n/lt_LT.php b/settings/l10n/lt_LT.php index a23d21ed7f7..df0247fc27e 100644 --- a/settings/l10n/lt_LT.php +++ b/settings/l10n/lt_LT.php @@ -16,6 +16,12 @@ $TRANSLATIONS = array( "Unable to add user to group %s" => "Nepavyko pridėti vartotojo prie grupės %s", "Unable to remove user from group %s" => "Nepavyko ištrinti vartotojo iš grupės %s", "Couldn't update app." => "Nepavyko atnaujinti programos.", +"Wrong password" => "Neteisingas slaptažodis", +"No user supplied" => "Nepateiktas naudotojas", +"Please provide an admin recovery password, otherwise all user data will be lost" => "Prašome įvesti administratoriaus atkūrimo slaptažodį, kitaip visi naudotojo suomenys bus prarasti", +"Wrong admin recovery password. Please check the password and try again." => "Netinkamas administratoriau atkūrimo slaptažodis. Prašome pasitikrinti ir bandyti vėl.", +"Back-end doesn't support password change, but the users encryption key was successfully updated." => "Sistema nepalaiko slaptažodžio keitimo, bet naudotojo šifravimo raktas buvo sėkmingai atnaujintas.", +"Unable to change password" => "Nepavyksta pakeisti slaptažodžio", "Update to {appversion}" => "Atnaujinti iki {appversion}", "Disable" => "Išjungti", "Enable" => "Įjungti", diff --git a/settings/l10n/pl.php b/settings/l10n/pl.php index d07d1f7a4d2..6cce72df4b6 100644 --- a/settings/l10n/pl.php +++ b/settings/l10n/pl.php @@ -16,6 +16,8 @@ $TRANSLATIONS = array( "Unable to add user to group %s" => "Nie można dodać użytkownika do grupy %s", "Unable to remove user from group %s" => "Nie można usunąć użytkownika z grupy %s", "Couldn't update app." => "Nie można uaktualnić aplikacji.", +"Wrong password" => "Złe hasło", +"Unable to change password" => "Nie można zmienić hasła", "Update to {appversion}" => "Aktualizacja do {appversion}", "Disable" => "Wyłącz", "Enable" => "Włącz", @@ -27,6 +29,7 @@ $TRANSLATIONS = array( "Error" => "Błąd", "Update" => "Aktualizuj", "Updated" => "Zaktualizowano", +"Select a profile picture" => "Wybierz zdjęcie profilu", "Decrypting files... Please wait, this can take some time." => "Odszyfrowuje pliki... Proszę czekać, to może zająć jakiś czas.", "Saving..." => "Zapisywanie...", "deleted" => "usunięto", @@ -101,7 +104,11 @@ $TRANSLATIONS = array( "Your email address" => "Twój adres e-mail", "Fill in an email address to enable password recovery" => "Podaj adres e-mail, aby uzyskać możliwość odzyskania hasła", "Profile picture" => "Zdjęcie profilu", +"Upload new" => "Wczytaj nowe", +"Select new from Files" => "Wybierz nowe z plików", +"Remove image" => "Usuń zdjęcie", "Abort" => "Anuluj", +"Choose as profile image" => "Wybierz zdjęcie profilu", "Language" => "Język", "Help translate" => "Pomóż w tłumaczeniu", "WebDAV" => "WebDAV", -- cgit v1.2.3 From 9c9dc276b7a1d2592c4fb0a887888632dc1f1e29 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 25 Sep 2013 13:36:30 +0200 Subject: move the private namespace OC into lib/private - OCP will stay in lib/public Conflicts: lib/private/vcategories.php --- lib/allconfig.php | 77 -- lib/api.php | 293 ------ lib/app.php | 967 ------------------ lib/appconfig.php | 203 ---- lib/appframework/app.php | 98 -- lib/appframework/controller/controller.php | 142 --- lib/appframework/core/api.php | 348 ------- .../dependencyinjection/dicontainer.php | 146 --- lib/appframework/http/dispatcher.php | 100 -- lib/appframework/http/downloadresponse.php | 50 - lib/appframework/http/http.php | 148 --- lib/appframework/http/redirectresponse.php | 56 - lib/appframework/http/request.php | 307 ------ lib/appframework/middleware/middleware.php | 100 -- .../middleware/middlewaredispatcher.php | 159 --- .../middleware/security/securityexception.php | 41 - .../middleware/security/securitymiddleware.php | 136 --- lib/appframework/routing/routeactionhandler.php | 42 - lib/appframework/routing/routeconfig.php | 186 ---- .../utility/methodannotationreader.php | 61 -- lib/appframework/utility/simplecontainer.php | 44 - lib/appframework/utility/timefactory.php | 42 - lib/archive.php | 137 --- lib/archive/tar.php | 339 ------ lib/archive/zip.php | 201 ---- lib/arrayparser.php | 189 ---- lib/autoloader.php | 6 +- lib/avatar.php | 89 -- lib/backgroundjob.php | 52 - lib/backgroundjob/job.php | 49 - lib/backgroundjob/joblist.php | 172 ---- lib/backgroundjob/legacy/queuedjob.php | 18 - lib/backgroundjob/legacy/regularjob.php | 15 - lib/backgroundjob/queuedjob.php | 28 - lib/backgroundjob/timedjob.php | 41 - lib/base.php | 2 +- lib/cache.php | 112 -- lib/cache/broker.php | 63 -- lib/cache/file.php | 118 --- lib/cache/fileglobal.php | 106 -- lib/cache/fileglobalgc.php | 9 - lib/cache/usercache.php | 77 -- lib/config.php | 186 ---- lib/connector/sabre/ServiceUnavailable.php | 22 - lib/connector/sabre/auth.php | 84 -- lib/connector/sabre/directory.php | 256 ----- lib/connector/sabre/file.php | 176 ---- lib/connector/sabre/locks.php | 189 ---- lib/connector/sabre/maintenanceplugin.php | 59 -- lib/connector/sabre/node.php | 238 ----- lib/connector/sabre/objecttree.php | 142 --- lib/connector/sabre/principal.php | 128 --- lib/connector/sabre/quotaplugin.php | 97 -- lib/connector/sabre/request.php | 50 - lib/contactsmanager.php | 145 --- lib/db.php | 462 --------- lib/db/adapter.php | 72 -- lib/db/adapteroci8.php | 28 - lib/db/adapterpgsql.php | 23 - lib/db/adaptersqlite.php | 60 -- lib/db/adaptersqlsrv.php | 28 - lib/db/connection.php | 197 ---- lib/db/mdb2schemamanager.php | 150 --- lib/db/mdb2schemareader.php | 305 ------ lib/db/mdb2schemawriter.php | 133 --- lib/db/oracleconnection.php | 50 - lib/db/statementwrapper.php | 191 ---- lib/defaults.php | 135 --- lib/eventsource.php | 85 -- lib/filechunking.php | 149 --- lib/fileproxy.php | 115 --- lib/fileproxy/fileoperations.php | 37 - lib/files.php | 321 ------ lib/files/cache/backgroundwatcher.php | 104 -- lib/files/cache/cache.php | 582 ----------- lib/files/cache/legacy.php | 136 --- lib/files/cache/permissions.php | 143 --- lib/files/cache/scanner.php | 258 ----- lib/files/cache/storage.php | 60 -- lib/files/cache/updater.php | 161 --- lib/files/cache/upgrade.php | 227 ----- lib/files/cache/watcher.php | 72 -- lib/files/filesystem.php | 770 -------------- lib/files/mapper.php | 239 ----- lib/files/mount/manager.php | 127 --- lib/files/mount/mount.php | 148 --- lib/files/node/file.php | 155 --- lib/files/node/folder.php | 382 ------- lib/files/node/node.php | 245 ----- lib/files/node/nonexistingfile.php | 89 -- lib/files/node/nonexistingfolder.php | 113 -- lib/files/node/root.php | 337 ------ lib/files/storage/common.php | 374 ------- lib/files/storage/commontest.php | 80 -- lib/files/storage/loader.php | 38 - lib/files/storage/local.php | 310 ------ lib/files/storage/mappedlocal.php | 365 ------- lib/files/storage/storage.php | 343 ------- lib/files/storage/temporary.php | 27 - lib/files/storage/wrapper/quota.php | 104 -- lib/files/storage/wrapper/wrapper.php | 427 -------- lib/files/stream/close.php | 100 -- lib/files/stream/dir.php | 47 - lib/files/stream/oc.php | 129 --- lib/files/stream/quota.php | 128 --- lib/files/stream/staticstream.php | 156 --- lib/files/type/detection.php | 121 --- lib/files/type/templatemanager.php | 46 - lib/files/utils/scanner.php | 96 -- lib/files/view.php | 1078 -------------------- lib/geo.php | 31 - lib/group.php | 301 ------ lib/group/backend.php | 157 --- lib/group/database.php | 239 ----- lib/group/dummy.php | 160 --- lib/group/example.php | 109 -- lib/group/group.php | 248 ----- lib/group/interface.php | 83 -- lib/group/manager.php | 169 --- lib/helper.php | 934 ----------------- lib/hintexception.php | 27 - lib/hook.php | 100 -- lib/hooks/basicemitter.php | 89 -- lib/hooks/emitter.php | 32 - lib/hooks/forwardingemitter.php | 50 - lib/hooks/legacyemitter.php | 16 - lib/hooks/publicemitter.php | 20 - lib/image.php | 1020 ------------------ lib/installer.php | 481 --------- lib/json.php | 115 --- lib/l10n.php | 546 ---------- lib/l10n/ach.php | 8 - lib/l10n/af_ZA.php | 14 - lib/l10n/ar.php | 50 - lib/l10n/be.php | 8 - lib/l10n/bg_BG.php | 51 - lib/l10n/bn_BD.php | 29 - lib/l10n/bs.php | 8 - lib/l10n/ca.php | 72 -- lib/l10n/cs_CZ.php | 72 -- lib/l10n/cy_GB.php | 50 - lib/l10n/da.php | 72 -- lib/l10n/de.php | 72 -- lib/l10n/de_AT.php | 8 - lib/l10n/de_CH.php | 59 -- lib/l10n/de_DE.php | 72 -- lib/l10n/el.php | 55 - lib/l10n/en@pirate.php | 9 - lib/l10n/en_GB.php | 72 -- lib/l10n/eo.php | 48 - lib/l10n/es.php | 69 -- lib/l10n/es_AR.php | 69 -- lib/l10n/es_MX.php | 8 - lib/l10n/et_EE.php | 72 -- lib/l10n/eu.php | 55 - lib/l10n/fa.php | 51 - lib/l10n/fi.php | 5 - lib/l10n/fi_FI.php | 62 -- lib/l10n/fr.php | 72 -- lib/l10n/gl.php | 72 -- lib/l10n/he.php | 33 - lib/l10n/hi.php | 12 - lib/l10n/hr.php | 23 - lib/l10n/hu_HU.php | 62 -- lib/l10n/hy.php | 8 - lib/l10n/ia.php | 16 - lib/l10n/id.php | 50 - lib/l10n/is.php | 31 - lib/l10n/it.php | 72 -- lib/l10n/ja_JP.php | 72 -- lib/l10n/ka.php | 17 - lib/l10n/ka_GE.php | 50 - lib/l10n/km.php | 8 - lib/l10n/kn.php | 8 - lib/l10n/ko.php | 72 -- lib/l10n/ku_IQ.php | 13 - lib/l10n/lb.php | 23 - lib/l10n/lt_LT.php | 72 -- lib/l10n/lv.php | 55 - lib/l10n/mk.php | 31 - lib/l10n/ml_IN.php | 8 - lib/l10n/ms_MY.php | 17 - lib/l10n/my_MM.php | 27 - lib/l10n/nb_NO.php | 33 - lib/l10n/ne.php | 8 - lib/l10n/nl.php | 72 -- lib/l10n/nn_NO.php | 27 - lib/l10n/nqo.php | 8 - lib/l10n/oc.php | 25 - lib/l10n/pa.php | 16 - lib/l10n/pl.php | 72 -- lib/l10n/pl_PL.php | 5 - lib/l10n/pt_BR.php | 72 -- lib/l10n/pt_PT.php | 57 -- lib/l10n/ro.php | 35 - lib/l10n/ru.php | 72 -- lib/l10n/si_LK.php | 30 - lib/l10n/sk.php | 8 - lib/l10n/sk_SK.php | 69 -- lib/l10n/sl.php | 51 - lib/l10n/sq.php | 50 - lib/l10n/sr.php | 33 - lib/l10n/sr@latin.php | 22 - lib/l10n/string.php | 56 - lib/l10n/sv.php | 69 -- lib/l10n/sw_KE.php | 8 - lib/l10n/ta_LK.php | 31 - lib/l10n/te.php | 17 - lib/l10n/th_TH.php | 31 - lib/l10n/tr.php | 69 -- lib/l10n/ug.php | 19 - lib/l10n/uk.php | 50 - lib/l10n/ur_PK.php | 14 - lib/l10n/vi.php | 31 - lib/l10n/zh_CN.php | 52 - lib/l10n/zh_HK.php | 18 - lib/l10n/zh_TW.php | 69 -- lib/legacy/cache.php | 10 - lib/legacy/config.php | 107 -- lib/legacy/filesystem.php | 415 -------- lib/legacy/filesystemview.php | 9 - lib/legacy/log.php | 50 - lib/legacy/preferences.php | 146 --- lib/legacy/updater.php | 14 - lib/log.php | 136 --- lib/log/errorhandler.php | 54 - lib/log/owncloud.php | 112 -- lib/log/rotate.php | 35 - lib/log/syslog.php | 40 - lib/mail.php | 133 --- lib/memcache/apc.php | 67 -- lib/memcache/apcu.php | 28 - lib/memcache/cache.php | 77 -- lib/memcache/factory.php | 69 -- lib/memcache/memcached.php | 76 -- lib/memcache/xcache.php | 60 -- lib/migrate.php | 693 ------------- lib/migration/content.php | 258 ----- lib/migration/provider.php | 52 - lib/mimetypes.list.php | 107 -- lib/minimizer.php | 64 -- lib/minimizer/css.php | 38 - lib/minimizer/js.php | 21 - lib/navigationmanager.php | 64 -- lib/notsquareexception.php | 12 - lib/ocs.php | 263 ----- lib/ocs/cloud.php | 108 -- lib/ocs/config.php | 36 - lib/ocs/person.php | 42 - lib/ocs/privatedata.php | 66 -- lib/ocs/result.php | 97 -- lib/ocsclient.php | 208 ---- lib/preferences.php | 232 ----- lib/preview.php | 630 ------------ lib/preview/image.php | 36 - lib/preview/movies.php | 47 - lib/preview/mp3.php | 48 - lib/preview/office-cl.php | 134 --- lib/preview/office-fallback.php | 142 --- lib/preview/office.php | 22 - lib/preview/pdf.php | 40 - lib/preview/provider.php | 19 - lib/preview/svg.php | 46 - lib/preview/txt.php | 83 -- lib/preview/unknown.php | 27 - lib/previewmanager.php | 38 - lib/private/allconfig.php | 77 ++ lib/private/api.php | 293 ++++++ lib/private/app.php | 967 ++++++++++++++++++ lib/private/appconfig.php | 203 ++++ lib/private/appframework/app.php | 98 ++ lib/private/appframework/controller/controller.php | 142 +++ lib/private/appframework/core/api.php | 348 +++++++ .../dependencyinjection/dicontainer.php | 146 +++ lib/private/appframework/http/dispatcher.php | 100 ++ lib/private/appframework/http/downloadresponse.php | 50 + lib/private/appframework/http/http.php | 148 +++ lib/private/appframework/http/redirectresponse.php | 56 + lib/private/appframework/http/request.php | 307 ++++++ lib/private/appframework/middleware/middleware.php | 100 ++ .../middleware/middlewaredispatcher.php | 159 +++ .../middleware/security/securityexception.php | 41 + .../middleware/security/securitymiddleware.php | 136 +++ .../appframework/routing/routeactionhandler.php | 42 + lib/private/appframework/routing/routeconfig.php | 186 ++++ .../utility/methodannotationreader.php | 61 ++ .../appframework/utility/simplecontainer.php | 44 + lib/private/appframework/utility/timefactory.php | 42 + lib/private/archive.php | 137 +++ lib/private/archive/tar.php | 339 ++++++ lib/private/archive/zip.php | 201 ++++ lib/private/arrayparser.php | 189 ++++ lib/private/avatar.php | 89 ++ lib/private/backgroundjob.php | 52 + lib/private/backgroundjob/job.php | 49 + lib/private/backgroundjob/joblist.php | 172 ++++ lib/private/backgroundjob/legacy/queuedjob.php | 18 + lib/private/backgroundjob/legacy/regularjob.php | 15 + lib/private/backgroundjob/queuedjob.php | 28 + lib/private/backgroundjob/timedjob.php | 41 + lib/private/cache.php | 112 ++ lib/private/cache/broker.php | 63 ++ lib/private/cache/file.php | 118 +++ lib/private/cache/fileglobal.php | 106 ++ lib/private/cache/fileglobalgc.php | 9 + lib/private/cache/usercache.php | 77 ++ lib/private/config.php | 186 ++++ lib/private/connector/sabre/ServiceUnavailable.php | 22 + lib/private/connector/sabre/auth.php | 84 ++ lib/private/connector/sabre/directory.php | 256 +++++ lib/private/connector/sabre/file.php | 176 ++++ lib/private/connector/sabre/locks.php | 189 ++++ lib/private/connector/sabre/maintenanceplugin.php | 59 ++ lib/private/connector/sabre/node.php | 238 +++++ lib/private/connector/sabre/objecttree.php | 142 +++ lib/private/connector/sabre/principal.php | 128 +++ lib/private/connector/sabre/quotaplugin.php | 97 ++ lib/private/connector/sabre/request.php | 50 + lib/private/contactsmanager.php | 145 +++ lib/private/db.php | 462 +++++++++ lib/private/db/adapter.php | 72 ++ lib/private/db/adapteroci8.php | 28 + lib/private/db/adapterpgsql.php | 23 + lib/private/db/adaptersqlite.php | 60 ++ lib/private/db/adaptersqlsrv.php | 28 + lib/private/db/connection.php | 197 ++++ lib/private/db/mdb2schemamanager.php | 150 +++ lib/private/db/mdb2schemareader.php | 305 ++++++ lib/private/db/mdb2schemawriter.php | 133 +++ lib/private/db/oracleconnection.php | 50 + lib/private/db/statementwrapper.php | 191 ++++ lib/private/defaults.php | 135 +++ lib/private/eventsource.php | 85 ++ lib/private/filechunking.php | 149 +++ lib/private/fileproxy.php | 115 +++ lib/private/fileproxy/fileoperations.php | 37 + lib/private/files.php | 321 ++++++ lib/private/files/cache/backgroundwatcher.php | 104 ++ lib/private/files/cache/cache.php | 582 +++++++++++ lib/private/files/cache/legacy.php | 136 +++ lib/private/files/cache/permissions.php | 143 +++ lib/private/files/cache/scanner.php | 258 +++++ lib/private/files/cache/storage.php | 60 ++ lib/private/files/cache/updater.php | 161 +++ lib/private/files/cache/upgrade.php | 227 +++++ lib/private/files/cache/watcher.php | 72 ++ lib/private/files/filesystem.php | 770 ++++++++++++++ lib/private/files/mapper.php | 239 +++++ lib/private/files/mount/manager.php | 127 +++ lib/private/files/mount/mount.php | 148 +++ lib/private/files/node/file.php | 155 +++ lib/private/files/node/folder.php | 382 +++++++ lib/private/files/node/node.php | 245 +++++ lib/private/files/node/nonexistingfile.php | 89 ++ lib/private/files/node/nonexistingfolder.php | 113 ++ lib/private/files/node/root.php | 337 ++++++ lib/private/files/storage/common.php | 374 +++++++ lib/private/files/storage/commontest.php | 80 ++ lib/private/files/storage/loader.php | 38 + lib/private/files/storage/local.php | 310 ++++++ lib/private/files/storage/mappedlocal.php | 365 +++++++ lib/private/files/storage/storage.php | 343 +++++++ lib/private/files/storage/temporary.php | 27 + lib/private/files/storage/wrapper/quota.php | 104 ++ lib/private/files/storage/wrapper/wrapper.php | 427 ++++++++ lib/private/files/stream/close.php | 100 ++ lib/private/files/stream/dir.php | 47 + lib/private/files/stream/oc.php | 129 +++ lib/private/files/stream/quota.php | 128 +++ lib/private/files/stream/staticstream.php | 156 +++ lib/private/files/type/detection.php | 121 +++ lib/private/files/type/templatemanager.php | 46 + lib/private/files/utils/scanner.php | 96 ++ lib/private/files/view.php | 1078 ++++++++++++++++++++ lib/private/geo.php | 31 + lib/private/group.php | 301 ++++++ lib/private/group/backend.php | 157 +++ lib/private/group/database.php | 239 +++++ lib/private/group/dummy.php | 160 +++ lib/private/group/example.php | 109 ++ lib/private/group/group.php | 248 +++++ lib/private/group/interface.php | 83 ++ lib/private/group/manager.php | 169 +++ lib/private/helper.php | 934 +++++++++++++++++ lib/private/hintexception.php | 27 + lib/private/hook.php | 100 ++ lib/private/hooks/basicemitter.php | 89 ++ lib/private/hooks/emitter.php | 32 + lib/private/hooks/forwardingemitter.php | 50 + lib/private/hooks/legacyemitter.php | 16 + lib/private/hooks/publicemitter.php | 20 + lib/private/image.php | 1020 ++++++++++++++++++ lib/private/installer.php | 481 +++++++++ lib/private/json.php | 115 +++ lib/private/l10n.php | 546 ++++++++++ lib/private/l10n/ach.php | 8 + lib/private/l10n/af_ZA.php | 14 + lib/private/l10n/ar.php | 50 + lib/private/l10n/be.php | 8 + lib/private/l10n/bg_BG.php | 51 + lib/private/l10n/bn_BD.php | 29 + lib/private/l10n/bs.php | 8 + lib/private/l10n/ca.php | 72 ++ lib/private/l10n/cs_CZ.php | 72 ++ lib/private/l10n/cy_GB.php | 50 + lib/private/l10n/da.php | 72 ++ lib/private/l10n/de.php | 72 ++ lib/private/l10n/de_AT.php | 8 + lib/private/l10n/de_CH.php | 59 ++ lib/private/l10n/de_DE.php | 72 ++ lib/private/l10n/el.php | 55 + lib/private/l10n/en@pirate.php | 9 + lib/private/l10n/en_GB.php | 72 ++ lib/private/l10n/eo.php | 48 + lib/private/l10n/es.php | 69 ++ lib/private/l10n/es_AR.php | 69 ++ lib/private/l10n/es_MX.php | 8 + lib/private/l10n/et_EE.php | 72 ++ lib/private/l10n/eu.php | 55 + lib/private/l10n/fa.php | 51 + lib/private/l10n/fi.php | 5 + lib/private/l10n/fi_FI.php | 62 ++ lib/private/l10n/fr.php | 72 ++ lib/private/l10n/gl.php | 72 ++ lib/private/l10n/he.php | 33 + lib/private/l10n/hi.php | 12 + lib/private/l10n/hr.php | 23 + lib/private/l10n/hu_HU.php | 62 ++ lib/private/l10n/hy.php | 8 + lib/private/l10n/ia.php | 16 + lib/private/l10n/id.php | 50 + lib/private/l10n/is.php | 31 + lib/private/l10n/it.php | 72 ++ lib/private/l10n/ja_JP.php | 72 ++ lib/private/l10n/ka.php | 17 + lib/private/l10n/ka_GE.php | 50 + lib/private/l10n/km.php | 8 + lib/private/l10n/kn.php | 8 + lib/private/l10n/ko.php | 72 ++ lib/private/l10n/ku_IQ.php | 13 + lib/private/l10n/lb.php | 23 + lib/private/l10n/lt_LT.php | 72 ++ lib/private/l10n/lv.php | 55 + lib/private/l10n/mk.php | 31 + lib/private/l10n/ml_IN.php | 8 + lib/private/l10n/ms_MY.php | 17 + lib/private/l10n/my_MM.php | 27 + lib/private/l10n/nb_NO.php | 33 + lib/private/l10n/ne.php | 8 + lib/private/l10n/nl.php | 72 ++ lib/private/l10n/nn_NO.php | 27 + lib/private/l10n/nqo.php | 8 + lib/private/l10n/oc.php | 25 + lib/private/l10n/pa.php | 16 + lib/private/l10n/pl.php | 72 ++ lib/private/l10n/pl_PL.php | 5 + lib/private/l10n/pt_BR.php | 72 ++ lib/private/l10n/pt_PT.php | 57 ++ lib/private/l10n/ro.php | 35 + lib/private/l10n/ru.php | 72 ++ lib/private/l10n/si_LK.php | 30 + lib/private/l10n/sk.php | 8 + lib/private/l10n/sk_SK.php | 69 ++ lib/private/l10n/sl.php | 51 + lib/private/l10n/sq.php | 50 + lib/private/l10n/sr.php | 33 + lib/private/l10n/sr@latin.php | 22 + lib/private/l10n/string.php | 56 + lib/private/l10n/sv.php | 69 ++ lib/private/l10n/sw_KE.php | 8 + lib/private/l10n/ta_LK.php | 31 + lib/private/l10n/te.php | 17 + lib/private/l10n/th_TH.php | 31 + lib/private/l10n/tr.php | 69 ++ lib/private/l10n/ug.php | 19 + lib/private/l10n/uk.php | 50 + lib/private/l10n/ur_PK.php | 14 + lib/private/l10n/vi.php | 31 + lib/private/l10n/zh_CN.php | 52 + lib/private/l10n/zh_HK.php | 18 + lib/private/l10n/zh_TW.php | 69 ++ lib/private/legacy/cache.php | 10 + lib/private/legacy/config.php | 107 ++ lib/private/legacy/filesystem.php | 415 ++++++++ lib/private/legacy/filesystemview.php | 9 + lib/private/legacy/log.php | 50 + lib/private/legacy/preferences.php | 146 +++ lib/private/legacy/updater.php | 14 + lib/private/log.php | 136 +++ lib/private/log/errorhandler.php | 54 + lib/private/log/owncloud.php | 112 ++ lib/private/log/rotate.php | 35 + lib/private/log/syslog.php | 40 + lib/private/mail.php | 133 +++ lib/private/memcache/apc.php | 67 ++ lib/private/memcache/apcu.php | 28 + lib/private/memcache/cache.php | 77 ++ lib/private/memcache/factory.php | 69 ++ lib/private/memcache/memcached.php | 76 ++ lib/private/memcache/xcache.php | 60 ++ lib/private/migrate.php | 693 +++++++++++++ lib/private/migration/content.php | 258 +++++ lib/private/migration/provider.php | 52 + lib/private/mimetypes.list.php | 107 ++ lib/private/minimizer.php | 64 ++ lib/private/minimizer/css.php | 38 + lib/private/minimizer/js.php | 21 + lib/private/navigationmanager.php | 64 ++ lib/private/notsquareexception.php | 12 + lib/private/ocs.php | 263 +++++ lib/private/ocs/cloud.php | 108 ++ lib/private/ocs/config.php | 36 + lib/private/ocs/person.php | 42 + lib/private/ocs/privatedata.php | 66 ++ lib/private/ocs/result.php | 97 ++ lib/private/ocsclient.php | 208 ++++ lib/private/preferences.php | 232 +++++ lib/private/preview.php | 630 ++++++++++++ lib/private/preview/image.php | 36 + lib/private/preview/movies.php | 47 + lib/private/preview/mp3.php | 48 + lib/private/preview/office-cl.php | 134 +++ lib/private/preview/office-fallback.php | 142 +++ lib/private/preview/office.php | 22 + lib/private/preview/pdf.php | 40 + lib/private/preview/provider.php | 19 + lib/private/preview/svg.php | 46 + lib/private/preview/txt.php | 83 ++ lib/private/preview/unknown.php | 27 + lib/private/previewmanager.php | 38 + lib/private/request.php | 184 ++++ lib/private/response.php | 167 +++ lib/private/route.php | 116 +++ lib/private/router.php | 183 ++++ lib/private/search.php | 90 ++ lib/private/search/provider.php | 18 + lib/private/search/provider/file.php | 46 + lib/private/search/result.php | 26 + lib/private/server.php | 255 +++++ lib/private/session/internal.php | 39 + lib/private/session/memory.php | 63 ++ lib/private/session/session.php | 79 ++ lib/private/setup.php | 192 ++++ lib/private/setup/abstractdatabase.php | 50 + lib/private/setup/mssql.php | 182 ++++ lib/private/setup/mysql.php | 95 ++ lib/private/setup/oci.php | 210 ++++ lib/private/setup/postgresql.php | 140 +++ lib/private/setup/sqlite.php | 26 + lib/private/subadmin.php | 189 ++++ lib/private/template.php | 311 ++++++ lib/private/template/base.php | 134 +++ lib/private/template/cssresourcelocator.php | 43 + lib/private/template/functions.php | 134 +++ lib/private/template/jsresourcelocator.php | 43 + lib/private/template/resourcelocator.php | 70 ++ lib/private/template/templatefilelocator.php | 44 + lib/private/templatelayout.php | 114 +++ lib/private/updater.php | 159 +++ lib/private/user.php | 500 +++++++++ lib/private/user/backend.php | 159 +++ lib/private/user/database.php | 269 +++++ lib/private/user/dummy.php | 126 +++ lib/private/user/example.php | 70 ++ lib/private/user/http.php | 110 ++ lib/private/user/interface.php | 80 ++ lib/private/user/manager.php | 250 +++++ lib/private/user/session.php | 174 ++++ lib/private/user/user.php | 179 ++++ lib/private/util.php | 1019 ++++++++++++++++++ lib/private/vobject.php | 207 ++++ lib/private/vobject/compoundproperty.php | 70 ++ lib/private/vobject/stringproperty.php | 80 ++ lib/request.php | 184 ---- lib/response.php | 167 --- lib/route.php | 116 --- lib/router.php | 183 ---- lib/search.php | 90 -- lib/search/provider.php | 18 - lib/search/provider/file.php | 46 - lib/search/result.php | 26 - lib/server.php | 255 ----- lib/session/internal.php | 39 - lib/session/memory.php | 63 -- lib/session/session.php | 79 -- lib/setup.php | 192 ---- lib/setup/abstractdatabase.php | 50 - lib/setup/mssql.php | 182 ---- lib/setup/mysql.php | 95 -- lib/setup/oci.php | 210 ---- lib/setup/postgresql.php | 140 --- lib/setup/sqlite.php | 26 - lib/subadmin.php | 189 ---- lib/template.php | 311 ------ lib/template/base.php | 134 --- lib/template/cssresourcelocator.php | 43 - lib/template/functions.php | 134 --- lib/template/jsresourcelocator.php | 43 - lib/template/resourcelocator.php | 70 -- lib/template/templatefilelocator.php | 44 - lib/templatelayout.php | 114 --- lib/updater.php | 159 --- lib/user.php | 500 --------- lib/user/backend.php | 159 --- lib/user/database.php | 269 ----- lib/user/dummy.php | 126 --- lib/user/example.php | 70 -- lib/user/http.php | 110 -- lib/user/interface.php | 80 -- lib/user/manager.php | 250 ----- lib/user/session.php | 174 ---- lib/user/user.php | 179 ---- lib/util.php | 1019 ------------------ lib/vobject.php | 207 ---- lib/vobject/compoundproperty.php | 70 -- lib/vobject/stringproperty.php | 80 -- tests/lib/autoloader.php | 10 +- 617 files changed, 38576 insertions(+), 38576 deletions(-) delete mode 100644 lib/allconfig.php delete mode 100644 lib/api.php delete mode 100644 lib/app.php delete mode 100644 lib/appconfig.php delete mode 100644 lib/appframework/app.php delete mode 100644 lib/appframework/controller/controller.php delete mode 100644 lib/appframework/core/api.php delete mode 100644 lib/appframework/dependencyinjection/dicontainer.php delete mode 100644 lib/appframework/http/dispatcher.php delete mode 100644 lib/appframework/http/downloadresponse.php delete mode 100644 lib/appframework/http/http.php delete mode 100644 lib/appframework/http/redirectresponse.php delete mode 100644 lib/appframework/http/request.php delete mode 100644 lib/appframework/middleware/middleware.php delete mode 100644 lib/appframework/middleware/middlewaredispatcher.php delete mode 100644 lib/appframework/middleware/security/securityexception.php delete mode 100644 lib/appframework/middleware/security/securitymiddleware.php delete mode 100644 lib/appframework/routing/routeactionhandler.php delete mode 100644 lib/appframework/routing/routeconfig.php delete mode 100644 lib/appframework/utility/methodannotationreader.php delete mode 100644 lib/appframework/utility/simplecontainer.php delete mode 100644 lib/appframework/utility/timefactory.php delete mode 100644 lib/archive.php delete mode 100644 lib/archive/tar.php delete mode 100644 lib/archive/zip.php delete mode 100644 lib/arrayparser.php delete mode 100644 lib/avatar.php delete mode 100644 lib/backgroundjob.php delete mode 100644 lib/backgroundjob/job.php delete mode 100644 lib/backgroundjob/joblist.php delete mode 100644 lib/backgroundjob/legacy/queuedjob.php delete mode 100644 lib/backgroundjob/legacy/regularjob.php delete mode 100644 lib/backgroundjob/queuedjob.php delete mode 100644 lib/backgroundjob/timedjob.php delete mode 100644 lib/cache.php delete mode 100644 lib/cache/broker.php delete mode 100644 lib/cache/file.php delete mode 100644 lib/cache/fileglobal.php delete mode 100644 lib/cache/fileglobalgc.php delete mode 100644 lib/cache/usercache.php delete mode 100644 lib/config.php delete mode 100644 lib/connector/sabre/ServiceUnavailable.php delete mode 100644 lib/connector/sabre/auth.php delete mode 100644 lib/connector/sabre/directory.php delete mode 100644 lib/connector/sabre/file.php delete mode 100644 lib/connector/sabre/locks.php delete mode 100644 lib/connector/sabre/maintenanceplugin.php delete mode 100644 lib/connector/sabre/node.php delete mode 100644 lib/connector/sabre/objecttree.php delete mode 100644 lib/connector/sabre/principal.php delete mode 100644 lib/connector/sabre/quotaplugin.php delete mode 100644 lib/connector/sabre/request.php delete mode 100644 lib/contactsmanager.php delete mode 100644 lib/db.php delete mode 100644 lib/db/adapter.php delete mode 100644 lib/db/adapteroci8.php delete mode 100644 lib/db/adapterpgsql.php delete mode 100644 lib/db/adaptersqlite.php delete mode 100644 lib/db/adaptersqlsrv.php delete mode 100644 lib/db/connection.php delete mode 100644 lib/db/mdb2schemamanager.php delete mode 100644 lib/db/mdb2schemareader.php delete mode 100644 lib/db/mdb2schemawriter.php delete mode 100644 lib/db/oracleconnection.php delete mode 100644 lib/db/statementwrapper.php delete mode 100644 lib/defaults.php delete mode 100644 lib/eventsource.php delete mode 100644 lib/filechunking.php delete mode 100644 lib/fileproxy.php delete mode 100644 lib/fileproxy/fileoperations.php delete mode 100644 lib/files.php delete mode 100644 lib/files/cache/backgroundwatcher.php delete mode 100644 lib/files/cache/cache.php delete mode 100644 lib/files/cache/legacy.php delete mode 100644 lib/files/cache/permissions.php delete mode 100644 lib/files/cache/scanner.php delete mode 100644 lib/files/cache/storage.php delete mode 100644 lib/files/cache/updater.php delete mode 100644 lib/files/cache/upgrade.php delete mode 100644 lib/files/cache/watcher.php delete mode 100644 lib/files/filesystem.php delete mode 100644 lib/files/mapper.php delete mode 100644 lib/files/mount/manager.php delete mode 100644 lib/files/mount/mount.php delete mode 100644 lib/files/node/file.php delete mode 100644 lib/files/node/folder.php delete mode 100644 lib/files/node/node.php delete mode 100644 lib/files/node/nonexistingfile.php delete mode 100644 lib/files/node/nonexistingfolder.php delete mode 100644 lib/files/node/root.php delete mode 100644 lib/files/storage/common.php delete mode 100644 lib/files/storage/commontest.php delete mode 100644 lib/files/storage/loader.php delete mode 100644 lib/files/storage/local.php delete mode 100644 lib/files/storage/mappedlocal.php delete mode 100644 lib/files/storage/storage.php delete mode 100644 lib/files/storage/temporary.php delete mode 100644 lib/files/storage/wrapper/quota.php delete mode 100644 lib/files/storage/wrapper/wrapper.php delete mode 100644 lib/files/stream/close.php delete mode 100644 lib/files/stream/dir.php delete mode 100644 lib/files/stream/oc.php delete mode 100644 lib/files/stream/quota.php delete mode 100644 lib/files/stream/staticstream.php delete mode 100644 lib/files/type/detection.php delete mode 100644 lib/files/type/templatemanager.php delete mode 100644 lib/files/utils/scanner.php delete mode 100644 lib/files/view.php delete mode 100644 lib/geo.php delete mode 100644 lib/group.php delete mode 100644 lib/group/backend.php delete mode 100644 lib/group/database.php delete mode 100644 lib/group/dummy.php delete mode 100644 lib/group/example.php delete mode 100644 lib/group/group.php delete mode 100644 lib/group/interface.php delete mode 100644 lib/group/manager.php delete mode 100644 lib/helper.php delete mode 100644 lib/hintexception.php delete mode 100644 lib/hook.php delete mode 100644 lib/hooks/basicemitter.php delete mode 100644 lib/hooks/emitter.php delete mode 100644 lib/hooks/forwardingemitter.php delete mode 100644 lib/hooks/legacyemitter.php delete mode 100644 lib/hooks/publicemitter.php delete mode 100644 lib/image.php delete mode 100644 lib/installer.php delete mode 100644 lib/json.php delete mode 100644 lib/l10n.php delete mode 100644 lib/l10n/ach.php delete mode 100644 lib/l10n/af_ZA.php delete mode 100644 lib/l10n/ar.php delete mode 100644 lib/l10n/be.php delete mode 100644 lib/l10n/bg_BG.php delete mode 100644 lib/l10n/bn_BD.php delete mode 100644 lib/l10n/bs.php delete mode 100644 lib/l10n/ca.php delete mode 100644 lib/l10n/cs_CZ.php delete mode 100644 lib/l10n/cy_GB.php delete mode 100644 lib/l10n/da.php delete mode 100644 lib/l10n/de.php delete mode 100644 lib/l10n/de_AT.php delete mode 100644 lib/l10n/de_CH.php delete mode 100644 lib/l10n/de_DE.php delete mode 100644 lib/l10n/el.php delete mode 100644 lib/l10n/en@pirate.php delete mode 100644 lib/l10n/en_GB.php delete mode 100644 lib/l10n/eo.php delete mode 100644 lib/l10n/es.php delete mode 100644 lib/l10n/es_AR.php delete mode 100644 lib/l10n/es_MX.php delete mode 100644 lib/l10n/et_EE.php delete mode 100644 lib/l10n/eu.php delete mode 100644 lib/l10n/fa.php delete mode 100644 lib/l10n/fi.php delete mode 100644 lib/l10n/fi_FI.php delete mode 100644 lib/l10n/fr.php delete mode 100644 lib/l10n/gl.php delete mode 100644 lib/l10n/he.php delete mode 100644 lib/l10n/hi.php delete mode 100644 lib/l10n/hr.php delete mode 100644 lib/l10n/hu_HU.php delete mode 100644 lib/l10n/hy.php delete mode 100644 lib/l10n/ia.php delete mode 100644 lib/l10n/id.php delete mode 100644 lib/l10n/is.php delete mode 100644 lib/l10n/it.php delete mode 100644 lib/l10n/ja_JP.php delete mode 100644 lib/l10n/ka.php delete mode 100644 lib/l10n/ka_GE.php delete mode 100644 lib/l10n/km.php delete mode 100644 lib/l10n/kn.php delete mode 100644 lib/l10n/ko.php delete mode 100644 lib/l10n/ku_IQ.php delete mode 100644 lib/l10n/lb.php delete mode 100644 lib/l10n/lt_LT.php delete mode 100644 lib/l10n/lv.php delete mode 100644 lib/l10n/mk.php delete mode 100644 lib/l10n/ml_IN.php delete mode 100644 lib/l10n/ms_MY.php delete mode 100644 lib/l10n/my_MM.php delete mode 100644 lib/l10n/nb_NO.php delete mode 100644 lib/l10n/ne.php delete mode 100644 lib/l10n/nl.php delete mode 100644 lib/l10n/nn_NO.php delete mode 100644 lib/l10n/nqo.php delete mode 100644 lib/l10n/oc.php delete mode 100644 lib/l10n/pa.php delete mode 100644 lib/l10n/pl.php delete mode 100644 lib/l10n/pl_PL.php delete mode 100644 lib/l10n/pt_BR.php delete mode 100644 lib/l10n/pt_PT.php delete mode 100644 lib/l10n/ro.php delete mode 100644 lib/l10n/ru.php delete mode 100644 lib/l10n/si_LK.php delete mode 100644 lib/l10n/sk.php delete mode 100644 lib/l10n/sk_SK.php delete mode 100644 lib/l10n/sl.php delete mode 100644 lib/l10n/sq.php delete mode 100644 lib/l10n/sr.php delete mode 100644 lib/l10n/sr@latin.php delete mode 100644 lib/l10n/string.php delete mode 100644 lib/l10n/sv.php delete mode 100644 lib/l10n/sw_KE.php delete mode 100644 lib/l10n/ta_LK.php delete mode 100644 lib/l10n/te.php delete mode 100644 lib/l10n/th_TH.php delete mode 100644 lib/l10n/tr.php delete mode 100644 lib/l10n/ug.php delete mode 100644 lib/l10n/uk.php delete mode 100644 lib/l10n/ur_PK.php delete mode 100644 lib/l10n/vi.php delete mode 100644 lib/l10n/zh_CN.php delete mode 100644 lib/l10n/zh_HK.php delete mode 100644 lib/l10n/zh_TW.php delete mode 100644 lib/legacy/cache.php delete mode 100644 lib/legacy/config.php delete mode 100644 lib/legacy/filesystem.php delete mode 100644 lib/legacy/filesystemview.php delete mode 100644 lib/legacy/log.php delete mode 100644 lib/legacy/preferences.php delete mode 100644 lib/legacy/updater.php delete mode 100644 lib/log.php delete mode 100644 lib/log/errorhandler.php delete mode 100644 lib/log/owncloud.php delete mode 100644 lib/log/rotate.php delete mode 100644 lib/log/syslog.php delete mode 100644 lib/mail.php delete mode 100644 lib/memcache/apc.php delete mode 100644 lib/memcache/apcu.php delete mode 100644 lib/memcache/cache.php delete mode 100644 lib/memcache/factory.php delete mode 100644 lib/memcache/memcached.php delete mode 100644 lib/memcache/xcache.php delete mode 100644 lib/migrate.php delete mode 100644 lib/migration/content.php delete mode 100644 lib/migration/provider.php delete mode 100644 lib/mimetypes.list.php delete mode 100644 lib/minimizer.php delete mode 100644 lib/minimizer/css.php delete mode 100644 lib/minimizer/js.php delete mode 100644 lib/navigationmanager.php delete mode 100644 lib/notsquareexception.php delete mode 100644 lib/ocs.php delete mode 100644 lib/ocs/cloud.php delete mode 100644 lib/ocs/config.php delete mode 100644 lib/ocs/person.php delete mode 100644 lib/ocs/privatedata.php delete mode 100644 lib/ocs/result.php delete mode 100644 lib/ocsclient.php delete mode 100644 lib/preferences.php delete mode 100755 lib/preview.php delete mode 100644 lib/preview/image.php delete mode 100644 lib/preview/movies.php delete mode 100644 lib/preview/mp3.php delete mode 100644 lib/preview/office-cl.php delete mode 100644 lib/preview/office-fallback.php delete mode 100644 lib/preview/office.php delete mode 100644 lib/preview/pdf.php delete mode 100644 lib/preview/provider.php delete mode 100644 lib/preview/svg.php delete mode 100644 lib/preview/txt.php delete mode 100644 lib/preview/unknown.php delete mode 100755 lib/previewmanager.php create mode 100644 lib/private/allconfig.php create mode 100644 lib/private/api.php create mode 100644 lib/private/app.php create mode 100644 lib/private/appconfig.php create mode 100644 lib/private/appframework/app.php create mode 100644 lib/private/appframework/controller/controller.php create mode 100644 lib/private/appframework/core/api.php create mode 100644 lib/private/appframework/dependencyinjection/dicontainer.php create mode 100644 lib/private/appframework/http/dispatcher.php create mode 100644 lib/private/appframework/http/downloadresponse.php create mode 100644 lib/private/appframework/http/http.php create mode 100644 lib/private/appframework/http/redirectresponse.php create mode 100644 lib/private/appframework/http/request.php create mode 100644 lib/private/appframework/middleware/middleware.php create mode 100644 lib/private/appframework/middleware/middlewaredispatcher.php create mode 100644 lib/private/appframework/middleware/security/securityexception.php create mode 100644 lib/private/appframework/middleware/security/securitymiddleware.php create mode 100644 lib/private/appframework/routing/routeactionhandler.php create mode 100644 lib/private/appframework/routing/routeconfig.php create mode 100644 lib/private/appframework/utility/methodannotationreader.php create mode 100644 lib/private/appframework/utility/simplecontainer.php create mode 100644 lib/private/appframework/utility/timefactory.php create mode 100644 lib/private/archive.php create mode 100644 lib/private/archive/tar.php create mode 100644 lib/private/archive/zip.php create mode 100644 lib/private/arrayparser.php create mode 100644 lib/private/avatar.php create mode 100644 lib/private/backgroundjob.php create mode 100644 lib/private/backgroundjob/job.php create mode 100644 lib/private/backgroundjob/joblist.php create mode 100644 lib/private/backgroundjob/legacy/queuedjob.php create mode 100644 lib/private/backgroundjob/legacy/regularjob.php create mode 100644 lib/private/backgroundjob/queuedjob.php create mode 100644 lib/private/backgroundjob/timedjob.php create mode 100644 lib/private/cache.php create mode 100644 lib/private/cache/broker.php create mode 100644 lib/private/cache/file.php create mode 100644 lib/private/cache/fileglobal.php create mode 100644 lib/private/cache/fileglobalgc.php create mode 100644 lib/private/cache/usercache.php create mode 100644 lib/private/config.php create mode 100644 lib/private/connector/sabre/ServiceUnavailable.php create mode 100644 lib/private/connector/sabre/auth.php create mode 100644 lib/private/connector/sabre/directory.php create mode 100644 lib/private/connector/sabre/file.php create mode 100644 lib/private/connector/sabre/locks.php create mode 100644 lib/private/connector/sabre/maintenanceplugin.php create mode 100644 lib/private/connector/sabre/node.php create mode 100644 lib/private/connector/sabre/objecttree.php create mode 100644 lib/private/connector/sabre/principal.php create mode 100644 lib/private/connector/sabre/quotaplugin.php create mode 100644 lib/private/connector/sabre/request.php create mode 100644 lib/private/contactsmanager.php create mode 100644 lib/private/db.php create mode 100644 lib/private/db/adapter.php create mode 100644 lib/private/db/adapteroci8.php create mode 100644 lib/private/db/adapterpgsql.php create mode 100644 lib/private/db/adaptersqlite.php create mode 100644 lib/private/db/adaptersqlsrv.php create mode 100644 lib/private/db/connection.php create mode 100644 lib/private/db/mdb2schemamanager.php create mode 100644 lib/private/db/mdb2schemareader.php create mode 100644 lib/private/db/mdb2schemawriter.php create mode 100644 lib/private/db/oracleconnection.php create mode 100644 lib/private/db/statementwrapper.php create mode 100644 lib/private/defaults.php create mode 100644 lib/private/eventsource.php create mode 100644 lib/private/filechunking.php create mode 100644 lib/private/fileproxy.php create mode 100644 lib/private/fileproxy/fileoperations.php create mode 100644 lib/private/files.php create mode 100644 lib/private/files/cache/backgroundwatcher.php create mode 100644 lib/private/files/cache/cache.php create mode 100644 lib/private/files/cache/legacy.php create mode 100644 lib/private/files/cache/permissions.php create mode 100644 lib/private/files/cache/scanner.php create mode 100644 lib/private/files/cache/storage.php create mode 100644 lib/private/files/cache/updater.php create mode 100644 lib/private/files/cache/upgrade.php create mode 100644 lib/private/files/cache/watcher.php create mode 100644 lib/private/files/filesystem.php create mode 100644 lib/private/files/mapper.php create mode 100644 lib/private/files/mount/manager.php create mode 100644 lib/private/files/mount/mount.php create mode 100644 lib/private/files/node/file.php create mode 100644 lib/private/files/node/folder.php create mode 100644 lib/private/files/node/node.php create mode 100644 lib/private/files/node/nonexistingfile.php create mode 100644 lib/private/files/node/nonexistingfolder.php create mode 100644 lib/private/files/node/root.php create mode 100644 lib/private/files/storage/common.php create mode 100644 lib/private/files/storage/commontest.php create mode 100644 lib/private/files/storage/loader.php create mode 100644 lib/private/files/storage/local.php create mode 100644 lib/private/files/storage/mappedlocal.php create mode 100644 lib/private/files/storage/storage.php create mode 100644 lib/private/files/storage/temporary.php create mode 100644 lib/private/files/storage/wrapper/quota.php create mode 100644 lib/private/files/storage/wrapper/wrapper.php create mode 100644 lib/private/files/stream/close.php create mode 100644 lib/private/files/stream/dir.php create mode 100644 lib/private/files/stream/oc.php create mode 100644 lib/private/files/stream/quota.php create mode 100644 lib/private/files/stream/staticstream.php create mode 100644 lib/private/files/type/detection.php create mode 100644 lib/private/files/type/templatemanager.php create mode 100644 lib/private/files/utils/scanner.php create mode 100644 lib/private/files/view.php create mode 100644 lib/private/geo.php create mode 100644 lib/private/group.php create mode 100644 lib/private/group/backend.php create mode 100644 lib/private/group/database.php create mode 100644 lib/private/group/dummy.php create mode 100644 lib/private/group/example.php create mode 100644 lib/private/group/group.php create mode 100644 lib/private/group/interface.php create mode 100644 lib/private/group/manager.php create mode 100644 lib/private/helper.php create mode 100644 lib/private/hintexception.php create mode 100644 lib/private/hook.php create mode 100644 lib/private/hooks/basicemitter.php create mode 100644 lib/private/hooks/emitter.php create mode 100644 lib/private/hooks/forwardingemitter.php create mode 100644 lib/private/hooks/legacyemitter.php create mode 100644 lib/private/hooks/publicemitter.php create mode 100644 lib/private/image.php create mode 100644 lib/private/installer.php create mode 100644 lib/private/json.php create mode 100644 lib/private/l10n.php create mode 100644 lib/private/l10n/ach.php create mode 100644 lib/private/l10n/af_ZA.php create mode 100644 lib/private/l10n/ar.php create mode 100644 lib/private/l10n/be.php create mode 100644 lib/private/l10n/bg_BG.php create mode 100644 lib/private/l10n/bn_BD.php create mode 100644 lib/private/l10n/bs.php create mode 100644 lib/private/l10n/ca.php create mode 100644 lib/private/l10n/cs_CZ.php create mode 100644 lib/private/l10n/cy_GB.php create mode 100644 lib/private/l10n/da.php create mode 100644 lib/private/l10n/de.php create mode 100644 lib/private/l10n/de_AT.php create mode 100644 lib/private/l10n/de_CH.php create mode 100644 lib/private/l10n/de_DE.php create mode 100644 lib/private/l10n/el.php create mode 100644 lib/private/l10n/en@pirate.php create mode 100644 lib/private/l10n/en_GB.php create mode 100644 lib/private/l10n/eo.php create mode 100644 lib/private/l10n/es.php create mode 100644 lib/private/l10n/es_AR.php create mode 100644 lib/private/l10n/es_MX.php create mode 100644 lib/private/l10n/et_EE.php create mode 100644 lib/private/l10n/eu.php create mode 100644 lib/private/l10n/fa.php create mode 100644 lib/private/l10n/fi.php create mode 100644 lib/private/l10n/fi_FI.php create mode 100644 lib/private/l10n/fr.php create mode 100644 lib/private/l10n/gl.php create mode 100644 lib/private/l10n/he.php create mode 100644 lib/private/l10n/hi.php create mode 100644 lib/private/l10n/hr.php create mode 100644 lib/private/l10n/hu_HU.php create mode 100644 lib/private/l10n/hy.php create mode 100644 lib/private/l10n/ia.php create mode 100644 lib/private/l10n/id.php create mode 100644 lib/private/l10n/is.php create mode 100644 lib/private/l10n/it.php create mode 100644 lib/private/l10n/ja_JP.php create mode 100644 lib/private/l10n/ka.php create mode 100644 lib/private/l10n/ka_GE.php create mode 100644 lib/private/l10n/km.php create mode 100644 lib/private/l10n/kn.php create mode 100644 lib/private/l10n/ko.php create mode 100644 lib/private/l10n/ku_IQ.php create mode 100644 lib/private/l10n/lb.php create mode 100644 lib/private/l10n/lt_LT.php create mode 100644 lib/private/l10n/lv.php create mode 100644 lib/private/l10n/mk.php create mode 100644 lib/private/l10n/ml_IN.php create mode 100644 lib/private/l10n/ms_MY.php create mode 100644 lib/private/l10n/my_MM.php create mode 100644 lib/private/l10n/nb_NO.php create mode 100644 lib/private/l10n/ne.php create mode 100644 lib/private/l10n/nl.php create mode 100644 lib/private/l10n/nn_NO.php create mode 100644 lib/private/l10n/nqo.php create mode 100644 lib/private/l10n/oc.php create mode 100644 lib/private/l10n/pa.php create mode 100644 lib/private/l10n/pl.php create mode 100644 lib/private/l10n/pl_PL.php create mode 100644 lib/private/l10n/pt_BR.php create mode 100644 lib/private/l10n/pt_PT.php create mode 100644 lib/private/l10n/ro.php create mode 100644 lib/private/l10n/ru.php create mode 100644 lib/private/l10n/si_LK.php create mode 100644 lib/private/l10n/sk.php create mode 100644 lib/private/l10n/sk_SK.php create mode 100644 lib/private/l10n/sl.php create mode 100644 lib/private/l10n/sq.php create mode 100644 lib/private/l10n/sr.php create mode 100644 lib/private/l10n/sr@latin.php create mode 100644 lib/private/l10n/string.php create mode 100644 lib/private/l10n/sv.php create mode 100644 lib/private/l10n/sw_KE.php create mode 100644 lib/private/l10n/ta_LK.php create mode 100644 lib/private/l10n/te.php create mode 100644 lib/private/l10n/th_TH.php create mode 100644 lib/private/l10n/tr.php create mode 100644 lib/private/l10n/ug.php create mode 100644 lib/private/l10n/uk.php create mode 100644 lib/private/l10n/ur_PK.php create mode 100644 lib/private/l10n/vi.php create mode 100644 lib/private/l10n/zh_CN.php create mode 100644 lib/private/l10n/zh_HK.php create mode 100644 lib/private/l10n/zh_TW.php create mode 100644 lib/private/legacy/cache.php create mode 100644 lib/private/legacy/config.php create mode 100644 lib/private/legacy/filesystem.php create mode 100644 lib/private/legacy/filesystemview.php create mode 100644 lib/private/legacy/log.php create mode 100644 lib/private/legacy/preferences.php create mode 100644 lib/private/legacy/updater.php create mode 100644 lib/private/log.php create mode 100644 lib/private/log/errorhandler.php create mode 100644 lib/private/log/owncloud.php create mode 100644 lib/private/log/rotate.php create mode 100644 lib/private/log/syslog.php create mode 100644 lib/private/mail.php create mode 100644 lib/private/memcache/apc.php create mode 100644 lib/private/memcache/apcu.php create mode 100644 lib/private/memcache/cache.php create mode 100644 lib/private/memcache/factory.php create mode 100644 lib/private/memcache/memcached.php create mode 100644 lib/private/memcache/xcache.php create mode 100644 lib/private/migrate.php create mode 100644 lib/private/migration/content.php create mode 100644 lib/private/migration/provider.php create mode 100644 lib/private/mimetypes.list.php create mode 100644 lib/private/minimizer.php create mode 100644 lib/private/minimizer/css.php create mode 100644 lib/private/minimizer/js.php create mode 100644 lib/private/navigationmanager.php create mode 100644 lib/private/notsquareexception.php create mode 100644 lib/private/ocs.php create mode 100644 lib/private/ocs/cloud.php create mode 100644 lib/private/ocs/config.php create mode 100644 lib/private/ocs/person.php create mode 100644 lib/private/ocs/privatedata.php create mode 100644 lib/private/ocs/result.php create mode 100644 lib/private/ocsclient.php create mode 100644 lib/private/preferences.php create mode 100755 lib/private/preview.php create mode 100644 lib/private/preview/image.php create mode 100644 lib/private/preview/movies.php create mode 100644 lib/private/preview/mp3.php create mode 100644 lib/private/preview/office-cl.php create mode 100644 lib/private/preview/office-fallback.php create mode 100644 lib/private/preview/office.php create mode 100644 lib/private/preview/pdf.php create mode 100644 lib/private/preview/provider.php create mode 100644 lib/private/preview/svg.php create mode 100644 lib/private/preview/txt.php create mode 100644 lib/private/preview/unknown.php create mode 100755 lib/private/previewmanager.php create mode 100755 lib/private/request.php create mode 100644 lib/private/response.php create mode 100644 lib/private/route.php create mode 100644 lib/private/router.php create mode 100644 lib/private/search.php create mode 100644 lib/private/search/provider.php create mode 100644 lib/private/search/provider/file.php create mode 100644 lib/private/search/result.php create mode 100644 lib/private/server.php create mode 100644 lib/private/session/internal.php create mode 100644 lib/private/session/memory.php create mode 100644 lib/private/session/session.php create mode 100644 lib/private/setup.php create mode 100644 lib/private/setup/abstractdatabase.php create mode 100644 lib/private/setup/mssql.php create mode 100644 lib/private/setup/mysql.php create mode 100644 lib/private/setup/oci.php create mode 100644 lib/private/setup/postgresql.php create mode 100644 lib/private/setup/sqlite.php create mode 100644 lib/private/subadmin.php create mode 100644 lib/private/template.php create mode 100644 lib/private/template/base.php create mode 100644 lib/private/template/cssresourcelocator.php create mode 100644 lib/private/template/functions.php create mode 100644 lib/private/template/jsresourcelocator.php create mode 100644 lib/private/template/resourcelocator.php create mode 100644 lib/private/template/templatefilelocator.php create mode 100644 lib/private/templatelayout.php create mode 100644 lib/private/updater.php create mode 100644 lib/private/user.php create mode 100644 lib/private/user/backend.php create mode 100644 lib/private/user/database.php create mode 100644 lib/private/user/dummy.php create mode 100644 lib/private/user/example.php create mode 100644 lib/private/user/http.php create mode 100644 lib/private/user/interface.php create mode 100644 lib/private/user/manager.php create mode 100644 lib/private/user/session.php create mode 100644 lib/private/user/user.php create mode 100755 lib/private/util.php create mode 100644 lib/private/vobject.php create mode 100644 lib/private/vobject/compoundproperty.php create mode 100644 lib/private/vobject/stringproperty.php delete mode 100755 lib/request.php delete mode 100644 lib/response.php delete mode 100644 lib/route.php delete mode 100644 lib/router.php delete mode 100644 lib/search.php delete mode 100644 lib/search/provider.php delete mode 100644 lib/search/provider/file.php delete mode 100644 lib/search/result.php delete mode 100644 lib/server.php delete mode 100644 lib/session/internal.php delete mode 100644 lib/session/memory.php delete mode 100644 lib/session/session.php delete mode 100644 lib/setup.php delete mode 100644 lib/setup/abstractdatabase.php delete mode 100644 lib/setup/mssql.php delete mode 100644 lib/setup/mysql.php delete mode 100644 lib/setup/oci.php delete mode 100644 lib/setup/postgresql.php delete mode 100644 lib/setup/sqlite.php delete mode 100644 lib/subadmin.php delete mode 100644 lib/template.php delete mode 100644 lib/template/base.php delete mode 100644 lib/template/cssresourcelocator.php delete mode 100644 lib/template/functions.php delete mode 100644 lib/template/jsresourcelocator.php delete mode 100644 lib/template/resourcelocator.php delete mode 100644 lib/template/templatefilelocator.php delete mode 100644 lib/templatelayout.php delete mode 100644 lib/updater.php delete mode 100644 lib/user.php delete mode 100644 lib/user/backend.php delete mode 100644 lib/user/database.php delete mode 100644 lib/user/dummy.php delete mode 100644 lib/user/example.php delete mode 100644 lib/user/http.php delete mode 100644 lib/user/interface.php delete mode 100644 lib/user/manager.php delete mode 100644 lib/user/session.php delete mode 100644 lib/user/user.php delete mode 100755 lib/util.php delete mode 100644 lib/vobject.php delete mode 100644 lib/vobject/compoundproperty.php delete mode 100644 lib/vobject/stringproperty.php diff --git a/lib/allconfig.php b/lib/allconfig.php deleted file mode 100644 index 72aabf60793..00000000000 --- a/lib/allconfig.php +++ /dev/null @@ -1,77 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - * - */ - -namespace OC; - -/** - * Class to combine all the configuration options ownCloud offers - */ -class AllConfig implements \OCP\IConfig { - /** - * Sets a new system wide value - * @param string $key the key of the value, under which will be saved - * @param string $value the value that should be stored - * @todo need a use case for this - */ -// public function setSystemValue($key, $value) { -// \OCP\Config::setSystemValue($key, $value); -// } - - /** - * Looks up a system wide defined value - * @param string $key the key of the value, under which it was saved - * @return string the saved value - */ - public function getSystemValue($key) { - return \OCP\Config::getSystemValue($key, ''); - } - - - /** - * Writes a new app wide value - * @param string $appName the appName that we want to store the value under - * @param string $key the key of the value, under which will be saved - * @param string $value the value that should be stored - */ - public function setAppValue($appName, $key, $value) { - \OCP\Config::setAppValue($appName, $key, $value); - } - - /** - * Looks up an app wide defined value - * @param string $appName the appName that we stored the value under - * @param string $key the key of the value, under which it was saved - * @return string the saved value - */ - public function getAppValue($appName, $key) { - return \OCP\Config::getAppValue($appName, $key, ''); - } - - - /** - * Set a user defined value - * @param string $userId the userId of the user that we want to store the value under - * @param string $appName the appName that we want to store the value under - * @param string $key the key under which the value is being stored - * @param string $value the value that you want to store - */ - public function setUserValue($userId, $appName, $key, $value) { - \OCP\Config::setUserValue($userId, $appName, $key, $value); - } - - /** - * Shortcut for getting a user defined value - * @param string $userId the userId of the user that we want to store the value under - * @param string $appName the appName that we stored the value under - * @param string $key the key under which the value is being stored - */ - public function getUserValue($userId, $appName, $key){ - return \OCP\Config::getUserValue($userId, $appName, $key); - } -} diff --git a/lib/api.php b/lib/api.php deleted file mode 100644 index 31f3f968d9b..00000000000 --- a/lib/api.php +++ /dev/null @@ -1,293 +0,0 @@ -. -* -*/ - -class OC_API { - - /** - * API authentication levels - */ - const GUEST_AUTH = 0; - const USER_AUTH = 1; - const SUBADMIN_AUTH = 2; - const ADMIN_AUTH = 3; - - /** - * API Response Codes - */ - const RESPOND_UNAUTHORISED = 997; - const RESPOND_SERVER_ERROR = 996; - const RESPOND_NOT_FOUND = 998; - const RESPOND_UNKNOWN_ERROR = 999; - - /** - * api actions - */ - protected static $actions = array(); - - /** - * registers an api call - * @param string $method the http method - * @param string $url the url to match - * @param callable $action the function to run - * @param string $app the id of the app registering the call - * @param int $authLevel the level of authentication required for the call - * @param array $defaults - * @param array $requirements - */ - public static function register($method, $url, $action, $app, - $authLevel = OC_API::USER_AUTH, - $defaults = array(), - $requirements = array()) { - $name = strtolower($method).$url; - $name = str_replace(array('/', '{', '}'), '_', $name); - if(!isset(self::$actions[$name])) { - OC::getRouter()->useCollection('ocs'); - OC::getRouter()->create($name, $url) - ->method($method) - ->defaults($defaults) - ->requirements($requirements) - ->action('OC_API', 'call'); - self::$actions[$name] = array(); - } - self::$actions[$name][] = array('app' => $app, 'action' => $action, 'authlevel' => $authLevel); - } - - /** - * handles an api call - * @param array $parameters - */ - public static function call($parameters) { - // Prepare the request variables - if($_SERVER['REQUEST_METHOD'] == 'PUT') { - parse_str(file_get_contents("php://input"), $parameters['_put']); - } else if($_SERVER['REQUEST_METHOD'] == 'DELETE') { - parse_str(file_get_contents("php://input"), $parameters['_delete']); - } - $name = $parameters['_route']; - // Foreach registered action - $responses = array(); - foreach(self::$actions[$name] as $action) { - // Check authentication and availability - if(!self::isAuthorised($action)) { - $responses[] = array( - 'app' => $action['app'], - 'response' => new OC_OCS_Result(null, OC_API::RESPOND_UNAUTHORISED, 'Unauthorised'), - ); - continue; - } - if(!is_callable($action['action'])) { - $responses[] = array( - 'app' => $action['app'], - 'response' => new OC_OCS_Result(null, OC_API::RESPOND_NOT_FOUND, 'Api method not found'), - ); - continue; - } - // Run the action - $responses[] = array( - 'app' => $action['app'], - 'response' => call_user_func($action['action'], $parameters), - ); - } - $response = self::mergeResponses($responses); - $formats = array('json', 'xml'); - - $format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml'; - OC_User::logout(); - - self::respond($response, $format); - } - - /** - * merge the returned result objects into one response - * @param array $responses - */ - private static function mergeResponses($responses) { - $response = array(); - // Sort into shipped and thirdparty - $shipped = array( - 'succeeded' => array(), - 'failed' => array(), - ); - $thirdparty = array( - 'succeeded' => array(), - 'failed' => array(), - ); - - foreach($responses as $response) { - if(OC_App::isShipped($response['app']) || ($response['app'] === 'core')) { - if($response['response']->succeeded()) { - $shipped['succeeded'][$response['app']] = $response['response']; - } else { - $shipped['failed'][$response['app']] = $response['response']; - } - } else { - if($response['response']->succeeded()) { - $thirdparty['succeeded'][$response['app']] = $response['response']; - } else { - $thirdparty['failed'][$response['app']] = $response['response']; - } - } - } - - // Remove any error responses if there is one shipped response that succeeded - if(!empty($shipped['succeeded'])) { - $responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']); - } else if(!empty($shipped['failed'])) { - // Which shipped response do we use if they all failed? - // They may have failed for different reasons (different status codes) - // Which reponse code should we return? - // Maybe any that are not OC_API::RESPOND_SERVER_ERROR - $response = reset($shipped['failed']); - return $response; - } elseif(!empty($thirdparty['failed'])) { - // Return the third party failure result - $response = reset($thirdparty['failed']); - return $response; - } else { - $responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']); - } - // Merge the successful responses - $meta = array(); - $data = array(); - - foreach($responses as $app => $response) { - if(OC_App::isShipped($app)) { - $data = array_merge_recursive($response->getData(), $data); - } else { - $data = array_merge_recursive($data, $response->getData()); - } - } - $result = new OC_OCS_Result($data, 100); - return $result; - } - - /** - * authenticate the api call - * @param array $action the action details as supplied to OC_API::register() - * @return bool - */ - private static function isAuthorised($action) { - $level = $action['authlevel']; - switch($level) { - case OC_API::GUEST_AUTH: - // Anyone can access - return true; - break; - case OC_API::USER_AUTH: - // User required - return self::loginUser(); - break; - case OC_API::SUBADMIN_AUTH: - // Check for subadmin - $user = self::loginUser(); - if(!$user) { - return false; - } else { - $subAdmin = OC_SubAdmin::isSubAdmin($user); - $admin = OC_User::isAdminUser($user); - if($subAdmin || $admin) { - return true; - } else { - return false; - } - } - break; - case OC_API::ADMIN_AUTH: - // Check for admin - $user = self::loginUser(); - if(!$user) { - return false; - } else { - return OC_User::isAdminUser($user); - } - break; - default: - // oops looks like invalid level supplied - return false; - break; - } - } - - /** - * http basic auth - * @return string|false (username, or false on failure) - */ - private static function loginUser(){ - $authUser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : ''; - $authPw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; - return OC_User::login($authUser, $authPw) ? $authUser : false; - } - - /** - * respond to a call - * @param OC_OCS_Result $result - * @param string $format the format xml|json - */ - private static function respond($result, $format='xml') { - // Send 401 headers if unauthorised - if($result->getStatusCode() === self::RESPOND_UNAUTHORISED) { - header('WWW-Authenticate: Basic realm="Authorisation Required"'); - header('HTTP/1.0 401 Unauthorized'); - } - $response = array( - 'ocs' => array( - 'meta' => $result->getMeta(), - 'data' => $result->getData(), - ), - ); - if ($format == 'json') { - OC_JSON::encodedPrint($response); - } else if ($format == 'xml') { - header('Content-type: text/xml; charset=UTF-8'); - $writer = new XMLWriter(); - $writer->openMemory(); - $writer->setIndent( true ); - $writer->startDocument(); - self::toXML($response, $writer); - $writer->endDocument(); - echo $writer->outputMemory(true); - } - } - - private static function toXML($array, $writer) { - foreach($array as $k => $v) { - if ($k[0] === '@') { - $writer->writeAttribute(substr($k, 1), $v); - continue; - } else if (is_numeric($k)) { - $k = 'element'; - } - if(is_array($v)) { - $writer->startElement($k); - self::toXML($v, $writer); - $writer->endElement(); - } else { - $writer->writeElement($k, $v); - } - } - } - -} diff --git a/lib/app.php b/lib/app.php deleted file mode 100644 index 0ab1ee57f63..00000000000 --- a/lib/app.php +++ /dev/null @@ -1,967 +0,0 @@ -. - * - */ - -/** - * This class manages the apps. It allows them to register and integrate in the - * owncloud ecosystem. Furthermore, this class is responsible for installing, - * upgrading and removing apps. - */ -class OC_App{ - static private $settingsForms = array(); - static private $adminForms = array(); - static private $personalForms = array(); - static private $appInfo = array(); - static private $appTypes = array(); - static private $loadedApps = array(); - static private $checkedApps = array(); - static private $altLogin = array(); - - /** - * @brief clean the appid - * @param $app Appid that needs to be cleaned - * @return string - */ - public static function cleanAppId($app) { - return str_replace(array('\0', '/', '\\', '..'), '', $app); - } - - /** - * @brief loads all apps - * @param array $types - * @return bool - * - * This function walks through the owncloud directory and loads all apps - * it can find. A directory contains an app if the file /appinfo/app.php - * exists. - * - * if $types is set, only apps of those types will be loaded - */ - public static function loadApps($types=null) { - // Load the enabled apps here - $apps = self::getEnabledApps(); - // prevent app.php from printing output - ob_start(); - foreach( $apps as $app ) { - if((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) { - self::loadApp($app); - self::$loadedApps[] = $app; - } - } - ob_end_clean(); - - if (!defined('DEBUG') || !DEBUG) { - if (is_null($types) - && empty(OC_Util::$coreScripts) - && empty(OC_Util::$coreStyles)) { - OC_Util::$coreScripts = OC_Util::$scripts; - OC_Util::$scripts = array(); - OC_Util::$coreStyles = OC_Util::$styles; - OC_Util::$styles = array(); - } - } - // return - return true; - } - - /** - * load a single app - * @param string $app - */ - public static function loadApp($app) { - if(is_file(self::getAppPath($app).'/appinfo/app.php')) { - self::checkUpgrade($app); - require_once $app.'/appinfo/app.php'; - } - } - - /** - * check if an app is of a specific type - * @param string $app - * @param string/array $types - * @return bool - */ - public static function isType($app, $types) { - if(is_string($types)) { - $types=array($types); - } - $appTypes=self::getAppTypes($app); - foreach($types as $type) { - if(array_search($type, $appTypes)!==false) { - return true; - } - } - return false; - } - - /** - * get the types of an app - * @param string $app - * @return array - */ - private static function getAppTypes($app) { - //load the cache - if(count(self::$appTypes)==0) { - self::$appTypes=OC_Appconfig::getValues(false, 'types'); - } - - if(isset(self::$appTypes[$app])) { - return explode(',', self::$appTypes[$app]); - }else{ - return array(); - } - } - - /** - * read app types from info.xml and cache them in the database - */ - public static function setAppTypes($app) { - $appData=self::getAppInfo($app); - - if(isset($appData['types'])) { - $appTypes=implode(',', $appData['types']); - }else{ - $appTypes=''; - } - - OC_Appconfig::setValue($app, 'types', $appTypes); - } - - /** - * check if app is shipped - * @param string $appid the id of the app to check - * @return bool - * - * Check if an app that is installed is a shipped app or installed from the appstore. - */ - public static function isShipped($appid){ - $info = self::getAppInfo($appid); - if(isset($info['shipped']) && $info['shipped']=='true') { - return true; - } else { - return false; - } - } - - /** - * get all enabled apps - */ - public static function getEnabledApps() { - if(!OC_Config::getValue('installed', false)) { - return array(); - } - $apps=array('files'); - $sql = 'SELECT `appid` FROM `*PREFIX*appconfig`' - .' WHERE `configkey` = \'enabled\' AND `configvalue`=\'yes\''; - if (OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') { - //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison - $sql = 'SELECT `appid` FROM `*PREFIX*appconfig`' - .' WHERE `configkey` = \'enabled\' AND to_char(`configvalue`)=\'yes\''; - } - $query = OC_DB::prepare( $sql ); - $result=$query->execute(); - if( \OC_DB::isError($result)) { - throw new DatabaseException($result->getMessage(), $query); - } - while($row=$result->fetchRow()) { - if(array_search($row['appid'], $apps)===false) { - $apps[]=$row['appid']; - } - } - return $apps; - } - - /** - * @brief checks whether or not an app is enabled - * @param string $app app - * @return bool - * - * This function checks whether or not an app is enabled. - */ - public static function isEnabled( $app ) { - if( 'files'==$app or ('yes' == OC_Appconfig::getValue( $app, 'enabled' ))) { - return true; - } - - return false; - } - - /** - * @brief enables an app - * @param mixed $app app - * @throws \Exception - * @return void - * - * This function set an app as enabled in appconfig. - */ - public static function enable( $app ) { - if(!OC_Installer::isInstalled($app)) { - // check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string - if(!is_numeric($app)) { - $app = OC_Installer::installShippedApp($app); - }else{ - $appdata=OC_OCSClient::getApplication($app); - $download=OC_OCSClient::getApplicationDownload($app, 1); - if(isset($download['downloadlink']) and $download['downloadlink']!='') { - $info = array('source'=>'http', 'href'=>$download['downloadlink'], 'appdata'=>$appdata); - $app=OC_Installer::installApp($info); - } - } - } - $l = OC_L10N::get('core'); - if($app!==false) { - // check if the app is compatible with this version of ownCloud - $info=OC_App::getAppInfo($app); - $version=OC_Util::getVersion(); - if(!isset($info['require']) or !self::isAppVersionCompatible($version, $info['require'])) { - throw new \Exception( - $l->t("App \"%s\" can't be installed because it is not compatible with this version of ownCloud.", - array($info['name']) - ) - ); - }else{ - OC_Appconfig::setValue( $app, 'enabled', 'yes' ); - if(isset($appdata['id'])) { - OC_Appconfig::setValue( $app, 'ocsid', $appdata['id'] ); - } - } - }else{ - throw new \Exception($l->t("No app name specified")); - } - } - - /** - * @brief disables an app - * @param string $app app - * @return bool - * - * This function set an app as disabled in appconfig. - */ - public static function disable( $app ) { - // check if app is a shipped app or not. if not delete - \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app)); - OC_Appconfig::setValue( $app, 'enabled', 'no' ); - - // check if app is a shipped app or not. if not delete - if(!OC_App::isShipped( $app )) { - OC_Installer::removeApp( $app ); - } - } - - /** - * @brief adds an entry to the navigation - * @param array $data array containing the data - * @return bool - * - * This function adds a new entry to the navigation visible to users. $data - * is an associative array. - * The following keys are required: - * - id: unique id for this entry ('addressbook_index') - * - href: link to the page - * - name: Human readable name ('Addressbook') - * - * The following keys are optional: - * - icon: path to the icon of the app - * - order: integer, that influences the position of your application in - * the navigation. Lower values come first. - */ - public static function addNavigationEntry( $data ) { - OC::$server->getNavigationManager()->add($data); - return true; - } - - /** - * @brief marks a navigation entry as active - * @param string $id id of the entry - * @return bool - * - * This function sets a navigation entry as active and removes the 'active' - * property from all other entries. The templates can use this for - * highlighting the current position of the user. - */ - public static function setActiveNavigationEntry( $id ) { - OC::$server->getNavigationManager()->setActiveEntry($id); - return true; - } - - /** - * @brief Get the navigation entries for the $app - * @param string $app app - * @return array of the $data added with addNavigationEntry - * - * Warning: destroys the existing entries - */ - public static function getAppNavigationEntries($app) { - if(is_file(self::getAppPath($app).'/appinfo/app.php')) { - OC::$server->getNavigationManager()->clear(); - require $app.'/appinfo/app.php'; - return OC::$server->getNavigationManager()->getAll(); - } - return array(); - } - - /** - * @brief gets the active Menu entry - * @return string id or empty string - * - * This function returns the id of the active navigation entry (set by - * setActiveNavigationEntry - */ - public static function getActiveNavigationEntry() { - return OC::$server->getNavigationManager()->getActiveEntry(); - } - - /** - * @brief Returns the Settings Navigation - * @return array - * - * This function returns an array containing all settings pages added. The - * entries are sorted by the key 'order' ascending. - */ - public static function getSettingsNavigation() { - $l=OC_L10N::get('lib'); - - $settings = array(); - // by default, settings only contain the help menu - if(OC_Util::getEditionString() === '' && - OC_Config::getValue('knowledgebaseenabled', true)==true) { - $settings = array( - array( - "id" => "help", - "order" => 1000, - "href" => OC_Helper::linkToRoute( "settings_help" ), - "name" => $l->t("Help"), - "icon" => OC_Helper::imagePath( "settings", "help.svg" ) - ) - ); - } - - // if the user is logged-in - if (OC_User::isLoggedIn()) { - // personal menu - $settings[] = array( - "id" => "personal", - "order" => 1, - "href" => OC_Helper::linkToRoute( "settings_personal" ), - "name" => $l->t("Personal"), - "icon" => OC_Helper::imagePath( "settings", "personal.svg" ) - ); - - // if there are some settings forms - if(!empty(self::$settingsForms)) { - // settings menu - $settings[]=array( - "id" => "settings", - "order" => 1000, - "href" => OC_Helper::linkToRoute( "settings_settings" ), - "name" => $l->t("Settings"), - "icon" => OC_Helper::imagePath( "settings", "settings.svg" ) - ); - } - - //SubAdmins are also allowed to access user management - if(OC_SubAdmin::isSubAdmin(OC_User::getUser())) { - // admin users menu - $settings[] = array( - "id" => "core_users", - "order" => 2, - "href" => OC_Helper::linkToRoute( "settings_users" ), - "name" => $l->t("Users"), - "icon" => OC_Helper::imagePath( "settings", "users.svg" ) - ); - } - - - // if the user is an admin - if(OC_User::isAdminUser(OC_User::getUser())) { - // admin settings - $settings[]=array( - "id" => "admin", - "order" => 1000, - "href" => OC_Helper::linkToRoute( "settings_admin" ), - "name" => $l->t("Admin"), - "icon" => OC_Helper::imagePath( "settings", "admin.svg" ) - ); - } - } - - $navigation = self::proceedNavigation($settings); - return $navigation; - } - - // This is private as well. It simply works, so don't ask for more details - private static function proceedNavigation( $list ) { - $activeapp = OC::$server->getNavigationManager()->getActiveEntry(); - foreach( $list as &$naventry ) { - if( $naventry['id'] == $activeapp ) { - $naventry['active'] = true; - } - else{ - $naventry['active'] = false; - } - } unset( $naventry ); - - usort( $list, create_function( '$a, $b', 'if( $a["order"] == $b["order"] ) {return 0;}elseif( $a["order"] < $b["order"] ) {return -1;}else{return 1;}' )); - - return $list; - } - - /** - * Get the path where to install apps - */ - public static function getInstallPath() { - if(OC_Config::getValue('appstoreenabled', true)==false) { - return false; - } - - foreach(OC::$APPSROOTS as $dir) { - if(isset($dir['writable']) && $dir['writable']===true) { - return $dir['path']; - } - } - - OC_Log::write('core', 'No application directories are marked as writable.', OC_Log::ERROR); - return null; - } - - - protected static function findAppInDirectories($appid) { - static $app_dir = array(); - if (isset($app_dir[$appid])) { - return $app_dir[$appid]; - } - foreach(OC::$APPSROOTS as $dir) { - if(file_exists($dir['path'].'/'.$appid)) { - return $app_dir[$appid]=$dir; - } - } - return false; - } - /** - * Get the directory for the given app. - * If the app is defined in multiple directories, the first one is taken. (false if not found) - */ - public static function getAppPath($appid) { - if( ($dir = self::findAppInDirectories($appid)) != false) { - return $dir['path'].'/'.$appid; - } - return false; - } - - /** - * Get the path for the given app on the access - * If the app is defined in multiple directories, the first one is taken. (false if not found) - */ - public static function getAppWebPath($appid) { - if( ($dir = self::findAppInDirectories($appid)) != false) { - return OC::$WEBROOT.$dir['url'].'/'.$appid; - } - return false; - } - - /** - * get the last version of the app, either from appinfo/version or from appinfo/info.xml - */ - public static function getAppVersion($appid) { - $file= self::getAppPath($appid).'/appinfo/version'; - if(is_file($file) && $version = trim(file_get_contents($file))) { - return $version; - }else{ - $appData=self::getAppInfo($appid); - return isset($appData['version'])? $appData['version'] : ''; - } - } - - /** - * @brief Read all app metadata from the info.xml file - * @param string $appid id of the app or the path of the info.xml file - * @param boolean $path (optional) - * @return array - * @note all data is read from info.xml, not just pre-defined fields - */ - public static function getAppInfo($appid, $path=false) { - if($path) { - $file=$appid; - }else{ - if(isset(self::$appInfo[$appid])) { - return self::$appInfo[$appid]; - } - $file= self::getAppPath($appid).'/appinfo/info.xml'; - } - $data=array(); - $content=@file_get_contents($file); - if(!$content) { - return null; - } - $xml = new SimpleXMLElement($content); - $data['info']=array(); - $data['remote']=array(); - $data['public']=array(); - foreach($xml->children() as $child) { - /** - * @var $child SimpleXMLElement - */ - if($child->getName()=='remote') { - foreach($child->children() as $remote) { - /** - * @var $remote SimpleXMLElement - */ - $data['remote'][$remote->getName()]=(string)$remote; - } - }elseif($child->getName()=='public') { - foreach($child->children() as $public) { - /** - * @var $public SimpleXMLElement - */ - $data['public'][$public->getName()]=(string)$public; - } - }elseif($child->getName()=='types') { - $data['types']=array(); - foreach($child->children() as $type) { - /** - * @var $type SimpleXMLElement - */ - $data['types'][]=$type->getName(); - } - }elseif($child->getName()=='description') { - $xml=(string)$child->asXML(); - $data[$child->getName()]=substr($xml, 13, -14);//script tags - }else{ - $data[$child->getName()]=(string)$child; - } - } - self::$appInfo[$appid]=$data; - - return $data; - } - - /** - * @brief Returns the navigation - * @return array - * - * This function returns an array containing all entries added. The - * entries are sorted by the key 'order' ascending. Additional to the keys - * given for each app the following keys exist: - * - active: boolean, signals if the user is on this navigation entry - */ - public static function getNavigation() { - $entries = OC::$server->getNavigationManager()->getAll(); - $navigation = self::proceedNavigation( $entries ); - return $navigation; - } - - /** - * get the id of loaded app - * @return string - */ - public static function getCurrentApp() { - $script=substr(OC_Request::scriptName(), strlen(OC::$WEBROOT)+1); - $topFolder=substr($script, 0, strpos($script, '/')); - if (empty($topFolder)) { - $path_info = OC_Request::getPathInfo(); - if ($path_info) { - $topFolder=substr($path_info, 1, strpos($path_info, '/', 1)-1); - } - } - if($topFolder=='apps') { - $length=strlen($topFolder); - return substr($script, $length+1, strpos($script, '/', $length+1)-$length-1); - }else{ - return $topFolder; - } - } - - - /** - * get the forms for either settings, admin or personal - */ - public static function getForms($type) { - $forms=array(); - switch($type) { - case 'settings': - $source=self::$settingsForms; - break; - case 'admin': - $source=self::$adminForms; - break; - case 'personal': - $source=self::$personalForms; - break; - default: - return array(); - } - foreach($source as $form) { - $forms[]=include $form; - } - return $forms; - } - - /** - * register a settings form to be shown - */ - public static function registerSettings($app, $page) { - self::$settingsForms[]= $app.'/'.$page.'.php'; - } - - /** - * register an admin form to be shown - */ - public static function registerAdmin($app, $page) { - self::$adminForms[]= $app.'/'.$page.'.php'; - } - - /** - * register a personal form to be shown - */ - public static function registerPersonal($app, $page) { - self::$personalForms[]= $app.'/'.$page.'.php'; - } - - public static function registerLogIn($entry) { - self::$altLogin[] = $entry; - } - - public static function getAlternativeLogIns() { - return self::$altLogin; - } - - /** - * @brief: get a list of all apps in the apps folder - * @return array or app names (string IDs) - * @todo: change the name of this method to getInstalledApps, which is more accurate - */ - public static function getAllApps() { - - $apps=array(); - - foreach ( OC::$APPSROOTS as $apps_dir ) { - if(! is_readable($apps_dir['path'])) { - OC_Log::write('core', 'unable to read app folder : ' .$apps_dir['path'], OC_Log::WARN); - continue; - } - $dh = opendir( $apps_dir['path'] ); - - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - - if ($file[0] != '.' and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php')) { - - $apps[] = $file; - - } - - } - } - - } - - return $apps; - } - - /** - * @brief: Lists all apps, this is used in apps.php - * @return array - */ - public static function listAllApps() { - $installedApps = OC_App::getAllApps(); - - //TODO which apps do we want to blacklist and how do we integrate - // blacklisting with the multi apps folder feature? - - $blacklist = array('files');//we dont want to show configuration for these - $appList = array(); - - foreach ( $installedApps as $app ) { - if ( array_search( $app, $blacklist ) === false ) { - - $info=OC_App::getAppInfo($app); - - if (!isset($info['name'])) { - OC_Log::write('core', 'App id "'.$app.'" has no name in appinfo', OC_Log::ERROR); - continue; - } - - if ( OC_Appconfig::getValue( $app, 'enabled', 'no') == 'yes' ) { - $active = true; - } else { - $active = false; - } - - $info['active'] = $active; - - if(isset($info['shipped']) and ($info['shipped']=='true')) { - $info['internal']=true; - $info['internallabel']='Internal App'; - $info['internalclass']=''; - $info['update']=false; - } else { - $info['internal']=false; - $info['internallabel']='3rd Party'; - $info['internalclass']='externalapp'; - $info['update']=OC_Installer::isUpdateAvailable($app); - } - - $info['preview'] = OC_Helper::imagePath('settings', 'trans.png'); - $info['version'] = OC_App::getAppVersion($app); - $appList[] = $info; - } - } - $remoteApps = OC_App::getAppstoreApps(); - if ( $remoteApps ) { - // Remove duplicates - foreach ( $appList as $app ) { - foreach ( $remoteApps AS $key => $remote ) { - if ( - $app['name'] == $remote['name'] - // To set duplicate detection to use OCS ID instead of string name, - // enable this code, remove the line of code above, - // and add [ID] to info.xml of each 3rd party app: - // OR $app['ocs_id'] == $remote['ocs_id'] - ) { - unset( $remoteApps[$key]); - } - } - } - $combinedApps = array_merge( $appList, $remoteApps ); - } else { - $combinedApps = $appList; - } - return $combinedApps; - } - - /** - * @brief: get a list of all apps on apps.owncloud.com - * @return array, multi-dimensional array of apps. - * Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description - */ - public static function getAppstoreApps( $filter = 'approved' ) { - $categoryNames = OC_OCSClient::getCategories(); - if ( is_array( $categoryNames ) ) { - // Check that categories of apps were retrieved correctly - if ( ! $categories = array_keys( $categoryNames ) ) { - return false; - } - - $page = 0; - $remoteApps = OC_OCSClient::getApplications( $categories, $page, $filter ); - $app1 = array(); - $i = 0; - foreach ( $remoteApps as $app ) { - $app1[$i] = $app; - $app1[$i]['author'] = $app['personid']; - $app1[$i]['ocs_id'] = $app['id']; - $app1[$i]['internal'] = $app1[$i]['active'] = 0; - $app1[$i]['update'] = false; - if($app['label']=='recommended') { - $app1[$i]['internallabel'] = 'Recommended'; - $app1[$i]['internalclass'] = 'recommendedapp'; - }else{ - $app1[$i]['internallabel'] = '3rd Party'; - $app1[$i]['internalclass'] = 'externalapp'; - } - - - // rating img - if($app['score']>=0 and $app['score']<5) $img=OC_Helper::imagePath( "core", "rating/s1.png" ); - elseif($app['score']>=5 and $app['score']<15) $img=OC_Helper::imagePath( "core", "rating/s2.png" ); - elseif($app['score']>=15 and $app['score']<25) $img=OC_Helper::imagePath( "core", "rating/s3.png" ); - elseif($app['score']>=25 and $app['score']<35) $img=OC_Helper::imagePath( "core", "rating/s4.png" ); - elseif($app['score']>=35 and $app['score']<45) $img=OC_Helper::imagePath( "core", "rating/s5.png" ); - elseif($app['score']>=45 and $app['score']<55) $img=OC_Helper::imagePath( "core", "rating/s6.png" ); - elseif($app['score']>=55 and $app['score']<65) $img=OC_Helper::imagePath( "core", "rating/s7.png" ); - elseif($app['score']>=65 and $app['score']<75) $img=OC_Helper::imagePath( "core", "rating/s8.png" ); - elseif($app['score']>=75 and $app['score']<85) $img=OC_Helper::imagePath( "core", "rating/s9.png" ); - elseif($app['score']>=85 and $app['score']<95) $img=OC_Helper::imagePath( "core", "rating/s10.png" ); - elseif($app['score']>=95 and $app['score']<100) $img=OC_Helper::imagePath( "core", "rating/s11.png" ); - - $app1[$i]['score'] = ' Score: '.$app['score'].'%'; - $i++; - } - } - - if ( empty( $app1 ) ) { - return false; - } else { - return $app1; - } - } - - /** - * check if the app needs updating and update when needed - */ - public static function checkUpgrade($app) { - if (in_array($app, self::$checkedApps)) { - return; - } - self::$checkedApps[] = $app; - $versions = self::getAppVersions(); - $currentVersion=OC_App::getAppVersion($app); - if ($currentVersion) { - $installedVersion = $versions[$app]; - if (version_compare($currentVersion, $installedVersion, '>')) { - $info = self::getAppInfo($app); - OC_Log::write($app, - 'starting app upgrade from '.$installedVersion.' to '.$currentVersion, - OC_Log::DEBUG); - try { - OC_App::updateApp($app); - OC_Hook::emit('update', 'success', 'Updated '.$info['name'].' app'); - } - catch (Exception $e) { - OC_Hook::emit('update', 'failure', 'Failed to update '.$info['name'].' app: '.$e->getMessage()); - $l = OC_L10N::get('lib'); - throw new RuntimeException($l->t('Failed to upgrade "%s".', array($app)), 0, $e); - } - OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app)); - } - } - } - - /** - * check if the current enabled apps are compatible with the current - * ownCloud version. disable them if not. - * This is important if you upgrade ownCloud and have non ported 3rd - * party apps installed. - */ - public static function checkAppsRequirements($apps = array()) { - if (empty($apps)) { - $apps = OC_App::getEnabledApps(); - } - $version = OC_Util::getVersion(); - foreach($apps as $app) { - // check if the app is compatible with this version of ownCloud - $info = OC_App::getAppInfo($app); - if(!isset($info['require']) or !self::isAppVersionCompatible($version, $info['require'])) { - OC_Log::write('core', - 'App "'.$info['name'].'" ('.$app.') can\'t be used because it is' - .' not compatible with this version of ownCloud', - OC_Log::ERROR); - OC_App::disable( $app ); - OC_Hook::emit('update', 'success', 'Disabled '.$info['name'].' app because it is not compatible'); - } - } - } - - - /** - * Compares the app version with the owncloud version to see if the app - * requires a newer version than the currently active one - * @param array $owncloudVersions array with 3 entries: major minor bugfix - * @param string $appRequired the required version from the xml - * major.minor.bugfix - * @return boolean true if compatible, otherwise false - */ - public static function isAppVersionCompatible($owncloudVersions, $appRequired){ - $appVersions = explode('.', $appRequired); - - for($i=0; $i $appVersion) { - return true; - } - } - - return true; - } - - - /** - * get the installed version of all apps - */ - public static function getAppVersions() { - static $versions; - if (isset($versions)) { // simple cache, needs to be fixed - return $versions; // when function is used besides in checkUpgrade - } - $versions=array(); - $query = OC_DB::prepare( 'SELECT `appid`, `configvalue` FROM `*PREFIX*appconfig`' - .' WHERE `configkey` = \'installed_version\'' ); - $result = $query->execute(); - while($row = $result->fetchRow()) { - $versions[$row['appid']]=$row['configvalue']; - } - return $versions; - } - - /** - * update the database for the app and call the update script - * @param string $appid - */ - public static function updateApp($appid) { - if(file_exists(self::getAppPath($appid).'/appinfo/preupdate.php')) { - self::loadApp($appid); - include self::getAppPath($appid).'/appinfo/preupdate.php'; - } - if(file_exists(self::getAppPath($appid).'/appinfo/database.xml')) { - OC_DB::updateDbFromStructure(self::getAppPath($appid).'/appinfo/database.xml'); - } - if(!self::isEnabled($appid)) { - return; - } - if(file_exists(self::getAppPath($appid).'/appinfo/update.php')) { - self::loadApp($appid); - include self::getAppPath($appid).'/appinfo/update.php'; - } - - //set remote/public handlers - $appData=self::getAppInfo($appid); - foreach($appData['remote'] as $name=>$path) { - OCP\CONFIG::setAppValue('core', 'remote_'.$name, $appid.'/'.$path); - } - foreach($appData['public'] as $name=>$path) { - OCP\CONFIG::setAppValue('core', 'public_'.$name, $appid.'/'.$path); - } - - self::setAppTypes($appid); - } - - /** - * @param string $appid - * @return \OC\Files\View - */ - public static function getStorage($appid) { - if(OC_App::isEnabled($appid)) {//sanity check - if(OC_User::isLoggedIn()) { - $view = new \OC\Files\View('/'.OC_User::getUser()); - if(!$view->file_exists($appid)) { - $view->mkdir($appid); - } - return new \OC\Files\View('/'.OC_User::getUser().'/'.$appid); - }else{ - OC_Log::write('core', 'Can\'t get app storage, app '.$appid.', user not logged in', OC_Log::ERROR); - return false; - } - }else{ - OC_Log::write('core', 'Can\'t get app storage, app '.$appid.' not enabled', OC_Log::ERROR); - return false; - } - } -} diff --git a/lib/appconfig.php b/lib/appconfig.php deleted file mode 100644 index e615d838173..00000000000 --- a/lib/appconfig.php +++ /dev/null @@ -1,203 +0,0 @@ -. - * - */ -/* - * - * The following SQL statement is just a help for developers and will not be - * executed! - * - * CREATE TABLE `appconfig` ( - * `appid` VARCHAR( 255 ) NOT NULL , - * `configkey` VARCHAR( 255 ) NOT NULL , - * `configvalue` VARCHAR( 255 ) NOT NULL - * ) - * - */ - -/** - * This class provides an easy way for apps to store config values in the - * database. - */ -class OC_Appconfig{ - /** - * @brief Get all apps using the config - * @return array with app ids - * - * This function returns a list of all apps that have at least one - * entry in the appconfig table. - */ - public static function getApps() { - // No magic in here! - $query = OC_DB::prepare( 'SELECT DISTINCT `appid` FROM `*PREFIX*appconfig`' ); - $result = $query->execute(); - - $apps = array(); - while( $row = $result->fetchRow()) { - $apps[] = $row["appid"]; - } - - return $apps; - } - - /** - * @brief Get the available keys for an app - * @param string $app the app we are looking for - * @return array with key names - * - * This function gets all keys of an app. Please note that the values are - * not returned. - */ - public static function getKeys( $app ) { - // No magic in here as well - $query = OC_DB::prepare( 'SELECT `configkey` FROM `*PREFIX*appconfig` WHERE `appid` = ?' ); - $result = $query->execute( array( $app )); - - $keys = array(); - while( $row = $result->fetchRow()) { - $keys[] = $row["configkey"]; - } - - return $keys; - } - - /** - * @brief Gets the config value - * @param string $app app - * @param string $key key - * @param string $default = null, default value if the key does not exist - * @return string the value or $default - * - * This function gets a value from the appconfig table. If the key does - * not exist the default value will be returned - */ - public static function getValue( $app, $key, $default = null ) { - // At least some magic in here :-) - $query = OC_DB::prepare( 'SELECT `configvalue` FROM `*PREFIX*appconfig`' - .' WHERE `appid` = ? AND `configkey` = ?' ); - $result = $query->execute( array( $app, $key )); - $row = $result->fetchRow(); - if($row) { - return $row["configvalue"]; - }else{ - return $default; - } - } - - /** - * @brief check if a key is set in the appconfig - * @param string $app - * @param string $key - * @return bool - */ - public static function hasKey($app, $key) { - $exists = self::getKeys( $app ); - return in_array( $key, $exists ); - } - - /** - * @brief sets a value in the appconfig - * @param string $app app - * @param string $key key - * @param string $value value - * @return bool - * - * Sets a value. If the key did not exist before it will be created. - */ - public static function setValue( $app, $key, $value ) { - // Does the key exist? yes: update. No: insert - if(! self::hasKey($app, $key)) { - $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*appconfig` ( `appid`, `configkey`, `configvalue` )' - .' VALUES( ?, ?, ? )' ); - $query->execute( array( $app, $key, $value )); - } - else{ - $query = OC_DB::prepare( 'UPDATE `*PREFIX*appconfig` SET `configvalue` = ?' - .' WHERE `appid` = ? AND `configkey` = ?' ); - $query->execute( array( $value, $app, $key )); - } - } - - /** - * @brief Deletes a key - * @param string $app app - * @param string $key key - * @return bool - * - * Deletes a key. - */ - public static function deleteKey( $app, $key ) { - // Boring! - $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*appconfig` WHERE `appid` = ? AND `configkey` = ?' ); - $query->execute( array( $app, $key )); - - return true; - } - - /** - * @brief Remove app from appconfig - * @param string $app app - * @return bool - * - * Removes all keys in appconfig belonging to the app. - */ - public static function deleteApp( $app ) { - // Nothing special - $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*appconfig` WHERE `appid` = ?' ); - $query->execute( array( $app )); - - return true; - } - - /** - * get multiply values, either the app or key can be used as wildcard by setting it to false - * @param app - * @param key - * @return array - */ - public static function getValues($app, $key) { - if($app!==false and $key!==false) { - return false; - } - $fields='`configvalue`'; - $where='WHERE'; - $params=array(); - if($app!==false) { - $fields.=', `configkey`'; - $where.=' `appid` = ?'; - $params[]=$app; - $key='configkey'; - }else{ - $fields.=', `appid`'; - $where.=' `configkey` = ?'; - $params[]=$key; - $key='appid'; - } - $queryString='SELECT '.$fields.' FROM `*PREFIX*appconfig` '.$where; - $query=OC_DB::prepare($queryString); - $result=$query->execute($params); - $values=array(); - while($row=$result->fetchRow()) { - $values[$row[$key]]=$row['configvalue']; - } - return $values; - } -} diff --git a/lib/appframework/app.php b/lib/appframework/app.php deleted file mode 100644 index 7ff55bb809d..00000000000 --- a/lib/appframework/app.php +++ /dev/null @@ -1,98 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework; - -use OC\AppFramework\DependencyInjection\DIContainer; -use OCP\AppFramework\IAppContainer; - - -/** - * Entry point for every request in your app. You can consider this as your - * public static void main() method - * - * Handles all the dependency injection, controllers and output flow - */ -class App { - - - /** - * Shortcut for calling a controller method and printing the result - * @param string $controllerName the name of the controller under which it is - * stored in the DI container - * @param string $methodName the method that you want to call - * @param array $urlParams an array with variables extracted from the routes - * @param DIContainer $container an instance of a pimple container. - */ - public static function main($controllerName, $methodName, array $urlParams, - IAppContainer $container) { - $container['urlParams'] = $urlParams; - $controller = $container[$controllerName]; - - // initialize the dispatcher and run all the middleware before the controller - $dispatcher = $container['Dispatcher']; - - list($httpHeaders, $responseHeaders, $output) = - $dispatcher->dispatch($controller, $methodName); - - if(!is_null($httpHeaders)) { - header($httpHeaders); - } - - foreach($responseHeaders as $name => $value) { - header($name . ': ' . $value); - } - - if(!is_null($output)) { - header('Content-Length: ' . strlen($output)); - print($output); - } - - } - - /** - * Shortcut for calling a controller method and printing the result. - * Similar to App:main except that no headers will be sent. - * This should be used for example when registering sections via - * \OC\AppFramework\Core\API::registerAdmin() - * - * @param string $controllerName the name of the controller under which it is - * stored in the DI container - * @param string $methodName the method that you want to call - * @param array $urlParams an array with variables extracted from the routes - * @param DIContainer $container an instance of a pimple container. - */ - public static function part($controllerName, $methodName, array $urlParams, - DIContainer $container){ - - $container['urlParams'] = $urlParams; - $controller = $container[$controllerName]; - - $dispatcher = $container['Dispatcher']; - - list(, , $output) = $dispatcher->dispatch($controller, $methodName); - return $output; - } - -} diff --git a/lib/appframework/controller/controller.php b/lib/appframework/controller/controller.php deleted file mode 100644 index 0ea0a38cc09..00000000000 --- a/lib/appframework/controller/controller.php +++ /dev/null @@ -1,142 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Controller; - -use OC\AppFramework\Http\Request; -use OC\AppFramework\Core\API; -use OCP\AppFramework\Http\TemplateResponse; - - -/** - * Base class to inherit your controllers from - */ -abstract class Controller { - - /** - * @var API instance of the api layer - */ - protected $api; - - protected $request; - - /** - * @param API $api an api wrapper instance - * @param Request $request an instance of the request - */ - public function __construct(API $api, Request $request){ - $this->api = $api; - $this->request = $request; - } - - - /** - * Lets you access post and get parameters by the index - * @param string $key the key which you want to access in the URL Parameter - * placeholder, $_POST or $_GET array. - * The priority how they're returned is the following: - * 1. URL parameters - * 2. POST parameters - * 3. GET parameters - * @param mixed $default If the key is not found, this value will be returned - * @return mixed the content of the array - */ - public function params($key, $default=null){ - return $this->request->getParam($key, $default); - } - - - /** - * Returns all params that were received, be it from the request - * (as GET or POST) or throuh the URL by the route - * @return array the array with all parameters - */ - public function getParams() { - return $this->request->getParams(); - } - - - /** - * Returns the method of the request - * @return string the method of the request (POST, GET, etc) - */ - public function method() { - return $this->request->getMethod(); - } - - - /** - * Shortcut for accessing an uploaded file through the $_FILES array - * @param string $key the key that will be taken from the $_FILES array - * @return array the file in the $_FILES element - */ - public function getUploadedFile($key) { - return $this->request->getUploadedFile($key); - } - - - /** - * Shortcut for getting env variables - * @param string $key the key that will be taken from the $_ENV array - * @return array the value in the $_ENV element - */ - public function env($key) { - return $this->request->getEnv($key); - } - - - /** - * Shortcut for getting cookie variables - * @param string $key the key that will be taken from the $_COOKIE array - * @return array the value in the $_COOKIE element - */ - public function cookie($key) { - return $this->request->getCookie($key); - } - - - /** - * Shortcut for rendering a template - * @param string $templateName the name of the template - * @param array $params the template parameters in key => value structure - * @param string $renderAs user renders a full page, blank only your template - * admin an entry in the admin settings - * @param array $headers set additional headers in name/value pairs - * @return \OCP\AppFramework\Http\TemplateResponse containing the page - */ - public function render($templateName, array $params=array(), - $renderAs='user', array $headers=array()){ - $response = new TemplateResponse($this->api, $templateName); - $response->setParams($params); - $response->renderAs($renderAs); - - foreach($headers as $name => $value){ - $response->addHeader($name, $value); - } - - return $response; - } - - -} diff --git a/lib/appframework/core/api.php b/lib/appframework/core/api.php deleted file mode 100644 index 39522ee3dd5..00000000000 --- a/lib/appframework/core/api.php +++ /dev/null @@ -1,348 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Core; -use OCP\AppFramework\IApi; - - -/** - * This is used to wrap the owncloud static api calls into an object to make the - * code better abstractable for use in the dependency injection container - * - * Should you find yourself in need for more methods, simply inherit from this - * class and add your methods - */ -class API implements IApi{ - - private $appName; - - /** - * constructor - * @param string $appName the name of your application - */ - public function __construct($appName){ - $this->appName = $appName; - } - - - /** - * Gets the userid of the current user - * @return string the user id of the current user - */ - public function getUserId(){ - return \OCP\User::getUser(); - } - - - /** - * Adds a new javascript file - * @param string $scriptName the name of the javascript in js/ without the suffix - * @param string $appName the name of the app, defaults to the current one - */ - public function addScript($scriptName, $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - \OCP\Util::addScript($appName, $scriptName); - } - - - /** - * Adds a new css file - * @param string $styleName the name of the css file in css/without the suffix - * @param string $appName the name of the app, defaults to the current one - */ - public function addStyle($styleName, $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - \OCP\Util::addStyle($appName, $styleName); - } - - - /** - * shorthand for addScript for files in the 3rdparty directory - * @param string $name the name of the file without the suffix - */ - public function add3rdPartyScript($name){ - \OCP\Util::addScript($this->appName . '/3rdparty', $name); - } - - - /** - * shorthand for addStyle for files in the 3rdparty directory - * @param string $name the name of the file without the suffix - */ - public function add3rdPartyStyle($name){ - \OCP\Util::addStyle($this->appName . '/3rdparty', $name); - } - - - /** - * Returns the translation object - * @return \OC_L10N the translation object - */ - public function getTrans(){ - # TODO: use public api - return \OC_L10N::get($this->appName); - } - - - /** - * Returns the URL for a route - * @param string $routeName the name of the route - * @param array $arguments an array with arguments which will be filled into the url - * @return string the url - */ - public function linkToRoute($routeName, $arguments=array()){ - return \OCP\Util::linkToRoute($routeName, $arguments); - } - - - /** - * Returns an URL for an image or file - * @param string $file the name of the file - * @param string $appName the name of the app, defaults to the current one - */ - public function linkTo($file, $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - return \OCP\Util::linkTo($appName, $file); - } - - - /** - * Returns the link to an image, like link to but only with prepending img/ - * @param string $file the name of the file - * @param string $appName the name of the app, defaults to the current one - */ - public function imagePath($file, $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - return \OCP\Util::imagePath($appName, $file); - } - - - /** - * Makes an URL absolute - * @param string $url the url - * @return string the absolute url - */ - public function getAbsoluteURL($url){ - # TODO: use public api - return \OC_Helper::makeURLAbsolute($url); - } - - - /** - * links to a file - * @param string $file the name of the file - * @param string $appName the name of the app, defaults to the current one - * @deprecated replaced with linkToRoute() - * @return string the url - */ - public function linkToAbsolute($file, $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - return \OCP\Util::linkToAbsolute($appName, $file); - } - - - /** - * Checks if the CSRF check was correct - * @return bool true if CSRF check passed - */ - public function passesCSRFCheck(){ - # TODO: use public api - return \OC_Util::isCallRegistered(); - } - - - /** - * Checks if an app is enabled - * @param string $appName the name of an app - * @return bool true if app is enabled - */ - public function isAppEnabled($appName){ - return \OCP\App::isEnabled($appName); - } - - - /** - * Writes a function into the error log - * @param string $msg the error message to be logged - * @param int $level the error level - */ - public function log($msg, $level=null){ - switch($level){ - case 'debug': - $level = \OCP\Util::DEBUG; - break; - case 'info': - $level = \OCP\Util::INFO; - break; - case 'warn': - $level = \OCP\Util::WARN; - break; - case 'fatal': - $level = \OCP\Util::FATAL; - break; - default: - $level = \OCP\Util::ERROR; - break; - } - \OCP\Util::writeLog($this->appName, $msg, $level); - } - - - /** - * turns an owncloud path into a path on the filesystem - * @param string path the path to the file on the oc filesystem - * @return string the filepath in the filesystem - */ - public function getLocalFilePath($path){ - # TODO: use public api - return \OC_Filesystem::getLocalFile($path); - } - - - /** - * used to return and open a new eventsource - * @return \OC_EventSource a new open EventSource class - */ - public function openEventSource(){ - # TODO: use public api - return new \OC_EventSource(); - } - - /** - * @brief connects a function to a hook - * @param string $signalClass class name of emitter - * @param string $signalName name of signal - * @param string $slotClass class name of slot - * @param string $slotName name of slot, in another word, this is the - * name of the method that will be called when registered - * signal is emitted. - * @return bool, always true - */ - public function connectHook($signalClass, $signalName, $slotClass, $slotName) { - return \OCP\Util::connectHook($signalClass, $signalName, $slotClass, $slotName); - } - - /** - * @brief Emits a signal. To get data from the slot use references! - * @param string $signalClass class name of emitter - * @param string $signalName name of signal - * @param array $params defautl: array() array with additional data - * @return bool, true if slots exists or false if not - */ - public function emitHook($signalClass, $signalName, $params = array()) { - return \OCP\Util::emitHook($signalClass, $signalName, $params); - } - - /** - * @brief clear hooks - * @param string $signalClass - * @param string $signalName - */ - public function clearHook($signalClass=false, $signalName=false) { - if ($signalClass) { - \OC_Hook::clear($signalClass, $signalName); - } - } - - /** - * Gets the content of an URL by using CURL or a fallback if it is not - * installed - * @param string $url the url that should be fetched - * @return string the content of the webpage - */ - public function getUrlContent($url) { - return \OC_Util::getUrlContent($url); - } - - /** - * Register a backgroundjob task - * @param string $className full namespace and class name of the class - * @param string $methodName the name of the static method that should be - * called - */ - public function addRegularTask($className, $methodName) { - \OCP\Backgroundjob::addRegularTask($className, $methodName); - } - - /** - * Returns a template - * @param string $templateName the name of the template - * @param string $renderAs how it should be rendered - * @param string $appName the name of the app - * @return \OCP\Template a new template - */ - public function getTemplate($templateName, $renderAs='user', $appName=null){ - if($appName === null){ - $appName = $this->appName; - } - - if($renderAs === 'blank'){ - return new \OCP\Template($appName, $templateName); - } else { - return new \OCP\Template($appName, $templateName, $renderAs); - } - } - - - /** - * Tells ownCloud to include a template in the admin overview - * @param string $mainPath the path to the main php file without the php - * suffix, relative to your apps directory! not the template directory - * @param string $appName the name of the app, defaults to the current one - */ - public function registerAdmin($mainPath, $appName=null) { - if($appName === null){ - $appName = $this->appName; - } - - \OCP\App::registerAdmin($appName, $mainPath); - } - - - /** - * get the filesystem info - * - * @param string $path - * @return array with the following keys: - * - size - * - mtime - * - mimetype - * - encrypted - * - versioned - */ - public function getFileInfo($path) { - return \OC\Files\Filesystem::getFileInfo($path); - } - -} diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php deleted file mode 100644 index 3755d45fa09..00000000000 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ /dev/null @@ -1,146 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\DependencyInjection; - -use OC\AppFramework\Http\Http; -use OC\AppFramework\Http\Request; -use OC\AppFramework\Http\Dispatcher; -use OC\AppFramework\Core\API; -use OC\AppFramework\Middleware\MiddlewareDispatcher; -use OC\AppFramework\Middleware\Security\SecurityMiddleware; -use OC\AppFramework\Utility\SimpleContainer; -use OC\AppFramework\Utility\TimeFactory; -use OCP\AppFramework\IApi; -use OCP\AppFramework\IAppContainer; -use OCP\AppFramework\IMiddleWare; -use OCP\IServerContainer; - - -class DIContainer extends SimpleContainer implements IAppContainer{ - - /** - * @var array - */ - private $middleWares = array(); - - /** - * Put your class dependencies in here - * @param string $appName the name of the app - */ - public function __construct($appName){ - - $this['AppName'] = $appName; - - $this->registerParameter('ServerContainer', \OC::$server); - - $this['API'] = $this->share(function($c){ - return new API($c['AppName']); - }); - - /** - * Http - */ - $this['Request'] = $this->share(function($c) { - /** @var $c SimpleContainer */ - /** @var $server IServerContainer */ - $server = $c->query('ServerContainer'); - return $server->getRequest(); - }); - - $this['Protocol'] = $this->share(function($c){ - if(isset($_SERVER['SERVER_PROTOCOL'])) { - return new Http($_SERVER, $_SERVER['SERVER_PROTOCOL']); - } else { - return new Http($_SERVER); - } - }); - - $this['Dispatcher'] = $this->share(function($c) { - return new Dispatcher($c['Protocol'], $c['MiddlewareDispatcher']); - }); - - - /** - * Middleware - */ - $this['SecurityMiddleware'] = $this->share(function($c){ - return new SecurityMiddleware($c['API'], $c['Request']); - }); - - $this['MiddlewareDispatcher'] = $this->share(function($c){ - $dispatcher = new MiddlewareDispatcher(); - $dispatcher->registerMiddleware($c['SecurityMiddleware']); - - foreach($this->middleWares as $middleWare) { - $dispatcher->registerMiddleware($middleWare); - } - - return $dispatcher; - }); - - - /** - * Utilities - */ - $this['TimeFactory'] = $this->share(function($c){ - return new TimeFactory(); - }); - - - } - - - /** - * @return IApi - */ - function getCoreApi() - { - return $this->query('API'); - } - - /** - * @return \OCP\IServerContainer - */ - function getServer() - { - return $this->query('ServerContainer'); - } - - /** - * @param IMiddleWare $middleWare - * @return boolean - */ - function registerMiddleWare(IMiddleWare $middleWare) { - array_push($this->middleWares, $middleWare); - } - - /** - * used to return the appname of the set application - * @return string the name of your application - */ - function getAppName() { - return $this->query('AppName'); - } -} diff --git a/lib/appframework/http/dispatcher.php b/lib/appframework/http/dispatcher.php deleted file mode 100644 index ea57a6860cc..00000000000 --- a/lib/appframework/http/dispatcher.php +++ /dev/null @@ -1,100 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Http; - -use \OC\AppFramework\Controller\Controller; -use \OC\AppFramework\Middleware\MiddlewareDispatcher; - - -/** - * Class to dispatch the request to the middleware dispatcher - */ -class Dispatcher { - - private $middlewareDispatcher; - private $protocol; - - - /** - * @param Http $protocol the http protocol with contains all status headers - * @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which - * runs the middleware - */ - public function __construct(Http $protocol, - MiddlewareDispatcher $middlewareDispatcher) { - $this->protocol = $protocol; - $this->middlewareDispatcher = $middlewareDispatcher; - } - - - /** - * Handles a request and calls the dispatcher on the controller - * @param Controller $controller the controller which will be called - * @param string $methodName the method name which will be called on - * the controller - * @return array $array[0] contains a string with the http main header, - * $array[1] contains headers in the form: $key => value, $array[2] contains - * the response output - */ - public function dispatch(Controller $controller, $methodName) { - $out = array(null, array(), null); - - try { - - $this->middlewareDispatcher->beforeController($controller, - $methodName); - $response = $controller->$methodName(); - - // if an exception appears, the middleware checks if it can handle the - // exception and creates a response. If no response is created, it is - // assumed that theres no middleware who can handle it and the error is - // thrown again - } catch(\Exception $exception){ - $response = $this->middlewareDispatcher->afterException( - $controller, $methodName, $exception); - if (is_null($response)) { - throw $exception; - } - } - - $response = $this->middlewareDispatcher->afterController( - $controller, $methodName, $response); - - // get the output which should be printed and run the after output - // middleware to modify the response - $output = $response->render(); - $out[2] = $this->middlewareDispatcher->beforeOutput( - $controller, $methodName, $output); - - // depending on the cache object the headers need to be changed - $out[0] = $this->protocol->getStatusHeader($response->getStatus(), - $response->getLastModified(), $response->getETag()); - $out[1] = $response->getHeaders(); - - return $out; - } - - -} diff --git a/lib/appframework/http/downloadresponse.php b/lib/appframework/http/downloadresponse.php deleted file mode 100644 index 67b9542dba6..00000000000 --- a/lib/appframework/http/downloadresponse.php +++ /dev/null @@ -1,50 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Http; - - -/** - * Prompts the user to download the a file - */ -class DownloadResponse extends \OCP\AppFramework\Http\Response { - - private $filename; - private $contentType; - - /** - * Creates a response that prompts the user to download the file - * @param string $filename the name that the downloaded file should have - * @param string $contentType the mimetype that the downloaded file should have - */ - public function __construct($filename, $contentType) { - $this->filename = $filename; - $this->contentType = $contentType; - - $this->addHeader('Content-Disposition', 'attachment; filename="' . $filename . '"'); - $this->addHeader('Content-Type', $contentType); - } - - -} diff --git a/lib/appframework/http/http.php b/lib/appframework/http/http.php deleted file mode 100644 index e00dc9cdc4a..00000000000 --- a/lib/appframework/http/http.php +++ /dev/null @@ -1,148 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Http; - - -class Http extends \OCP\AppFramework\Http\Http{ - - private $server; - private $protocolVersion; - protected $headers; - - /** - * @param $_SERVER $server - * @param string $protocolVersion the http version to use defaults to HTTP/1.1 - */ - public function __construct($server, $protocolVersion='HTTP/1.1') { - $this->server = $server; - $this->protocolVersion = $protocolVersion; - - $this->headers = array( - self::STATUS_CONTINUE => 'Continue', - self::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols', - self::STATUS_PROCESSING => 'Processing', - self::STATUS_OK => 'OK', - self::STATUS_CREATED => 'Created', - self::STATUS_ACCEPTED => 'Accepted', - self::STATUS_NON_AUTHORATIVE_INFORMATION => 'Non-Authorative Information', - self::STATUS_NO_CONTENT => 'No Content', - self::STATUS_RESET_CONTENT => 'Reset Content', - self::STATUS_PARTIAL_CONTENT => 'Partial Content', - self::STATUS_MULTI_STATUS => 'Multi-Status', // RFC 4918 - self::STATUS_ALREADY_REPORTED => 'Already Reported', // RFC 5842 - self::STATUS_IM_USED => 'IM Used', // RFC 3229 - self::STATUS_MULTIPLE_CHOICES => 'Multiple Choices', - self::STATUS_MOVED_PERMANENTLY => 'Moved Permanently', - self::STATUS_FOUND => 'Found', - self::STATUS_SEE_OTHER => 'See Other', - self::STATUS_NOT_MODIFIED => 'Not Modified', - self::STATUS_USE_PROXY => 'Use Proxy', - self::STATUS_RESERVED => 'Reserved', - self::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect', - self::STATUS_BAD_REQUEST => 'Bad request', - self::STATUS_UNAUTHORIZED => 'Unauthorized', - self::STATUS_PAYMENT_REQUIRED => 'Payment Required', - self::STATUS_FORBIDDEN => 'Forbidden', - self::STATUS_NOT_FOUND => 'Not Found', - self::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed', - self::STATUS_NOT_ACCEPTABLE => 'Not Acceptable', - self::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required', - self::STATUS_REQUEST_TIMEOUT => 'Request Timeout', - self::STATUS_CONFLICT => 'Conflict', - self::STATUS_GONE => 'Gone', - self::STATUS_LENGTH_REQUIRED => 'Length Required', - self::STATUS_PRECONDITION_FAILED => 'Precondition failed', - self::STATUS_REQUEST_ENTITY_TOO_LARGE => 'Request Entity Too Large', - self::STATUS_REQUEST_URI_TOO_LONG => 'Request-URI Too Long', - self::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type', - self::STATUS_REQUEST_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable', - self::STATUS_EXPECTATION_FAILED => 'Expectation Failed', - self::STATUS_IM_A_TEAPOT => 'I\'m a teapot', // RFC 2324 - self::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', // RFC 4918 - self::STATUS_LOCKED => 'Locked', // RFC 4918 - self::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', // RFC 4918 - self::STATUS_UPGRADE_REQUIRED => 'Upgrade required', - self::STATUS_PRECONDITION_REQUIRED => 'Precondition required', // draft-nottingham-http-new-status - self::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', // draft-nottingham-http-new-status - self::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', // draft-nottingham-http-new-status - self::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error', - self::STATUS_NOT_IMPLEMENTED => 'Not Implemented', - self::STATUS_BAD_GATEWAY => 'Bad Gateway', - self::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable', - self::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout', - self::STATUS_HTTP_VERSION_NOT_SUPPORTED => 'HTTP Version not supported', - self::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates', - self::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', // RFC 4918 - self::STATUS_LOOP_DETECTED => 'Loop Detected', // RFC 5842 - self::STATUS_BANDWIDTH_LIMIT_EXCEEDED => 'Bandwidth Limit Exceeded', // non-standard - self::STATUS_NOT_EXTENDED => 'Not extended', - self::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', // draft-nottingham-http-new-status - ); - } - - - /** - * Gets the correct header - * @param Http::CONSTANT $status the constant from the Http class - * @param \DateTime $lastModified formatted last modified date - * @param string $Etag the etag - */ - public function getStatusHeader($status, \DateTime $lastModified=null, - $ETag=null) { - - if(!is_null($lastModified)) { - $lastModified = $lastModified->format(\DateTime::RFC2822); - } - - // if etag or lastmodified have not changed, return a not modified - if ((isset($this->server['HTTP_IF_NONE_MATCH']) - && trim($this->server['HTTP_IF_NONE_MATCH']) === $ETag) - - || - - (isset($this->server['HTTP_IF_MODIFIED_SINCE']) - && trim($this->server['HTTP_IF_MODIFIED_SINCE']) === - $lastModified)) { - - $status = self::STATUS_NOT_MODIFIED; - } - - // we have one change currently for the http 1.0 header that differs - // from 1.1: STATUS_TEMPORARY_REDIRECT should be STATUS_FOUND - // if this differs any more, we want to create childclasses for this - if($status === self::STATUS_TEMPORARY_REDIRECT - && $this->protocolVersion === 'HTTP/1.0') { - - $status = self::STATUS_FOUND; - } - - return $this->protocolVersion . ' ' . $status . ' ' . - $this->headers[$status]; - } - - -} - - diff --git a/lib/appframework/http/redirectresponse.php b/lib/appframework/http/redirectresponse.php deleted file mode 100644 index 688447f1618..00000000000 --- a/lib/appframework/http/redirectresponse.php +++ /dev/null @@ -1,56 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Http; - -use OCP\AppFramework\Http\Response; - - -/** - * Redirects to a different URL - */ -class RedirectResponse extends Response { - - private $redirectURL; - - /** - * Creates a response that redirects to a url - * @param string $redirectURL the url to redirect to - */ - public function __construct($redirectURL) { - $this->redirectURL = $redirectURL; - $this->setStatus(Http::STATUS_TEMPORARY_REDIRECT); - $this->addHeader('Location', $redirectURL); - } - - - /** - * @return string the url to redirect - */ - public function getRedirectURL() { - return $this->redirectURL; - } - - -} diff --git a/lib/appframework/http/request.php b/lib/appframework/http/request.php deleted file mode 100644 index 34605acdfea..00000000000 --- a/lib/appframework/http/request.php +++ /dev/null @@ -1,307 +0,0 @@ -. - * - */ - -namespace OC\AppFramework\Http; - -use OCP\IRequest; - -/** - * Class for accessing variables in the request. - * This class provides an immutable object with request variables. - */ - -class Request implements \ArrayAccess, \Countable, IRequest { - - protected $items = array(); - protected $allowedKeys = array( - 'get', - 'post', - 'files', - 'server', - 'env', - 'cookies', - 'urlParams', - 'params', - 'parameters', - 'method' - ); - - /** - * @param array $vars An associative array with the following optional values: - * @param array 'params' the parsed json array - * @param array 'urlParams' the parameters which were matched from the URL - * @param array 'get' the $_GET array - * @param array 'post' the $_POST array - * @param array 'files' the $_FILES array - * @param array 'server' the $_SERVER array - * @param array 'env' the $_ENV array - * @param array 'session' the $_SESSION array - * @param array 'cookies' the $_COOKIE array - * @param string 'method' the request method (GET, POST etc) - * @see http://www.php.net/manual/en/reserved.variables.php - */ - public function __construct(array $vars=array()) { - - foreach($this->allowedKeys as $name) { - $this->items[$name] = isset($vars[$name]) - ? $vars[$name] - : array(); - } - - $this->items['parameters'] = array_merge( - $this->items['params'], - $this->items['get'], - $this->items['post'], - $this->items['urlParams'] - ); - - } - - // Countable method. - public function count() { - return count(array_keys($this->items['parameters'])); - } - - /** - * ArrayAccess methods - * - * Gives access to the combined GET, POST and urlParams arrays - * - * Examples: - * - * $var = $request['myvar']; - * - * or - * - * if(!isset($request['myvar']) { - * // Do something - * } - * - * $request['myvar'] = 'something'; // This throws an exception. - * - * @param string $offset The key to lookup - * @return string|null - */ - public function offsetExists($offset) { - return isset($this->items['parameters'][$offset]); - } - - /** - * @see offsetExists - */ - public function offsetGet($offset) { - return isset($this->items['parameters'][$offset]) - ? $this->items['parameters'][$offset] - : null; - } - - /** - * @see offsetExists - */ - public function offsetSet($offset, $value) { - throw new \RuntimeException('You cannot change the contents of the request object'); - } - - /** - * @see offsetExists - */ - public function offsetUnset($offset) { - throw new \RuntimeException('You cannot change the contents of the request object'); - } - - // Magic property accessors - public function __set($name, $value) { - throw new \RuntimeException('You cannot change the contents of the request object'); - } - - /** - * Access request variables by method and name. - * Examples: - * - * $request->post['myvar']; // Only look for POST variables - * $request->myvar; or $request->{'myvar'}; or $request->{$myvar} - * Looks in the combined GET, POST and urlParams array. - * - * if($request->method !== 'POST') { - * throw new Exception('This function can only be invoked using POST'); - * } - * - * @param string $name The key to look for. - * @return mixed|null - */ - public function __get($name) { - switch($name) { - case 'get': - case 'post': - case 'files': - case 'server': - case 'env': - case 'cookies': - case 'parameters': - case 'params': - case 'urlParams': - return isset($this->items[$name]) - ? $this->items[$name] - : null; - break; - case 'method': - return $this->items['method']; - break; - default; - return isset($this[$name]) - ? $this[$name] - : null; - break; - } - } - - - public function __isset($name) { - return isset($this->items['parameters'][$name]); - } - - - public function __unset($id) { - throw new \RunTimeException('You cannot change the contents of the request object'); - } - - /** - * Returns the value for a specific http header. - * - * This method returns null if the header did not exist. - * - * @param string $name - * @return string - */ - public function getHeader($name) { - - $name = strtoupper(str_replace(array('-'),array('_'),$name)); - if (isset($this->server['HTTP_' . $name])) { - return $this->server['HTTP_' . $name]; - } - - // There's a few headers that seem to end up in the top-level - // server array. - switch($name) { - case 'CONTENT_TYPE' : - case 'CONTENT_LENGTH' : - if (isset($this->server[$name])) { - return $this->server[$name]; - } - break; - - } - - return null; - } - - /** - * Lets you access post and get parameters by the index - * In case of json requests the encoded json body is accessed - * - * @param string $key the key which you want to access in the URL Parameter - * placeholder, $_POST or $_GET array. - * The priority how they're returned is the following: - * 1. URL parameters - * 2. POST parameters - * 3. GET parameters - * @param mixed $default If the key is not found, this value will be returned - * @return mixed the content of the array - */ - public function getParam($key, $default = null) { - return isset($this->parameters[$key]) - ? $this->parameters[$key] - : $default; - } - - /** - * Returns all params that were received, be it from the request - * (as GET or POST) or throuh the URL by the route - * @return array the array with all parameters - */ - public function getParams() { - return $this->parameters; - } - - /** - * Returns the method of the request - * @return string the method of the request (POST, GET, etc) - */ - public function getMethod() { - return $this->method; - } - - /** - * Shortcut for accessing an uploaded file through the $_FILES array - * @param string $key the key that will be taken from the $_FILES array - * @return array the file in the $_FILES element - */ - public function getUploadedFile($key) { - return isset($this->files[$key]) ? $this->files[$key] : null; - } - - /** - * Shortcut for getting env variables - * @param string $key the key that will be taken from the $_ENV array - * @return array the value in the $_ENV element - */ - public function getEnv($key) { - return isset($this->env[$key]) ? $this->env[$key] : null; - } - - /** - * Shortcut for getting cookie variables - * @param string $key the key that will be taken from the $_COOKIE array - * @return array the value in the $_COOKIE element - */ - function getCookie($key) { - return isset($this->cookies[$key]) ? $this->cookies[$key] : null; - } - - /** - * Returns the request body content. - * - * @param Boolean $asResource If true, a resource will be returned - * - * @return string|resource The request body content or a resource to read the body stream. - * - * @throws \LogicException - */ - function getContent($asResource = false) { - return null; -// if (false === $this->content || (true === $asResource && null !== $this->content)) { -// throw new \LogicException('getContent() can only be called once when using the resource return type.'); -// } -// -// if (true === $asResource) { -// $this->content = false; -// -// return fopen('php://input', 'rb'); -// } -// -// if (null === $this->content) { -// $this->content = file_get_contents('php://input'); -// } -// -// return $this->content; - } -} diff --git a/lib/appframework/middleware/middleware.php b/lib/appframework/middleware/middleware.php deleted file mode 100644 index b12c03c3eb8..00000000000 --- a/lib/appframework/middleware/middleware.php +++ /dev/null @@ -1,100 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Middleware; - -use OCP\AppFramework\Http\Response; - - -/** - * Middleware is used to provide hooks before or after controller methods and - * deal with possible exceptions raised in the controller methods. - * They're modeled after Django's middleware system: - * https://docs.djangoproject.com/en/dev/topics/http/middleware/ - */ -abstract class Middleware { - - - /** - * This is being run in normal order before the controller is being - * called which allows several modifications and checks - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - */ - public function beforeController($controller, $methodName){ - - } - - - /** - * This is being run when either the beforeController method or the - * controller method itself is throwing an exception. The middleware is - * asked in reverse order to handle the exception and to return a response. - * If the response is null, it is assumed that the exception could not be - * handled and the error will be thrown again - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param \Exception $exception the thrown exception - * @throws \Exception the passed in exception if it cant handle it - * @return Response a Response object in case that the exception was handled - */ - public function afterException($controller, $methodName, \Exception $exception){ - throw $exception; - } - - - /** - * This is being run after a successful controllermethod call and allows - * the manipulation of a Response object. The middleware is run in reverse order - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param Response $response the generated response from the controller - * @return Response a Response object - */ - public function afterController($controller, $methodName, Response $response){ - return $response; - } - - - /** - * This is being run after the response object has been rendered and - * allows the manipulation of the output. The middleware is run in reverse order - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param string $output the generated output from a response - * @return string the output that should be printed - */ - public function beforeOutput($controller, $methodName, $output){ - return $output; - } - -} diff --git a/lib/appframework/middleware/middlewaredispatcher.php b/lib/appframework/middleware/middlewaredispatcher.php deleted file mode 100644 index 70ab108e6b8..00000000000 --- a/lib/appframework/middleware/middlewaredispatcher.php +++ /dev/null @@ -1,159 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Middleware; - -use OC\AppFramework\Controller\Controller; -use OCP\AppFramework\Http\Response; - - -/** - * This class is used to store and run all the middleware in correct order - */ -class MiddlewareDispatcher { - - /** - * @var array array containing all the middlewares - */ - private $middlewares; - - /** - * @var int counter which tells us what middlware was executed once an - * exception occurs - */ - private $middlewareCounter; - - - /** - * Constructor - */ - public function __construct(){ - $this->middlewares = array(); - $this->middlewareCounter = 0; - } - - - /** - * Adds a new middleware - * @param Middleware $middleware the middleware which will be added - */ - public function registerMiddleware(Middleware $middleWare){ - array_push($this->middlewares, $middleWare); - } - - - /** - * returns an array with all middleware elements - * @return array the middlewares - */ - public function getMiddlewares(){ - return $this->middlewares; - } - - - /** - * This is being run in normal order before the controller is being - * called which allows several modifications and checks - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - */ - public function beforeController(Controller $controller, $methodName){ - // we need to count so that we know which middlewares we have to ask in - // case theres an exception - for($i=0; $imiddlewares); $i++){ - $this->middlewareCounter++; - $middleware = $this->middlewares[$i]; - $middleware->beforeController($controller, $methodName); - } - } - - - /** - * This is being run when either the beforeController method or the - * controller method itself is throwing an exception. The middleware is asked - * in reverse order to handle the exception and to return a response. - * If the response is null, it is assumed that the exception could not be - * handled and the error will be thrown again - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param \Exception $exception the thrown exception - * @return Response a Response object if the middleware can handle the - * exception - * @throws \Exception the passed in exception if it cant handle it - */ - public function afterException(Controller $controller, $methodName, \Exception $exception){ - for($i=$this->middlewareCounter-1; $i>=0; $i--){ - $middleware = $this->middlewares[$i]; - try { - return $middleware->afterException($controller, $methodName, $exception); - } catch(\Exception $exception){ - continue; - } - } - throw $exception; - } - - - /** - * This is being run after a successful controllermethod call and allows - * the manipulation of a Response object. The middleware is run in reverse order - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param Response $response the generated response from the controller - * @return Response a Response object - */ - public function afterController(Controller $controller, $methodName, Response $response){ - for($i=count($this->middlewares)-1; $i>=0; $i--){ - $middleware = $this->middlewares[$i]; - $response = $middleware->afterController($controller, $methodName, $response); - } - return $response; - } - - - /** - * This is being run after the response object has been rendered and - * allows the manipulation of the output. The middleware is run in reverse order - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param string $output the generated output from a response - * @return string the output that should be printed - */ - public function beforeOutput(Controller $controller, $methodName, $output){ - for($i=count($this->middlewares)-1; $i>=0; $i--){ - $middleware = $this->middlewares[$i]; - $output = $middleware->beforeOutput($controller, $methodName, $output); - } - return $output; - } - -} diff --git a/lib/appframework/middleware/security/securityexception.php b/lib/appframework/middleware/security/securityexception.php deleted file mode 100644 index b32a2769ff5..00000000000 --- a/lib/appframework/middleware/security/securityexception.php +++ /dev/null @@ -1,41 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Middleware\Security; - - -/** - * Thrown when the security middleware encounters a security problem - */ -class SecurityException extends \Exception { - - /** - * @param string $msg the security error message - * @param bool $ajax true if it resulted because of an ajax request - */ - public function __construct($msg, $code = 0) { - parent::__construct($msg, $code); - } - -} diff --git a/lib/appframework/middleware/security/securitymiddleware.php b/lib/appframework/middleware/security/securitymiddleware.php deleted file mode 100644 index 4f1447e1afb..00000000000 --- a/lib/appframework/middleware/security/securitymiddleware.php +++ /dev/null @@ -1,136 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Middleware\Security; - -use OC\AppFramework\Controller\Controller; -use OC\AppFramework\Http\Http; -use OC\AppFramework\Http\Request; -use OC\AppFramework\Http\RedirectResponse; -use OC\AppFramework\Utility\MethodAnnotationReader; -use OC\AppFramework\Middleware\Middleware; -use OC\AppFramework\Core\API; -use OCP\AppFramework\Http\Response; -use OCP\AppFramework\Http\JSONResponse; - - -/** - * Used to do all the authentication and checking stuff for a controller method - * It reads out the annotations of a controller method and checks which if - * security things should be checked and also handles errors in case a security - * check fails - */ -class SecurityMiddleware extends Middleware { - - private $api; - - /** - * @var \OC\AppFramework\Http\Request - */ - private $request; - - /** - * @param API $api an instance of the api - */ - public function __construct(API $api, Request $request){ - $this->api = $api; - $this->request = $request; - } - - - /** - * This runs all the security checks before a method call. The - * security checks are determined by inspecting the controller method - * annotations - * @param string/Controller $controller the controllername or string - * @param string $methodName the name of the method - * @throws SecurityException when a security check fails - */ - public function beforeController($controller, $methodName){ - - // get annotations from comments - $annotationReader = new MethodAnnotationReader($controller, $methodName); - - // this will set the current navigation entry of the app, use this only - // for normal HTML requests and not for AJAX requests - $this->api->activateNavigationEntry(); - - // security checks - $isPublicPage = $annotationReader->hasAnnotation('PublicPage'); - if(!$isPublicPage) { - if(!$this->api->isLoggedIn()) { - throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); - } - - if(!$annotationReader->hasAnnotation('NoAdminRequired')) { - if(!$this->api->isAdminUser($this->api->getUserId())) { - throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); - } - } - } - - if(!$annotationReader->hasAnnotation('NoCSRFRequired')) { - if(!$this->api->passesCSRFCheck()) { - throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); - } - } - - } - - - /** - * If an SecurityException is being caught, ajax requests return a JSON error - * response and non ajax requests redirect to the index - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param \Exception $exception the thrown exception - * @throws \Exception the passed in exception if it cant handle it - * @return Response a Response object or null in case that the exception could not be handled - */ - public function afterException($controller, $methodName, \Exception $exception){ - if($exception instanceof SecurityException){ - - if (stripos($this->request->getHeader('Accept'),'html')===false) { - - $response = new JSONResponse( - array('message' => $exception->getMessage()), - $exception->getCode() - ); - $this->api->log($exception->getMessage(), 'debug'); - } else { - - $url = $this->api->linkToAbsolute('index.php', ''); // TODO: replace with link to route - $response = new RedirectResponse($url); - $this->api->log($exception->getMessage(), 'debug'); - } - - return $response; - - } - - throw $exception; - } - -} diff --git a/lib/appframework/routing/routeactionhandler.php b/lib/appframework/routing/routeactionhandler.php deleted file mode 100644 index 7fb56f14eab..00000000000 --- a/lib/appframework/routing/routeactionhandler.php +++ /dev/null @@ -1,42 +0,0 @@ -. - * - */ - -namespace OC\AppFramework\routing; - -use \OC\AppFramework\App; -use \OC\AppFramework\DependencyInjection\DIContainer; - -class RouteActionHandler { - private $controllerName; - private $actionName; - private $container; - - public function __construct(DIContainer $container, $controllerName, $actionName) { - $this->controllerName = $controllerName; - $this->actionName = $actionName; - $this->container = $container; - } - - public function __invoke($params) { - App::main($this->controllerName, $this->actionName, $params, $this->container); - } -} diff --git a/lib/appframework/routing/routeconfig.php b/lib/appframework/routing/routeconfig.php deleted file mode 100644 index 53ab11bf2f5..00000000000 --- a/lib/appframework/routing/routeconfig.php +++ /dev/null @@ -1,186 +0,0 @@ -. - * - */ - -namespace OC\AppFramework\routing; - -use OC\AppFramework\DependencyInjection\DIContainer; - -/** - * Class RouteConfig - * @package OC\AppFramework\routing - */ -class RouteConfig { - private $container; - private $router; - private $routes; - private $appName; - - /** - * @param \OC\AppFramework\DependencyInjection\DIContainer $container - * @param \OC_Router $router - * @param string $pathToYml - * @internal param $appName - */ - public function __construct(DIContainer $container, \OC_Router $router, $routes) { - $this->routes = $routes; - $this->container = $container; - $this->router = $router; - $this->appName = $container['AppName']; - } - - /** - * The routes and resource will be registered to the \OC_Router - */ - public function register() { - - // parse simple - $this->processSimpleRoutes($this->routes); - - // parse resources - $this->processResources($this->routes); - } - - /** - * Creates one route base on the give configuration - * @param $routes - * @throws \UnexpectedValueException - */ - private function processSimpleRoutes($routes) - { - $simpleRoutes = isset($routes['routes']) ? $routes['routes'] : array(); - foreach ($simpleRoutes as $simpleRoute) { - $name = $simpleRoute['name']; - $url = $simpleRoute['url']; - $verb = isset($simpleRoute['verb']) ? strtoupper($simpleRoute['verb']) : 'GET'; - - $split = explode('#', $name, 2); - if (count($split) != 2) { - throw new \UnexpectedValueException('Invalid route name'); - } - $controller = $split[0]; - $action = $split[1]; - - $controllerName = $this->buildControllerName($controller); - $actionName = $this->buildActionName($action); - - // register the route - $handler = new RouteActionHandler($this->container, $controllerName, $actionName); - $this->router->create($this->appName.'.'.$controller.'.'.$action, $url)->method($verb)->action($handler); - } - } - - /** - * For a given name and url restful routes are created: - * - index - * - show - * - new - * - create - * - update - * - destroy - * - * @param $routes - */ - private function processResources($routes) - { - // declaration of all restful actions - $actions = array( - array('name' => 'index', 'verb' => 'GET', 'on-collection' => true), - array('name' => 'show', 'verb' => 'GET'), - array('name' => 'create', 'verb' => 'POST', 'on-collection' => true), - array('name' => 'update', 'verb' => 'PUT'), - array('name' => 'destroy', 'verb' => 'DELETE'), - ); - - $resources = isset($routes['resources']) ? $routes['resources'] : array(); - foreach ($resources as $resource => $config) { - - // the url parameter used as id to the resource - $resourceId = $this->buildResourceId($resource); - foreach($actions as $action) { - $url = $config['url']; - $method = $action['name']; - $verb = isset($action['verb']) ? strtoupper($action['verb']) : 'GET'; - $collectionAction = isset($action['on-collection']) ? $action['on-collection'] : false; - if (!$collectionAction) { - $url = $url . '/' . $resourceId; - } - if (isset($action['url-postfix'])) { - $url = $url . '/' . $action['url-postfix']; - } - - $controller = $resource; - - $controllerName = $this->buildControllerName($controller); - $actionName = $this->buildActionName($method); - - $routeName = $this->appName . '.' . strtolower($resource) . '.' . strtolower($method); - - $this->router->create($routeName, $url)->method($verb)->action( - new RouteActionHandler($this->container, $controllerName, $actionName) - ); - } - } - } - - /** - * Based on a given route name the controller name is generated - * @param $controller - * @return string - */ - private function buildControllerName($controller) - { - return $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller'; - } - - /** - * Based on the action part of the route name the controller method name is generated - * @param $action - * @return string - */ - private function buildActionName($action) { - return $this->underScoreToCamelCase($action); - } - - /** - * Generates the id used in the url part o the route url - * @param $resource - * @return string - */ - private function buildResourceId($resource) { - return '{'.$this->underScoreToCamelCase(rtrim($resource, 's')).'Id}'; - } - - /** - * Underscored strings are converted to camel case strings - * @param $str string - * @return string - */ - private function underScoreToCamelCase($str) { - $pattern = "/_[a-z]?/"; - return preg_replace_callback( - $pattern, - function ($matches) { - return strtoupper(ltrim($matches[0], "_")); - }, - $str); - } -} diff --git a/lib/appframework/utility/methodannotationreader.php b/lib/appframework/utility/methodannotationreader.php deleted file mode 100644 index 42060a08529..00000000000 --- a/lib/appframework/utility/methodannotationreader.php +++ /dev/null @@ -1,61 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Utility; - - -/** - * Reads and parses annotations from doc comments - */ -class MethodAnnotationReader { - - private $annotations; - - /** - * @param object $object an object or classname - * @param string $method the method which we want to inspect for annotations - */ - public function __construct($object, $method){ - $this->annotations = array(); - - $reflection = new \ReflectionMethod($object, $method); - $docs = $reflection->getDocComment(); - - // extract everything prefixed by @ and first letter uppercase - preg_match_all('/@([A-Z]\w+)/', $docs, $matches); - $this->annotations = $matches[1]; - } - - - /** - * Check if a method contains an annotation - * @param string $name the name of the annotation - * @return bool true if the annotation is found - */ - public function hasAnnotation($name){ - return in_array($name, $this->annotations); - } - - -} diff --git a/lib/appframework/utility/simplecontainer.php b/lib/appframework/utility/simplecontainer.php deleted file mode 100644 index a51ace83a37..00000000000 --- a/lib/appframework/utility/simplecontainer.php +++ /dev/null @@ -1,44 +0,0 @@ -offsetGet($name); - } - - function registerParameter($name, $value) - { - $this[$name] = $value; - } - - /** - * The given closure is call the first time the given service is queried. - * The closure has to return the instance for the given service. - * Created instance will be cached in case $shared is true. - * - * @param string $name name of the service to register another backend for - * @param callable $closure the closure to be called on service creation - */ - function registerService($name, \Closure $closure, $shared = true) - { - if ($shared) { - $this[$name] = \Pimple::share($closure); - } else { - $this[$name] = $closure; - } - } -} diff --git a/lib/appframework/utility/timefactory.php b/lib/appframework/utility/timefactory.php deleted file mode 100644 index 2c3dd6cf5e3..00000000000 --- a/lib/appframework/utility/timefactory.php +++ /dev/null @@ -1,42 +0,0 @@ -. - * - */ - - -namespace OC\AppFramework\Utility; - - -/** - * Needed to mock calls to time() - */ -class TimeFactory { - - - /** - * @return int the result of a call to time() - */ - public function getTime() { - return time(); - } - - -} diff --git a/lib/archive.php b/lib/archive.php deleted file mode 100644 index 85bfae57295..00000000000 --- a/lib/archive.php +++ /dev/null @@ -1,137 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -abstract class OC_Archive{ - /** - * open any of the supported archive types - * @param string path - * @return OC_Archive - */ - public static function open($path) { - $ext=substr($path, strrpos($path, '.')); - switch($ext) { - case '.zip': - return new OC_Archive_ZIP($path); - case '.gz': - case '.bz': - case '.bz2': - if(strpos($path, '.tar.')) { - return new OC_Archive_TAR($path); - } - break; - case '.tgz': - return new OC_Archive_TAR($path); - } - } - - abstract function __construct($source); - /** - * add an empty folder to the archive - * @param string path - * @return bool - */ - abstract function addFolder($path); - /** - * add a file to the archive - * @param string path - * @param string source either a local file or string data - * @return bool - */ - abstract function addFile($path, $source=''); - /** - * rename a file or folder in the archive - * @param string source - * @param string dest - * @return bool - */ - abstract function rename($source, $dest); - /** - * get the uncompressed size of a file in the archive - * @param string path - * @return int - */ - abstract function filesize($path); - /** - * get the last modified time of a file in the archive - * @param string path - * @return int - */ - abstract function mtime($path); - /** - * get the files in a folder - * @param path - * @return array - */ - abstract function getFolder($path); - /** - * get all files in the archive - * @return array - */ - abstract function getFiles(); - /** - * get the content of a file - * @param string path - * @return string - */ - abstract function getFile($path); - /** - * extract a single file from the archive - * @param string path - * @param string dest - * @return bool - */ - abstract function extractFile($path, $dest); - /** - * extract the archive - * @param string path - * @param string dest - * @return bool - */ - abstract function extract($dest); - /** - * check if a file or folder exists in the archive - * @param string path - * @return bool - */ - abstract function fileExists($path); - /** - * remove a file or folder from the archive - * @param string path - * @return bool - */ - abstract function remove($path); - /** - * get a file handler - * @param string path - * @param string mode - * @return resource - */ - abstract function getStream($path, $mode); - /** - * add a folder and all its content - * @param string $path - * @param string source - * @return bool - */ - function addRecursive($path, $source) { - $dh = opendir($source); - if(is_resource($dh)) { - $this->addFolder($path); - while (($file = readdir($dh)) !== false) { - if($file=='.' or $file=='..') { - continue; - } - if(is_dir($source.'/'.$file)) { - $this->addRecursive($path.'/'.$file, $source.'/'.$file); - }else{ - $this->addFile($path.'/'.$file, $source.'/'.$file); - } - } - } - } -} diff --git a/lib/archive/tar.php b/lib/archive/tar.php deleted file mode 100644 index a1c0535b1c3..00000000000 --- a/lib/archive/tar.php +++ /dev/null @@ -1,339 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -require_once OC::$THIRDPARTYROOT . '/3rdparty/Archive/Tar.php'; - -class OC_Archive_TAR extends OC_Archive{ - const PLAIN=0; - const GZIP=1; - const BZIP=2; - - private $fileList; - private $cachedHeaders; - - /** - * @var Archive_Tar tar - */ - private $tar=null; - private $path; - - function __construct($source) { - $types=array(null, 'gz', 'bz'); - $this->path=$source; - $this->tar=new Archive_Tar($source, $types[self::getTarType($source)]); - } - - /** - * try to detect the type of tar compression - * @param string file - * @return str - */ - static public function getTarType($file) { - if(strpos($file, '.')) { - $extension=substr($file, strrpos($file, '.')); - switch($extension) { - case 'gz': - case 'tgz': - return self::GZIP; - case 'bz': - case 'bz2': - return self::BZIP; - default: - return self::PLAIN; - } - }else{ - return self::PLAIN; - } - } - - /** - * add an empty folder to the archive - * @param string path - * @return bool - */ - function addFolder($path) { - $tmpBase=OC_Helper::tmpFolder(); - if(substr($path, -1, 1)!='/') { - $path.='/'; - } - if($this->fileExists($path)) { - return false; - } - $parts=explode('/', $path); - $folder=$tmpBase; - foreach($parts as $part) { - $folder.='/'.$part; - if(!is_dir($folder)) { - mkdir($folder); - } - } - $result=$this->tar->addModify(array($tmpBase.$path), '', $tmpBase); - rmdir($tmpBase.$path); - $this->fileList=false; - $this->cachedHeaders=false; - return $result; - } - /** - * add a file to the archive - * @param string path - * @param string source either a local file or string data - * @return bool - */ - function addFile($path, $source='') { - if($this->fileExists($path)) { - $this->remove($path); - } - if($source and $source[0]=='/' and file_exists($source)) { - $header=array(); - $dummy=''; - $this->tar->_openAppend(); - $result=$this->tar->_addfile($source, $header, $dummy, $dummy, $path); - }else{ - $result=$this->tar->addString($path, $source); - } - $this->fileList=false; - $this->cachedHeaders=false; - return $result; - } - - /** - * rename a file or folder in the archive - * @param string source - * @param string dest - * @return bool - */ - function rename($source, $dest) { - //no proper way to delete, rename entire archive, rename file and remake archive - $tmp=OCP\Files::tmpFolder(); - $this->tar->extract($tmp); - rename($tmp.$source, $tmp.$dest); - $this->tar=null; - unlink($this->path); - $types=array(null, 'gz', 'bz'); - $this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]); - $this->tar->createModify(array($tmp), '', $tmp.'/'); - $this->fileList=false; - $this->cachedHeaders=false; - return true; - } - - private function getHeader($file) { - if ( ! $this->cachedHeaders ) { - $this->cachedHeaders = $this->tar->listContent(); - } - foreach($this->cachedHeaders as $header) { - if( $file == $header['filename'] - or $file.'/' == $header['filename'] - or '/'.$file.'/' == $header['filename'] - or '/'.$file == $header['filename']) { - return $header; - } - } - return null; - } - - /** - * get the uncompressed size of a file in the archive - * @param string path - * @return int - */ - function filesize($path) { - $stat=$this->getHeader($path); - return $stat['size']; - } - /** - * get the last modified time of a file in the archive - * @param string path - * @return int - */ - function mtime($path) { - $stat=$this->getHeader($path); - return $stat['mtime']; - } - - /** - * get the files in a folder - * @param path - * @return array - */ - function getFolder($path) { - $files=$this->getFiles(); - $folderContent=array(); - $pathLength=strlen($path); - foreach($files as $file) { - if($file[0]=='/') { - $file=substr($file, 1); - } - if(substr($file, 0, $pathLength)==$path and $file!=$path) { - $result=substr($file, $pathLength); - if($pos=strpos($result, '/')) { - $result=substr($result, 0, $pos+1); - } - if(array_search($result, $folderContent)===false) { - $folderContent[]=$result; - } - } - } - return $folderContent; - } - /** - * get all files in the archive - * @return array - */ - function getFiles() { - if($this->fileList) { - return $this->fileList; - } - if ( ! $this->cachedHeaders ) { - $this->cachedHeaders = $this->tar->listContent(); - } - $files=array(); - foreach($this->cachedHeaders as $header) { - $files[]=$header['filename']; - } - $this->fileList=$files; - return $files; - } - /** - * get the content of a file - * @param string path - * @return string - */ - function getFile($path) { - return $this->tar->extractInString($path); - } - /** - * extract a single file from the archive - * @param string path - * @param string dest - * @return bool - */ - function extractFile($path, $dest) { - $tmp=OCP\Files::tmpFolder(); - if(!$this->fileExists($path)) { - return false; - } - if($this->fileExists('/'.$path)) { - $success=$this->tar->extractList(array('/'.$path), $tmp); - }else{ - $success=$this->tar->extractList(array($path), $tmp); - } - if($success) { - rename($tmp.$path, $dest); - } - OCP\Files::rmdirr($tmp); - return $success; - } - /** - * extract the archive - * @param string path - * @param string dest - * @return bool - */ - function extract($dest) { - return $this->tar->extract($dest); - } - /** - * check if a file or folder exists in the archive - * @param string path - * @return bool - */ - function fileExists($path) { - $files=$this->getFiles(); - if((array_search($path, $files)!==false) or (array_search($path.'/', $files)!==false)) { - return true; - }else{ - $folderPath=$path; - if(substr($folderPath, -1, 1)!='/') { - $folderPath.='/'; - } - $pathLength=strlen($folderPath); - foreach($files as $file) { - if(strlen($file)>$pathLength and substr($file, 0, $pathLength)==$folderPath) { - return true; - } - } - } - if($path[0]!='/') {//not all programs agree on the use of a leading / - return $this->fileExists('/'.$path); - }else{ - return false; - } - } - - /** - * remove a file or folder from the archive - * @param string path - * @return bool - */ - function remove($path) { - if(!$this->fileExists($path)) { - return false; - } - $this->fileList=false; - $this->cachedHeaders=false; - //no proper way to delete, extract entire archive, delete file and remake archive - $tmp=OCP\Files::tmpFolder(); - $this->tar->extract($tmp); - OCP\Files::rmdirr($tmp.$path); - $this->tar=null; - unlink($this->path); - $this->reopen(); - $this->tar->createModify(array($tmp), '', $tmp); - return true; - } - /** - * get a file handler - * @param string path - * @param string mode - * @return resource - */ - function getStream($path, $mode) { - if(strrpos($path, '.')!==false) { - $ext=substr($path, strrpos($path, '.')); - }else{ - $ext=''; - } - $tmpFile=OCP\Files::tmpFile($ext); - if($this->fileExists($path)) { - $this->extractFile($path, $tmpFile); - }elseif($mode=='r' or $mode=='rb') { - return false; - } - if($mode=='r' or $mode=='rb') { - return fopen($tmpFile, $mode); - }else{ - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); - } - } - - private static $tempFiles=array(); - /** - * write back temporary files - */ - function writeBack($tmpFile) { - if(isset(self::$tempFiles[$tmpFile])) { - $this->addFile(self::$tempFiles[$tmpFile], $tmpFile); - unlink($tmpFile); - } - } - - /** - * reopen the archive to ensure everything is written - */ - private function reopen() { - if($this->tar) { - $this->tar->_close(); - $this->tar=null; - } - $types=array(null, 'gz', 'bz'); - $this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]); - } -} diff --git a/lib/archive/zip.php b/lib/archive/zip.php deleted file mode 100644 index 8a866716a79..00000000000 --- a/lib/archive/zip.php +++ /dev/null @@ -1,201 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_Archive_ZIP extends OC_Archive{ - /** - * @var ZipArchive zip - */ - private $zip=null; - private $path; - - function __construct($source) { - $this->path=$source; - $this->zip=new ZipArchive(); - if($this->zip->open($source, ZipArchive::CREATE)) { - }else{ - OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, OCP\Util::WARN); - } - } - /** - * add an empty folder to the archive - * @param string path - * @return bool - */ - function addFolder($path) { - return $this->zip->addEmptyDir($path); - } - /** - * add a file to the archive - * @param string path - * @param string source either a local file or string data - * @return bool - */ - function addFile($path, $source='') { - if($source and $source[0]=='/' and file_exists($source)) { - $result=$this->zip->addFile($source, $path); - }else{ - $result=$this->zip->addFromString($path, $source); - } - if($result) { - $this->zip->close();//close and reopen to save the zip - $this->zip->open($this->path); - } - return $result; - } - /** - * rename a file or folder in the archive - * @param string source - * @param string dest - * @return bool - */ - function rename($source, $dest) { - $source=$this->stripPath($source); - $dest=$this->stripPath($dest); - $this->zip->renameName($source, $dest); - } - /** - * get the uncompressed size of a file in the archive - * @param string path - * @return int - */ - function filesize($path) { - $stat=$this->zip->statName($path); - return $stat['size']; - } - /** - * get the last modified time of a file in the archive - * @param string path - * @return int - */ - function mtime($path) { - return filemtime($this->path); - } - /** - * get the files in a folder - * @param path - * @return array - */ - function getFolder($path) { - $files=$this->getFiles(); - $folderContent=array(); - $pathLength=strlen($path); - foreach($files as $file) { - if(substr($file, 0, $pathLength)==$path and $file!=$path) { - if(strrpos(substr($file, 0, -1), '/')<=$pathLength) { - $folderContent[]=substr($file, $pathLength); - } - } - } - return $folderContent; - } - /** - * get all files in the archive - * @return array - */ - function getFiles() { - $fileCount=$this->zip->numFiles; - $files=array(); - for($i=0;$i<$fileCount;$i++) { - $files[]=$this->zip->getNameIndex($i); - } - return $files; - } - /** - * get the content of a file - * @param string path - * @return string - */ - function getFile($path) { - return $this->zip->getFromName($path); - } - /** - * extract a single file from the archive - * @param string path - * @param string dest - * @return bool - */ - function extractFile($path, $dest) { - $fp = $this->zip->getStream($path); - file_put_contents($dest, $fp); - } - /** - * extract the archive - * @param string path - * @param string dest - * @return bool - */ - function extract($dest) { - return $this->zip->extractTo($dest); - } - /** - * check if a file or folder exists in the archive - * @param string path - * @return bool - */ - function fileExists($path) { - return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false); - } - /** - * remove a file or folder from the archive - * @param string path - * @return bool - */ - function remove($path) { - if($this->fileExists($path.'/')) { - return $this->zip->deleteName($path.'/'); - }else{ - return $this->zip->deleteName($path); - } - } - /** - * get a file handler - * @param string path - * @param string mode - * @return resource - */ - function getStream($path, $mode) { - if($mode=='r' or $mode=='rb') { - return $this->zip->getStream($path); - } else { - //since we cant directly get a writable stream, - //make a temp copy of the file and put it back - //in the archive when the stream is closed - if(strrpos($path, '.')!==false) { - $ext=substr($path, strrpos($path, '.')); - }else{ - $ext=''; - } - $tmpFile=OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - if($this->fileExists($path)) { - $this->extractFile($path, $tmpFile); - } - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); - } - } - - private static $tempFiles=array(); - /** - * write back temporary files - */ - function writeBack($tmpFile) { - if(isset(self::$tempFiles[$tmpFile])) { - $this->addFile(self::$tempFiles[$tmpFile], $tmpFile); - unlink($tmpFile); - } - } - - private function stripPath($path) { - if(!$path || $path[0]=='/') { - return substr($path, 1); - }else{ - return $path; - } - } -} diff --git a/lib/arrayparser.php b/lib/arrayparser.php deleted file mode 100644 index 3bb394a5163..00000000000 --- a/lib/arrayparser.php +++ /dev/null @@ -1,189 +0,0 @@ -. - * - */ - -namespace OC; - -class SyntaxException extends \Exception { -} - -class ArrayParser { - const TYPE_NUM = 1; - const TYPE_BOOL = 2; - const TYPE_STRING = 3; - const TYPE_ARRAY = 4; - - function parsePHP($string) { - $string = $this->stripPHPTags($string); - $string = $this->stripAssignAndReturn($string); - return $this->parse($string); - } - - function stripPHPTags($string) { - $string = trim($string); - if (substr($string, 0, 5) === '') { - $string = substr($string, 0, -2); - } - return $string; - } - - function stripAssignAndReturn($string) { - $string = trim($string); - if (substr($string, 0, 6) === 'return') { - $string = substr($string, 6); - } - if (substr($string, 0, 1) === '$') { - list(, $string) = explode('=', $string, 2); - } - return $string; - } - - function parse($string) { - $string = trim($string); - $string = trim($string, ';'); - switch ($this->getType($string)) { - case self::TYPE_NUM: - return $this->parseNum($string); - case self::TYPE_BOOL: - return $this->parseBool($string); - case self::TYPE_STRING: - return $this->parseString($string); - case self::TYPE_ARRAY: - return $this->parseArray($string); - } - return null; - } - - function getType($string) { - $string = strtolower($string); - $first = substr($string, 0, 1); - $last = substr($string, -1, 1); - $arrayFirst = substr($string, 0, 5); - if (($first === '"' or $first === "'") and ($last === '"' or $last === "'")) { - return self::TYPE_STRING; - } elseif ($string === 'false' or $string === 'true') { - return self::TYPE_BOOL; - } elseif ($arrayFirst === 'array' and $last === ')') { - return self::TYPE_ARRAY; - } else { - return self::TYPE_NUM; - } - } - - function parseString($string) { - return substr($string, 1, -1); - } - - function parseNum($string) { - return intval($string); - } - - function parseBool($string) { - $string = strtolower($string); - return $string === 'true'; - } - - function parseArray($string) { - $body = substr($string, 5); - $body = trim($body); - $body = substr($body, 1, -1); - $items = $this->splitArray($body); - $result = array(); - $lastKey = -1; - foreach ($items as $item) { - $item = trim($item); - if ($item) { - if (strpos($item, '=>')) { - list($key, $value) = explode('=>', $item, 2); - $key = $this->parse($key); - $value = $this->parse($value); - } else { - $key = ++$lastKey; - $value = $item; - } - - if (is_numeric($key)) { - $lastKey = $key; - } - $result[$key] = $value; - } - } - return $result; - } - - function splitArray($body) { - $inSingleQuote = false;//keep track if we are inside quotes - $inDoubleQuote = false; - $bracketDepth = 0;//keep track if we are inside brackets - $parts = array(); - $start = 0; - $escaped = false;//keep track if we are after an escape character - $skips = array();//keep track of the escape characters we need to remove from the result - if (substr($body, -1, 1) !== ',') { - $body .= ','; - } - for ($i = 0; $i < strlen($body); $i++) { - $char = substr($body, $i, 1); - if ($char === '\\') { - if ($escaped) { - array_unshift($skips, $i - 1); - } - $escaped = !$escaped; - } else { - if ($char === '"' and !$inSingleQuote) { - if ($escaped) { - array_unshift($skips, $i - 1); - } else { - $inDoubleQuote = !$inDoubleQuote; - } - } elseif ($char === "'" and !$inDoubleQuote) { - if ($escaped) { - array_unshift($skips, $i - 1); - } else { - $inSingleQuote = !$inSingleQuote; - } - } elseif (!$inDoubleQuote and !$inSingleQuote) { - if ($char === '(') { - $bracketDepth++; - } elseif ($char === ')') { - if ($bracketDepth <= 0) { - throw new SyntaxException; - } else { - $bracketDepth--; - } - } elseif ($bracketDepth === 0 and $char === ',') { - $part = substr($body, $start, $i - $start); - foreach ($skips as $skip) { - $part = substr($part, 0, $skip - $start) . substr($part, $skip - $start + 1); - } - $parts[] = $part; - $start = $i + 1; - $skips = array(); - } - } - $escaped = false; - } - } - return $parts; - } -} diff --git a/lib/autoloader.php b/lib/autoloader.php index 01841f831be..72041200116 100644 --- a/lib/autoloader.php +++ b/lib/autoloader.php @@ -73,10 +73,10 @@ class Autoloader { } } elseif (strpos($class, 'OC_') === 0) { // first check for legacy classes if underscores are used - $paths[] = 'legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); - $paths[] = strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); + $paths[] = 'private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); + $paths[] = 'private/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); } elseif (strpos($class, 'OC\\') === 0) { - $paths[] = strtolower(str_replace('\\', '/', substr($class, 3)) . '.php'); + $paths[] = 'private/' . strtolower(str_replace('\\', '/', substr($class, 3)) . '.php'); } elseif (strpos($class, 'OCP\\') === 0) { $paths[] = 'public/' . strtolower(str_replace('\\', '/', substr($class, 4)) . '.php'); } elseif (strpos($class, 'OCA\\') === 0) { diff --git a/lib/avatar.php b/lib/avatar.php deleted file mode 100644 index f20980c364b..00000000000 --- a/lib/avatar.php +++ /dev/null @@ -1,89 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * This class gets and sets users avatars. - */ - -class OC_Avatar { - - private $view; - - /** - * @brief constructor - * @param $user string user to do avatar-management with - */ - public function __construct ($user) { - $this->view = new \OC\Files\View('/'.$user); - } - - /** - * @brief get the users avatar - * @param $size integer size in px of the avatar, defaults to 64 - * @return boolean|\OC_Image containing the avatar or false if there's no image - */ - public function get ($size = 64) { - if ($this->view->file_exists('avatar.jpg')) { - $ext = 'jpg'; - } elseif ($this->view->file_exists('avatar.png')) { - $ext = 'png'; - } else { - return false; - } - - $avatar = new OC_Image(); - $avatar->loadFromData($this->view->file_get_contents('avatar.'.$ext)); - $avatar->resize($size); - return $avatar; - } - - /** - * @brief sets the users avatar - * @param $data mixed imagedata or path to set a new avatar - * @throws Exception if the provided file is not a jpg or png image - * @throws Exception if the provided image is not valid - * @throws \OC\NotSquareException if the image is not square - * @return void - */ - public function set ($data) { - if (\OC_App::isEnabled('files_encryption')) { - $l = \OC_L10N::get('lib'); - throw new \Exception($l->t("Custom profile pictures don't work with encryption yet")); - } - - $img = new OC_Image($data); - $type = substr($img->mimeType(), -3); - if ($type === 'peg') { $type = 'jpg'; } - if ($type !== 'jpg' && $type !== 'png') { - $l = \OC_L10N::get('lib'); - throw new \Exception($l->t("Unknown filetype")); - } - - if (!$img->valid()) { - $l = \OC_L10N::get('lib'); - throw new \Exception($l->t("Invalid image")); - } - - if (!($img->height() === $img->width())) { - throw new \OC\NotSquareException(); - } - - $this->view->unlink('avatar.jpg'); - $this->view->unlink('avatar.png'); - $this->view->file_put_contents('avatar.'.$type, $data); - } - - /** - * @brief remove the users avatar - * @return void - */ - public function remove () { - $this->view->unlink('avatar.jpg'); - $this->view->unlink('avatar.png'); - } -} diff --git a/lib/backgroundjob.php b/lib/backgroundjob.php deleted file mode 100644 index 9619dcb732c..00000000000 --- a/lib/backgroundjob.php +++ /dev/null @@ -1,52 +0,0 @@ -. -* -*/ - -/** - * This class does the dirty work. - */ -class OC_BackgroundJob{ - /** - * @brief get the execution type of background jobs - * @return string - * - * This method returns the type how background jobs are executed. If the user - * did not select something, the type is ajax. - */ - public static function getExecutionType() { - return OC_Appconfig::getValue( 'core', 'backgroundjobs_mode', 'ajax' ); - } - - /** - * @brief sets the background jobs execution type - * @param $type execution type - * @return boolean - * - * This method sets the execution type of the background jobs. Possible types - * are "none", "ajax", "webcron", "cron" - */ - public static function setExecutionType( $type ) { - if( !in_array( $type, array('none', 'ajax', 'webcron', 'cron'))) { - return false; - } - return OC_Appconfig::setValue( 'core', 'backgroundjobs_mode', $type ); - } -} diff --git a/lib/backgroundjob/job.php b/lib/backgroundjob/job.php deleted file mode 100644 index 49fbffbd684..00000000000 --- a/lib/backgroundjob/job.php +++ /dev/null @@ -1,49 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\BackgroundJob; - -abstract class Job { - protected $id; - protected $lastRun; - protected $argument; - - /** - * @param JobList $jobList - */ - public function execute($jobList) { - $jobList->setLastRun($this); - $this->run($this->argument); - } - - abstract protected function run($argument); - - public function setId($id) { - $this->id = $id; - } - - public function setLastRun($lastRun) { - $this->lastRun = $lastRun; - } - - public function setArgument($argument) { - $this->argument = $argument; - } - - public function getId() { - return $this->id; - } - - public function getLastRun() { - return $this->lastRun; - } - - public function getArgument() { - return $this->argument; - } -} diff --git a/lib/backgroundjob/joblist.php b/lib/backgroundjob/joblist.php deleted file mode 100644 index cc803dd9b5f..00000000000 --- a/lib/backgroundjob/joblist.php +++ /dev/null @@ -1,172 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\BackgroundJob; - -/** - * Class QueuedJob - * - * create a background job that is to be executed once - * - * @package OC\BackgroundJob - */ -class JobList { - /** - * @param Job|string $job - * @param mixed $argument - */ - public function add($job, $argument = null) { - if (!$this->has($job, $argument)) { - if ($job instanceof Job) { - $class = get_class($job); - } else { - $class = $job; - } - $argument = json_encode($argument); - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)'); - $query->execute(array($class, $argument)); - } - } - - /** - * @param Job|string $job - * @param mixed $argument - */ - public function remove($job, $argument = null) { - if ($job instanceof Job) { - $class = get_class($job); - } else { - $class = $job; - } - if (!is_null($argument)) { - $argument = json_encode($argument); - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); - $query->execute(array($class, $argument)); - } else { - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?'); - $query->execute(array($class)); - } - } - - /** - * check if a job is in the list - * - * @param $job - * @param mixed $argument - * @return bool - */ - public function has($job, $argument) { - if ($job instanceof Job) { - $class = get_class($job); - } else { - $class = $job; - } - $argument = json_encode($argument); - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); - $result = $query->execute(array($class, $argument)); - return (bool)$result->fetchRow(); - } - - /** - * get all jobs in the list - * - * @return Job[] - */ - public function getAll() { - $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`'); - $result = $query->execute(); - $jobs = array(); - while ($row = $result->fetchRow()) { - $jobs[] = $this->buildJob($row); - } - return $jobs; - } - - /** - * get the next job in the list - * - * @return Job - */ - public function getNext() { - $lastId = $this->getLastJob(); - $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1); - $result = $query->execute(array($lastId)); - if ($row = $result->fetchRow()) { - return $this->buildJob($row); - } else { - //begin at the start of the queue - $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1); - $result = $query->execute(); - if ($row = $result->fetchRow()) { - return $this->buildJob($row); - } else { - return null; //empty job list - } - } - } - - /** - * @param int $id - * @return Job - */ - public function getById($id) { - $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?'); - $result = $query->execute(array($id)); - if ($row = $result->fetchRow()) { - return $this->buildJob($row); - } else { - return null; - } - } - - /** - * get the job object from a row in the db - * - * @param array $row - * @return Job - */ - private function buildJob($row) { - $class = $row['class']; - /** - * @var Job $job - */ - $job = new $class(); - $job->setId($row['id']); - $job->setLastRun($row['last_run']); - $job->setArgument(json_decode($row['argument'])); - return $job; - } - - /** - * set the job that was last ran - * - * @param Job $job - */ - public function setLastJob($job) { - \OC_Appconfig::setValue('backgroundjob', 'lastjob', $job->getId()); - } - - /** - * get the id of the last ran job - * - * @return int - */ - public function getLastJob() { - return \OC_Appconfig::getValue('backgroundjob', 'lastjob', 0); - } - - /** - * set the lastRun of $job to now - * - * @param Job $job - */ - public function setLastRun($job) { - $query = \OC_DB::prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?'); - $query->execute(array(time(), $job->getId())); - } -} diff --git a/lib/backgroundjob/legacy/queuedjob.php b/lib/backgroundjob/legacy/queuedjob.php deleted file mode 100644 index 2bc001103b8..00000000000 --- a/lib/backgroundjob/legacy/queuedjob.php +++ /dev/null @@ -1,18 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\BackgroundJob\Legacy; - -class QueuedJob extends \OC\BackgroundJob\QueuedJob { - public function run($argument) { - $class = $argument['klass']; - $method = $argument['method']; - $parameters = $argument['parameters']; - call_user_func(array($class, $method), $parameters); - } -} diff --git a/lib/backgroundjob/legacy/regularjob.php b/lib/backgroundjob/legacy/regularjob.php deleted file mode 100644 index d4cfa348cea..00000000000 --- a/lib/backgroundjob/legacy/regularjob.php +++ /dev/null @@ -1,15 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\BackgroundJob\Legacy; - -class RegularJob extends \OC\BackgroundJob\Job { - public function run($argument) { - call_user_func($argument); - } -} diff --git a/lib/backgroundjob/queuedjob.php b/lib/backgroundjob/queuedjob.php deleted file mode 100644 index 1714182820d..00000000000 --- a/lib/backgroundjob/queuedjob.php +++ /dev/null @@ -1,28 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\BackgroundJob; - -/** - * Class QueuedJob - * - * create a background job that is to be executed once - * - * @package OC\BackgroundJob - */ -abstract class QueuedJob extends Job { - /** - * run the job, then remove it from the joblist - * - * @param JobList $jobList - */ - public function execute($jobList) { - $jobList->remove($this); - $this->run($this->argument); - } -} diff --git a/lib/backgroundjob/timedjob.php b/lib/backgroundjob/timedjob.php deleted file mode 100644 index ae9f33505ab..00000000000 --- a/lib/backgroundjob/timedjob.php +++ /dev/null @@ -1,41 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\BackgroundJob; - -/** - * Class QueuedJob - * - * create a background job that is to be executed at an interval - * - * @package OC\BackgroundJob - */ -abstract class TimedJob extends Job { - protected $interval = 0; - - /** - * set the interval for the job - * - * @param int $interval - */ - public function setInterval($interval) { - $this->interval = $interval; - } - - /** - * run the job if - * - * @param JobList $jobList - */ - public function execute($jobList) { - if ((time() - $this->lastRun) > $this->interval) { - $jobList->setLastRun($this); - $this->run($this->argument); - } - } -} diff --git a/lib/base.php b/lib/base.php index 58894be03ee..7e237c35d27 100644 --- a/lib/base.php +++ b/lib/base.php @@ -164,7 +164,7 @@ class OC { // set the right include path set_include_path( - OC::$SERVERROOT . '/lib' . PATH_SEPARATOR . + OC::$SERVERROOT . '/lib/private' . PATH_SEPARATOR . OC::$SERVERROOT . '/config' . PATH_SEPARATOR . OC::$THIRDPARTYROOT . '/3rdparty' . PATH_SEPARATOR . implode($paths, PATH_SEPARATOR) . PATH_SEPARATOR . diff --git a/lib/cache.php b/lib/cache.php deleted file mode 100644 index a311f10a00f..00000000000 --- a/lib/cache.php +++ /dev/null @@ -1,112 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC; - -class Cache { - /** - * @var Cache $user_cache - */ - static protected $user_cache; - /** - * @var Cache $global_cache - */ - static protected $global_cache; - - /** - * get the global cache - * @return Cache - */ - static public function getGlobalCache() { - if (!self::$global_cache) { - self::$global_cache = new Cache\FileGlobal(); - } - return self::$global_cache; - } - - /** - * get the user cache - * @return Cache - */ - static public function getUserCache() { - if (!self::$user_cache) { - self::$user_cache = new Cache\File(); - } - return self::$user_cache; - } - - /** - * get a value from the user cache - * @param string $key - * @return mixed - */ - static public function get($key) { - $user_cache = self::getUserCache(); - return $user_cache->get($key); - } - - /** - * set a value in the user cache - * @param string $key - * @param mixed $value - * @param int $ttl - * @return bool - */ - static public function set($key, $value, $ttl=0) { - if (empty($key)) { - return false; - } - $user_cache = self::getUserCache(); - return $user_cache->set($key, $value, $ttl); - } - - /** - * check if a value is set in the user cache - * @param string $key - * @return bool - */ - static public function hasKey($key) { - $user_cache = self::getUserCache(); - return $user_cache->hasKey($key); - } - - /** - * remove an item from the user cache - * @param string $key - * @return bool - */ - static public function remove($key) { - $user_cache = self::getUserCache(); - return $user_cache->remove($key); - } - - /** - * clear the user cache of all entries starting with a prefix - * @param string $prefix (optional) - * @return bool - */ - static public function clear($prefix='') { - $user_cache = self::getUserCache(); - return $user_cache->clear($prefix); - } - - /** - * creates cache key based on the files given - * @param $files - * @return string - */ - static public function generateCacheKeyFromFiles($files) { - $key = ''; - sort($files); - foreach($files as $file) { - $stat = stat($file); - $key .= $file.$stat['mtime'].$stat['size']; - } - return md5($key); - } -} diff --git a/lib/cache/broker.php b/lib/cache/broker.php deleted file mode 100644 index 9b7e837e1bc..00000000000 --- a/lib/cache/broker.php +++ /dev/null @@ -1,63 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Cache; - -class Broker { - - /** - * @var \OC\Cache - */ - protected $fast_cache; - - /** - * @var \OC\Cache - */ - protected $slow_cache; - - public function __construct($fast_cache, $slow_cache) { - $this->fast_cache = $fast_cache; - $this->slow_cache = $slow_cache; - } - - public function get($key) { - if ($r = $this->fast_cache->get($key)) { - return $r; - } - return $this->slow_cache->get($key); - } - - public function set($key, $value, $ttl=0) { - if (!$this->fast_cache->set($key, $value, $ttl)) { - if ($this->fast_cache->hasKey($key)) { - $this->fast_cache->remove($key); - } - return $this->slow_cache->set($key, $value, $ttl); - } - return true; - } - - public function hasKey($key) { - if ($this->fast_cache->hasKey($key)) { - return true; - } - return $this->slow_cache->hasKey($key); - } - - public function remove($key) { - if ($this->fast_cache->remove($key)) { - return true; - } - return $this->slow_cache->remove($key); - } - - public function clear($prefix='') { - $this->fast_cache->clear($prefix); - $this->slow_cache->clear($prefix); - } -} diff --git a/lib/cache/file.php b/lib/cache/file.php deleted file mode 100644 index 2ab914d17b8..00000000000 --- a/lib/cache/file.php +++ /dev/null @@ -1,118 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Cache; - -class File { - protected $storage; - protected function getStorage() { - if (isset($this->storage)) { - return $this->storage; - } - if(\OC_User::isLoggedIn()) { - \OC\Files\Filesystem::initMountPoints(\OC_User::getUser()); - $subdir = 'cache'; - $view = new \OC\Files\View('/' . \OC_User::getUser()); - if(!$view->file_exists($subdir)) { - $view->mkdir($subdir); - } - $this->storage = new \OC\Files\View('/' . \OC_User::getUser().'/'.$subdir); - return $this->storage; - }else{ - \OC_Log::write('core', 'Can\'t get cache storage, user not logged in', \OC_Log::ERROR); - return false; - } - } - - public function get($key) { - $result = null; - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - if ($this->hasKey($key)) { - $storage = $this->getStorage(); - $result = $storage->file_get_contents($key); - } - \OC_FileProxy::$enabled = $proxyStatus; - return $result; - } - - public function set($key, $value, $ttl=0) { - $storage = $this->getStorage(); - $result = false; - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - if ($storage and $storage->file_put_contents($key, $value)) { - if ($ttl === 0) { - $ttl = 86400; // 60*60*24 - } - $result = $storage->touch($key, time() + $ttl); - } - \OC_FileProxy::$enabled = $proxyStatus; - return $result; - } - - public function hasKey($key) { - $storage = $this->getStorage(); - if ($storage && $storage->is_file($key)) { - $mtime = $storage->filemtime($key); - if ($mtime < time()) { - $storage->unlink($key); - return false; - } - return true; - } - return false; - } - - public function remove($key) { - $storage = $this->getStorage(); - if(!$storage) { - return false; - } - return $storage->unlink($key); - } - - public function clear($prefix='') { - $storage = $this->getStorage(); - if($storage and $storage->is_dir('/')) { - $dh=$storage->opendir('/'); - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) { - $storage->unlink('/'.$file); - } - } - } - } - return true; - } - - public function gc() { - $storage = $this->getStorage(); - if($storage and $storage->is_dir('/')) { - $now = time(); - $dh=$storage->opendir('/'); - if(!is_resource($dh)) { - return null; - } - while (($file = readdir($dh)) !== false) { - if($file!='.' and $file!='..') { - $mtime = $storage->filemtime('/'.$file); - if ($mtime < $now) { - $storage->unlink('/'.$file); - } - } - } - } - } - - public static function loginListener() { - $c = new self(); - $c->gc(); - } -} diff --git a/lib/cache/fileglobal.php b/lib/cache/fileglobal.php deleted file mode 100644 index bd049bba4d0..00000000000 --- a/lib/cache/fileglobal.php +++ /dev/null @@ -1,106 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Cache; - -class FileGlobal { - static protected function getCacheDir() { - $cache_dir = get_temp_dir().'/owncloud-' . \OC_Util::getInstanceId().'/'; - if (!is_dir($cache_dir)) { - mkdir($cache_dir); - } - return $cache_dir; - } - - protected function fixKey($key) { - return str_replace('/', '_', $key); - } - - public function get($key) { - $key = $this->fixKey($key); - if ($this->hasKey($key)) { - $cache_dir = self::getCacheDir(); - return file_get_contents($cache_dir.$key); - } - return null; - } - - public function set($key, $value, $ttl=0) { - $key = $this->fixKey($key); - $cache_dir = self::getCacheDir(); - if ($cache_dir and file_put_contents($cache_dir.$key, $value)) { - if ($ttl === 0) { - $ttl = 86400; // 60*60*24 - } - return touch($cache_dir.$key, time() + $ttl); - } - return false; - } - - public function hasKey($key) { - $key = $this->fixKey($key); - $cache_dir = self::getCacheDir(); - if ($cache_dir && is_file($cache_dir.$key)) { - $mtime = filemtime($cache_dir.$key); - if ($mtime < time()) { - unlink($cache_dir.$key); - return false; - } - return true; - } - return false; - } - - public function remove($key) { - $cache_dir = self::getCacheDir(); - if(!$cache_dir) { - return false; - } - $key = $this->fixKey($key); - return unlink($cache_dir.$key); - } - - public function clear($prefix='') { - $cache_dir = self::getCacheDir(); - $prefix = $this->fixKey($prefix); - if($cache_dir and is_dir($cache_dir)) { - $dh=opendir($cache_dir); - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) { - unlink($cache_dir.$file); - } - } - } - } - } - - static public function gc() { - $last_run = \OC_AppConfig::getValue('core', 'global_cache_gc_lastrun', 0); - $now = time(); - if (($now - $last_run) < 300) { - // only do cleanup every 5 minutes - return; - } - \OC_AppConfig::setValue('core', 'global_cache_gc_lastrun', $now); - $cache_dir = self::getCacheDir(); - if($cache_dir and is_dir($cache_dir)) { - $dh=opendir($cache_dir); - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if($file!='.' and $file!='..') { - $mtime = filemtime($cache_dir.$file); - if ($mtime < $now) { - unlink($cache_dir.$file); - } - } - } - } - } - } -} diff --git a/lib/cache/fileglobalgc.php b/lib/cache/fileglobalgc.php deleted file mode 100644 index 399dd5e6f94..00000000000 --- a/lib/cache/fileglobalgc.php +++ /dev/null @@ -1,9 +0,0 @@ -userCache = new File(); - } - - /** - * Get a value from the user cache - * - * @param string $key - * @return mixed - */ - public function get($key) { - return $this->userCache->get($key); - } - - /** - * Set a value in the user cache - * - * @param string $key - * @param mixed $value - * @param int $ttl Time To Live in seconds. Defaults to 60*60*24 - * @return bool - */ - public function set($key, $value, $ttl = 0) { - if (empty($key)) { - return false; - } - return $this->userCache->set($key, $value, $ttl); - } - - /** - * Check if a value is set in the user cache - * - * @param string $key - * @return bool - */ - public function hasKey($key) { - return $this->userCache->hasKey($key); - } - - /** - * Remove an item from the user cache - * - * @param string $key - * @return bool - */ - public function remove($key) { - return $this->userCache->remove($key); - } - - /** - * clear the user cache of all entries starting with a prefix - * @param string $prefix (optional) - * @return bool - */ - public function clear($prefix = '') { - return $this->userCache->clear($prefix); - } -} diff --git a/lib/config.php b/lib/config.php deleted file mode 100644 index e773e6e2eb0..00000000000 --- a/lib/config.php +++ /dev/null @@ -1,186 +0,0 @@ -. - * - */ -/* - * - * An example of config.php - * - * "mysql", - * "firstrun" => false, - * "pi" => 3.14 - * ); - * ?> - * - */ - -namespace OC; - -/** - * This class is responsible for reading and writing config.php, the very basic - * configuration file of ownCloud. - */ -class Config { - // associative array key => value - protected $cache = array(); - - protected $configDir; - protected $configFilename; - - protected $debugMode; - - /** - * @param $configDir path to the config dir, needs to end with '/' - */ - public function __construct($configDir) { - $this->configDir = $configDir; - $this->configFilename = $this->configDir.'config.php'; - $this->readData(); - $this->setDebugMode(defined('DEBUG') && DEBUG); - } - - public function setDebugMode($enable) { - $this->debugMode = $enable; - } - - /** - * @brief Lists all available config keys - * @return array with key names - * - * This function returns all keys saved in config.php. Please note that it - * does not return the values. - */ - public function getKeys() { - return array_keys($this->cache); - } - - /** - * @brief Gets a value from config.php - * @param string $key key - * @param string $default = null default value - * @return string the value or $default - * - * This function gets the value from config.php. If it does not exist, - * $default will be returned. - */ - public function getValue($key, $default = null) { - if (isset($this->cache[$key])) { - return $this->cache[$key]; - } - - return $default; - } - - /** - * @brief Sets a value - * @param string $key key - * @param string $value value - * - * This function sets the value and writes the config.php. - * - */ - public function setValue($key, $value) { - // Add change - $this->cache[$key] = $value; - - // Write changes - $this->writeData(); - } - - /** - * @brief Removes a key from the config - * @param string $key key - * - * This function removes a key from the config.php. - * - */ - public function deleteKey($key) { - if (isset($this->cache[$key])) { - // Delete key from cache - unset($this->cache[$key]); - - // Write changes - $this->writeData(); - } - } - - /** - * @brief Loads the config file - * - * Reads the config file and saves it to the cache - */ - private function readData() { - // Default config - $configFiles = array($this->configFilename); - // Add all files in the config dir ending with config.php - $extra = glob($this->configDir.'*.config.php'); - if (is_array($extra)) { - natsort($extra); - $configFiles = array_merge($configFiles, $extra); - } - // Include file and merge config - foreach ($configFiles as $file) { - if (!file_exists($file)) { - continue; - } - unset($CONFIG); - // ignore errors on include, this can happen when doing a fresh install - @include $file; - if (isset($CONFIG) && is_array($CONFIG)) { - $this->cache = array_merge($this->cache, $CONFIG); - } - } - } - - /** - * @brief Writes the config file - * - * Saves the config to the config file. - * - */ - private function writeData() { - // Create a php file ... - $defaults = new \OC_Defaults; - $content = "debugMode) { - $content .= "define('DEBUG',true);\n"; - } - $content .= '$CONFIG = '; - $content .= var_export($this->cache, true); - $content .= ";\n"; - - // Write the file - $result = @file_put_contents($this->configFilename, $content); - if (!$result) { - $url = $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html#set-the-directory-permissions'; - throw new HintException( - "Can't write into config directory!", - 'This can usually be fixed by ' - .'giving the webserver write access to the config directory.'); - } - // Prevent others not to read the config - @chmod($this->configFilename, 0640); - \OC_Util::clearOpcodeCache(); - } -} - diff --git a/lib/connector/sabre/ServiceUnavailable.php b/lib/connector/sabre/ServiceUnavailable.php deleted file mode 100644 index c1cc815c989..00000000000 --- a/lib/connector/sabre/ServiceUnavailable.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * @license AGPL3 - */ - -class Sabre_DAV_Exception_ServiceUnavailable extends Sabre_DAV_Exception { - - /** - * Returns the HTTP statuscode for this exception - * - * @return int - */ - public function getHTTPCode() { - - return 503; - } -} diff --git a/lib/connector/sabre/auth.php b/lib/connector/sabre/auth.php deleted file mode 100644 index bf3a49593cb..00000000000 --- a/lib/connector/sabre/auth.php +++ /dev/null @@ -1,84 +0,0 @@ -. - * - */ - -class OC_Connector_Sabre_Auth extends Sabre_DAV_Auth_Backend_AbstractBasic { - /** - * Validates a username and password - * - * This method should return true or false depending on if login - * succeeded. - * - * @return bool - */ - protected function validateUserPass($username, $password) { - if (OC_User::isLoggedIn()) { - OC_Util::setupFS(OC_User::getUser()); - return true; - } else { - OC_Util::setUpFS();//login hooks may need early access to the filesystem - if(OC_User::login($username, $password)) { - OC_Util::setUpFS(OC_User::getUser()); - return true; - } - else{ - return false; - } - } - } - - /** - * Returns information about the currently logged in username. - * - * If nobody is currently logged in, this method should return null. - * - * @return string|null - */ - public function getCurrentUser() { - $user = OC_User::getUser(); - if(!$user) { - return null; - } - return $user; - } - - /** - * Override function here. We want to cache authentication cookies - * in the syncing client to avoid HTTP-401 roundtrips. - * If the sync client supplies the cookies, then OC_User::isLoggedIn() - * will return true and we can see this WebDAV request as already authenticated, - * even if there are no HTTP Basic Auth headers. - * In other case, just fallback to the parent implementation. - * - * @return bool - */ - public function authenticate(Sabre_DAV_Server $server, $realm) { - if (OC_User::isLoggedIn()) { - $user = OC_User::getUser(); - OC_Util::setupFS($user); - $this->currentUser = $user; - return true; - } - - return parent::authenticate($server, $realm); - } -} diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php deleted file mode 100644 index 382bdf06df1..00000000000 --- a/lib/connector/sabre/directory.php +++ /dev/null @@ -1,256 +0,0 @@ -. - * - */ - -class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sabre_DAV_ICollection, Sabre_DAV_IQuota { - - /** - * Creates a new file in the directory - * - * Data will either be supplied as a stream resource, or in certain cases - * as a string. Keep in mind that you may have to support either. - * - * After succesful creation of the file, you may choose to return the ETag - * of the new file here. - * - * The returned ETag must be surrounded by double-quotes (The quotes should - * be part of the actual string). - * - * If you cannot accurately determine the ETag, you should not return it. - * If you don't store the file exactly as-is (you're transforming it - * somehow) you should also not return an ETag. - * - * This means that if a subsequent GET to this new file does not exactly - * return the same contents of what was submitted here, you are strongly - * recommended to omit the ETag. - * - * @param string $name Name of the file - * @param resource|string $data Initial payload - * @throws Sabre_DAV_Exception_Forbidden - * @return null|string - */ - public function createFile($name, $data = null) { - - if (!\OC\Files\Filesystem::isCreatable($this->path)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - - if (isset($_SERVER['HTTP_OC_CHUNKED'])) { - $info = OC_FileChunking::decodeName($name); - if (empty($info)) { - throw new Sabre_DAV_Exception_NotImplemented(); - } - $chunk_handler = new OC_FileChunking($info); - $chunk_handler->store($info['index'], $data); - if ($chunk_handler->isComplete()) { - $newPath = $this->path . '/' . $info['name']; - $chunk_handler->file_assemble($newPath); - return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); - } - } else { - $newPath = $this->path . '/' . $name; - - // mark file as partial while uploading (ignored by the scanner) - $partpath = $newPath . '.part'; - - \OC\Files\Filesystem::file_put_contents($partpath, $data); - - // rename to correct path - $renameOkay = \OC\Files\Filesystem::rename($partpath, $newPath); - $fileExists = \OC\Files\Filesystem::file_exists($newPath); - if ($renameOkay === false || $fileExists === false) { - \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); - \OC\Files\Filesystem::unlink($partpath); - throw new Sabre_DAV_Exception(); - } - - // allow sync clients to send the mtime along in a header - $mtime = OC_Request::hasModificationTime(); - if ($mtime !== false) { - if(\OC\Files\Filesystem::touch($newPath, $mtime)) { - header('X-OC-MTime: accepted'); - } - } - - return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); - } - - return null; - } - - /** - * Creates a new subdirectory - * - * @param string $name - * @throws Sabre_DAV_Exception_Forbidden - * @return void - */ - public function createDirectory($name) { - - if (!\OC\Files\Filesystem::isCreatable($this->path)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - - $newPath = $this->path . '/' . $name; - if(!\OC\Files\Filesystem::mkdir($newPath)) { - throw new Sabre_DAV_Exception_Forbidden('Could not create directory '.$newPath); - } - - } - - /** - * Returns a specific child node, referenced by its name - * - * @param string $name - * @throws Sabre_DAV_Exception_FileNotFound - * @return Sabre_DAV_INode - */ - public function getChild($name, $info = null) { - - $path = $this->path . '/' . $name; - if (is_null($info)) { - $info = \OC\Files\Filesystem::getFileInfo($path); - } - - if (!$info) { - throw new Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); - } - - if ($info['mimetype'] == 'httpd/unix-directory') { - $node = new OC_Connector_Sabre_Directory($path); - } else { - $node = new OC_Connector_Sabre_File($path); - } - - $node->setFileinfoCache($info); - return $node; - } - - /** - * Returns an array with all the child nodes - * - * @return Sabre_DAV_INode[] - */ - public function getChildren() { - - $folder_content = \OC\Files\Filesystem::getDirectoryContent($this->path); - $paths = array(); - foreach($folder_content as $info) { - $paths[] = $this->path.'/'.$info['name']; - $properties[$this->path.'/'.$info['name']][self::GETETAG_PROPERTYNAME] = '"' . $info['etag'] . '"'; - } - if(count($paths)>0) { - // - // the number of arguments within IN conditions are limited in most databases - // we chunk $paths into arrays of 200 items each to meet this criteria - // - $chunks = array_chunk($paths, 200, false); - foreach ($chunks as $pack) { - $placeholders = join(',', array_fill(0, count($pack), '?')); - $query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*properties`' - .' WHERE `userid` = ?' . ' AND `propertypath` IN ('.$placeholders.')' ); - array_unshift($pack, OC_User::getUser()); // prepend userid - $result = $query->execute( $pack ); - while($row = $result->fetchRow()) { - $propertypath = $row['propertypath']; - $propertyname = $row['propertyname']; - $propertyvalue = $row['propertyvalue']; - if($propertyname !== self::GETETAG_PROPERTYNAME) { - $properties[$propertypath][$propertyname] = $propertyvalue; - } - } - } - } - - $nodes = array(); - foreach($folder_content as $info) { - $node = $this->getChild($info['name'], $info); - $node->setPropertyCache($properties[$this->path.'/'.$info['name']]); - $nodes[] = $node; - } - return $nodes; - } - - /** - * Checks if a child exists. - * - * @param string $name - * @return bool - */ - public function childExists($name) { - - $path = $this->path . '/' . $name; - return \OC\Files\Filesystem::file_exists($path); - - } - - /** - * Deletes all files in this directory, and then itself - * - * @return void - * @throws Sabre_DAV_Exception_Forbidden - */ - public function delete() { - - if (!\OC\Files\Filesystem::isDeletable($this->path)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - if ($this->path != "/Shared") { - \OC\Files\Filesystem::rmdir($this->path); - } - - } - - /** - * Returns available diskspace information - * - * @return array - */ - public function getQuotaInfo() { - $storageInfo = OC_Helper::getStorageInfo($this->path); - return array( - $storageInfo['used'], - $storageInfo['free'] - ); - - } - - /** - * Returns a list of properties for this nodes.; - * - * The properties list is a list of propertynames the client requested, - * encoded as xmlnamespace#tagName, for example: - * http://www.example.org/namespace#author - * If the array is empty, all properties should be returned - * - * @param array $properties - * @return void - */ - public function getProperties($properties) { - $props = parent::getProperties($properties); - if (in_array(self::GETETAG_PROPERTYNAME, $properties) && !isset($props[self::GETETAG_PROPERTYNAME])) { - $props[self::GETETAG_PROPERTYNAME] - = OC_Connector_Sabre_Node::getETagPropertyForPath($this->path); - } - return $props; - } -} diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php deleted file mode 100644 index 433b1148552..00000000000 --- a/lib/connector/sabre/file.php +++ /dev/null @@ -1,176 +0,0 @@ -. - * - */ - -class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_DAV_IFile { - - /** - * Updates the data - * - * The data argument is a readable stream resource. - * - * After a succesful put operation, you may choose to return an ETag. The - * etag must always be surrounded by double-quotes. These quotes must - * appear in the actual string you're returning. - * - * Clients may use the ETag from a PUT request to later on make sure that - * when they update the file, the contents haven't changed in the mean - * time. - * - * If you don't plan to store the file byte-by-byte, and you return a - * different object on a subsequent GET you are strongly recommended to not - * return an ETag, and just return null. - * - * @param resource $data - * @throws Sabre_DAV_Exception_Forbidden - * @return string|null - */ - public function put($data) { - - if (!\OC\Files\Filesystem::isUpdatable($this->path)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - - // throw an exception if encryption was disabled but the files are still encrypted - if (\OC_Util::encryptedFiles()) { - throw new \Sabre_DAV_Exception_ServiceUnavailable(); - } - - // mark file as partial while uploading (ignored by the scanner) - $partpath = $this->path . '.part'; - - \OC\Files\Filesystem::file_put_contents($partpath, $data); - - //detect aborted upload - if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { - if (isset($_SERVER['CONTENT_LENGTH'])) { - $expected = $_SERVER['CONTENT_LENGTH']; - $actual = \OC\Files\Filesystem::filesize($partpath); - if ($actual != $expected) { - \OC\Files\Filesystem::unlink($partpath); - throw new Sabre_DAV_Exception_BadRequest( - 'expected filesize ' . $expected . ' got ' . $actual); - } - } - } - - // rename to correct path - $renameOkay = \OC\Files\Filesystem::rename($partpath, $this->path); - $fileExists = \OC\Files\Filesystem::file_exists($this->path); - if ($renameOkay === false || $fileExists === false) { - \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); - \OC\Files\Filesystem::unlink($partpath); - throw new Sabre_DAV_Exception(); - } - - - //allow sync clients to send the mtime along in a header - $mtime = OC_Request::hasModificationTime(); - if ($mtime !== false) { - if (\OC\Files\Filesystem::touch($this->path, $mtime)) { - header('X-OC-MTime: accepted'); - } - } - - return OC_Connector_Sabre_Node::getETagPropertyForPath($this->path); - } - - /** - * Returns the data - * - * @return string - */ - public function get() { - - //throw execption if encryption is disabled but files are still encrypted - if (\OC_Util::encryptedFiles()) { - throw new \Sabre_DAV_Exception_ServiceUnavailable(); - } else { - return \OC\Files\Filesystem::fopen($this->path, 'rb'); - } - - } - - /** - * Delete the current file - * - * @return void - * @throws Sabre_DAV_Exception_Forbidden - */ - public function delete() { - - if (!\OC\Files\Filesystem::isDeletable($this->path)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - \OC\Files\Filesystem::unlink($this->path); - - } - - /** - * Returns the size of the node, in bytes - * - * @return int - */ - public function getSize() { - $this->getFileinfoCache(); - if ($this->fileinfo_cache['size'] > -1) { - return $this->fileinfo_cache['size']; - } else { - return null; - } - } - - /** - * Returns the ETag for a file - * - * An ETag is a unique identifier representing the current version of the - * file. If the file changes, the ETag MUST change. The ETag is an - * arbritrary string, but MUST be surrounded by double-quotes. - * - * Return null if the ETag can not effectively be determined - * - * @return mixed - */ - public function getETag() { - $properties = $this->getProperties(array(self::GETETAG_PROPERTYNAME)); - if (isset($properties[self::GETETAG_PROPERTYNAME])) { - return $properties[self::GETETAG_PROPERTYNAME]; - } - return null; - } - - /** - * Returns the mime-type for a file - * - * If null is returned, we'll assume application/octet-stream - * - * @return mixed - */ - public function getContentType() { - if (isset($this->fileinfo_cache['mimetype'])) { - return $this->fileinfo_cache['mimetype']; - } - - return \OC\Files\Filesystem::getMimeType($this->path); - - } -} diff --git a/lib/connector/sabre/locks.php b/lib/connector/sabre/locks.php deleted file mode 100644 index 69496c15ada..00000000000 --- a/lib/connector/sabre/locks.php +++ /dev/null @@ -1,189 +0,0 @@ -. - * - */ - -class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract { - - /** - * Returns a list of Sabre_DAV_Locks_LockInfo objects - * - * This method should return all the locks for a particular uri, including - * locks that might be set on a parent uri. - * - * If returnChildLocks is set to true, this method should also look for - * any locks in the subtree of the uri for locks. - * - * @param string $uri - * @param bool $returnChildLocks - * @return array - */ - public function getLocks($uri, $returnChildLocks) { - - // NOTE: the following 10 lines or so could be easily replaced by - // pure sql. MySQL's non-standard string concatination prevents us - // from doing this though. - // NOTE: SQLite requires time() to be inserted directly. That's ugly - // but otherwise reading locks from SQLite Databases will return - // nothing - $query = 'SELECT * FROM `*PREFIX*locks`' - .' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( `uri` = ?)'; - if (OC_Config::getValue( "dbtype") === 'oci') { - //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison - $query = 'SELECT * FROM `*PREFIX*locks`' - .' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( to_char(`uri`) = ?)'; - } - $params = array(OC_User::getUser(), $uri); - - // We need to check locks for every part in the uri. - $uriParts = explode('/', $uri); - - // We already covered the last part of the uri - array_pop($uriParts); - - $currentPath=''; - - foreach($uriParts as $part) { - - if ($currentPath) $currentPath.='/'; - $currentPath.=$part; - //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison - if (OC_Config::getValue( "dbtype") === 'oci') { - $query.=' OR (`depth` != 0 AND to_char(`uri`) = ?)'; - } else { - $query.=' OR (`depth` != 0 AND `uri` = ?)'; - } - $params[] = $currentPath; - - } - - if ($returnChildLocks) { - - //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison - if (OC_Config::getValue( "dbtype") === 'oci') { - $query.=' OR (to_char(`uri`) LIKE ?)'; - } else { - $query.=' OR (`uri` LIKE ?)'; - } - $params[] = $uri . '/%'; - - } - $query.=')'; - - $result = OC_DB::executeAudited( $query, $params ); - - $lockList = array(); - while( $row = $result->fetchRow()) { - - $lockInfo = new Sabre_DAV_Locks_LockInfo(); - $lockInfo->owner = $row['owner']; - $lockInfo->token = $row['token']; - $lockInfo->timeout = $row['timeout']; - $lockInfo->created = $row['created']; - $lockInfo->scope = $row['scope']; - $lockInfo->depth = $row['depth']; - $lockInfo->uri = $row['uri']; - $lockList[] = $lockInfo; - - } - - return $lockList; - - } - - /** - * Locks a uri - * - * @param string $uri - * @param Sabre_DAV_Locks_LockInfo $lockInfo - * @return bool - */ - public function lock($uri, Sabre_DAV_Locks_LockInfo $lockInfo) { - - // We're making the lock timeout 5 minutes - $lockInfo->timeout = 300; - $lockInfo->created = time(); - $lockInfo->uri = $uri; - - $locks = $this->getLocks($uri, false); - $exists = false; - foreach($locks as $lock) { - if ($lock->token == $lockInfo->token) { - $exists = true; - break; - } - } - - if ($exists) { - $sql = 'UPDATE `*PREFIX*locks`' - .' SET `owner` = ?, `timeout` = ?, `scope` = ?, `depth` = ?, `uri` = ?, `created` = ?' - .' WHERE `userid` = ? AND `token` = ?'; - $result = OC_DB::executeAudited( $sql, array( - $lockInfo->owner, - $lockInfo->timeout, - $lockInfo->scope, - $lockInfo->depth, - $uri, - $lockInfo->created, - OC_User::getUser(), - $lockInfo->token) - ); - } else { - $sql = 'INSERT INTO `*PREFIX*locks`' - .' (`userid`,`owner`,`timeout`,`scope`,`depth`,`uri`,`created`,`token`)' - .' VALUES (?,?,?,?,?,?,?,?)'; - $result = OC_DB::executeAudited( $sql, array( - OC_User::getUser(), - $lockInfo->owner, - $lockInfo->timeout, - $lockInfo->scope, - $lockInfo->depth, - $uri, - $lockInfo->created, - $lockInfo->token) - ); - } - - return true; - - } - - /** - * Removes a lock from a uri - * - * @param string $uri - * @param Sabre_DAV_Locks_LockInfo $lockInfo - * @return bool - */ - public function unlock($uri, Sabre_DAV_Locks_LockInfo $lockInfo) { - - $sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND `uri` = ? AND `token` = ?'; - if (OC_Config::getValue( "dbtype") === 'oci') { - //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison - $sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND to_char(`uri`) = ? AND `token` = ?'; - } - $result = OC_DB::executeAudited( $sql, array(OC_User::getUser(), $uri, $lockInfo->token)); - - return $result === 1; - - } - -} diff --git a/lib/connector/sabre/maintenanceplugin.php b/lib/connector/sabre/maintenanceplugin.php deleted file mode 100644 index 2eda269afc2..00000000000 --- a/lib/connector/sabre/maintenanceplugin.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * @license AGPL3 - */ - -require 'ServiceUnavailable.php'; - -class OC_Connector_Sabre_MaintenancePlugin extends Sabre_DAV_ServerPlugin -{ - - /** - * Reference to main server object - * - * @var Sabre_DAV_Server - */ - private $server; - - /** - * This initializes the plugin. - * - * This function is called by Sabre_DAV_Server, after - * addPlugin is called. - * - * This method should set up the required event subscriptions. - * - * @param Sabre_DAV_Server $server - * @return void - */ - public function initialize(Sabre_DAV_Server $server) { - - $this->server = $server; - $this->server->subscribeEvent('beforeMethod', array($this, 'checkMaintenanceMode'), 10); - } - - /** - * This method is called before any HTTP method and returns http status code 503 - * in case the system is in maintenance mode. - * - * @throws Sabre_DAV_Exception_ServiceUnavailable - * @internal param string $method - * @return bool - */ - public function checkMaintenanceMode() { - if (OC_Config::getValue('maintenance', false)) { - throw new Sabre_DAV_Exception_ServiceUnavailable(); - } - if (OC::checkUpgrade(false)) { - throw new Sabre_DAV_Exception_ServiceUnavailable('Upgrade needed'); - } - - return true; - } -} diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php deleted file mode 100644 index 29b7f9e53a5..00000000000 --- a/lib/connector/sabre/node.php +++ /dev/null @@ -1,238 +0,0 @@ -. - * - */ - -abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IProperties { - const GETETAG_PROPERTYNAME = '{DAV:}getetag'; - const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; - - /** - * Allow configuring the method used to generate Etags - * - * @var array(class_name, function_name) - */ - public static $ETagFunction = null; - - /** - * The path to the current node - * - * @var string - */ - protected $path; - /** - * node fileinfo cache - * @var array - */ - protected $fileinfo_cache; - /** - * node properties cache - * @var array - */ - protected $property_cache = null; - - /** - * @brief Sets up the node, expects a full path name - * @param string $path - * @return void - */ - public function __construct($path) { - $this->path = $path; - } - - - - /** - * @brief Returns the name of the node - * @return string - */ - public function getName() { - - list(, $name) = Sabre_DAV_URLUtil::splitPath($this->path); - return $name; - - } - - /** - * @brief Renames the node - * @param string $name The new name - * @return void - */ - public function setName($name) { - - // rename is only allowed if the update privilege is granted - if (!\OC\Files\Filesystem::isUpdatable($this->path)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - - list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path); - list(, $newName) = Sabre_DAV_URLUtil::splitPath($name); - - $newPath = $parentPath . '/' . $newName; - $oldPath = $this->path; - - \OC\Files\Filesystem::rename($this->path, $newPath); - - $this->path = $newPath; - - $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' - .' WHERE `userid` = ? AND `propertypath` = ?' ); - $query->execute( array( $newPath, OC_User::getUser(), $oldPath )); - - } - - public function setFileinfoCache($fileinfo_cache) - { - $this->fileinfo_cache = $fileinfo_cache; - } - - /** - * @brief Ensure that the fileinfo cache is filled - * @note Uses OC_FileCache or a direct stat - */ - protected function getFileinfoCache() { - if (!isset($this->fileinfo_cache)) { - if ($fileinfo_cache = \OC\Files\Filesystem::getFileInfo($this->path)) { - } else { - $fileinfo_cache = \OC\Files\Filesystem::stat($this->path); - } - - $this->fileinfo_cache = $fileinfo_cache; - } - } - - public function setPropertyCache($property_cache) - { - $this->property_cache = $property_cache; - } - - /** - * @brief Returns the last modification time, as a unix timestamp - * @return int - */ - public function getLastModified() { - $this->getFileinfoCache(); - return $this->fileinfo_cache['mtime']; - - } - - /** - * sets the last modification time of the file (mtime) to the value given - * in the second parameter or to now if the second param is empty. - * Even if the modification time is set to a custom value the access time is set to now. - */ - public function touch($mtime) { - - // touch is only allowed if the update privilege is granted - if (!\OC\Files\Filesystem::isUpdatable($this->path)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - - \OC\Files\Filesystem::touch($this->path, $mtime); - } - - /** - * @brief Updates properties on this node, - * @param array $mutations - * @see Sabre_DAV_IProperties::updateProperties - * @return bool|array - */ - public function updateProperties($properties) { - $existing = $this->getProperties(array()); - foreach($properties as $propertyName => $propertyValue) { - // If it was null, we need to delete the property - if (is_null($propertyValue)) { - if(array_key_exists( $propertyName, $existing )) { - $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*properties`' - .' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' ); - $query->execute( array( OC_User::getUser(), $this->path, $propertyName )); - } - } - else { - if( strcmp( $propertyName, self::GETETAG_PROPERTYNAME) === 0 ) { - \OC\Files\Filesystem::putFileInfo($this->path, array('etag'=> $propertyValue)); - } elseif( strcmp( $propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0 ) { - $this->touch($propertyValue); - } else { - if(!array_key_exists( $propertyName, $existing )) { - $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*properties`' - .' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)' ); - $query->execute( array( OC_User::getUser(), $this->path, $propertyName,$propertyValue )); - } else { - $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' - .' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' ); - $query->execute( array( $propertyValue,OC_User::getUser(), $this->path, $propertyName )); - } - } - } - - } - $this->setPropertyCache(null); - return true; - } - - /** - * @brief Returns a list of properties for this nodes.; - * @param array $properties - * @return array - * @note The properties list is a list of propertynames the client - * requested, encoded as xmlnamespace#tagName, for example: - * http://www.example.org/namespace#author If the array is empty, all - * properties should be returned - */ - public function getProperties($properties) { - if (is_null($this->property_cache)) { - $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?'; - $result = OC_DB::executeAudited( $sql, array( OC_User::getUser(), $this->path ) ); - - $this->property_cache = array(); - while( $row = $result->fetchRow()) { - $this->property_cache[$row['propertyname']] = $row['propertyvalue']; - } - $this->property_cache[self::GETETAG_PROPERTYNAME] = $this->getETagPropertyForPath($this->path); - } - - // if the array was empty, we need to return everything - if(count($properties) == 0) { - return $this->property_cache; - } - - $props = array(); - foreach($properties as $property) { - if (isset($this->property_cache[$property])) $props[$property] = $this->property_cache[$property]; - } - return $props; - } - - /** - * Returns the ETag surrounded by double-quotes for this path. - * @param string $path Path of the file - * @return string|null Returns null if the ETag can not effectively be determined - */ - static public function getETagPropertyForPath($path) { - $data = \OC\Files\Filesystem::getFileInfo($path); - if (isset($data['etag'])) { - return '"'.$data['etag'].'"'; - } - return null; - } - -} diff --git a/lib/connector/sabre/objecttree.php b/lib/connector/sabre/objecttree.php deleted file mode 100644 index 80c3840b99d..00000000000 --- a/lib/connector/sabre/objecttree.php +++ /dev/null @@ -1,142 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Connector\Sabre; - -use OC\Files\Filesystem; - -class ObjectTree extends \Sabre_DAV_ObjectTree { - - /** - * keep this public to allow mock injection during unit test - * - * @var \OC\Files\View - */ - public $fileView; - - /** - * Returns the INode object for the requested path - * - * @param string $path - * @throws \Sabre_DAV_Exception_NotFound - * @return \Sabre_DAV_INode - */ - public function getNodeForPath($path) { - - $path = trim($path, '/'); - if (isset($this->cache[$path])) { - return $this->cache[$path]; - } - - // Is it the root node? - if (!strlen($path)) { - return $this->rootNode; - } - - $info = $this->getFileView()->getFileInfo($path); - - if (!$info) { - throw new \Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); - } - - if ($info['mimetype'] === 'httpd/unix-directory') { - $node = new \OC_Connector_Sabre_Directory($path); - } else { - $node = new \OC_Connector_Sabre_File($path); - } - - $node->setFileinfoCache($info); - - $this->cache[$path] = $node; - return $node; - - } - - /** - * Moves a file from one location to another - * - * @param string $sourcePath The path to the file which should be moved - * @param string $destinationPath The full destination path, so not just the destination parent node - * @throws \Sabre_DAV_Exception_Forbidden - * @return int - */ - public function move($sourcePath, $destinationPath) { - - $sourceNode = $this->getNodeForPath($sourcePath); - if ($sourceNode instanceof \Sabre_DAV_ICollection and $this->nodeExists($destinationPath)) { - throw new \Sabre_DAV_Exception_Forbidden('Could not copy directory ' . $sourceNode . ', target exists'); - } - list($sourceDir,) = \Sabre_DAV_URLUtil::splitPath($sourcePath); - list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destinationPath); - - // check update privileges - $fs = $this->getFileView(); - if (!$fs->isUpdatable($sourcePath)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - if ($sourceDir !== $destinationDir) { - // for a full move we need update privileges on sourcePath and sourceDir as well as destinationDir - if (!$fs->isUpdatable($sourceDir)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - if (!$fs->isUpdatable($destinationDir)) { - throw new \Sabre_DAV_Exception_Forbidden(); - } - } - - $renameOkay = $fs->rename($sourcePath, $destinationPath); - if (!$renameOkay) { - throw new \Sabre_DAV_Exception_Forbidden(''); - } - - $this->markDirty($sourceDir); - $this->markDirty($destinationDir); - - } - - /** - * Copies a file or directory. - * - * This method must work recursively and delete the destination - * if it exists - * - * @param string $source - * @param string $destination - * @return void - */ - public function copy($source, $destination) { - - if (Filesystem::is_file($source)) { - Filesystem::copy($source, $destination); - } else { - Filesystem::mkdir($destination); - $dh = Filesystem::opendir($source); - if(is_resource($dh)) { - while (($subnode = readdir($dh)) !== false) { - - if ($subnode == '.' || $subnode == '..') continue; - $this->copy($source . '/' . $subnode, $destination . '/' . $subnode); - - } - } - } - - list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destination); - $this->markDirty($destinationDir); - } - - /** - * @return \OC\Files\View - */ - public function getFileView() { - if (is_null($this->fileView)) { - $this->fileView = \OC\Files\Filesystem::getView(); - } - return $this->fileView; - } -} diff --git a/lib/connector/sabre/principal.php b/lib/connector/sabre/principal.php deleted file mode 100644 index 59a96797c16..00000000000 --- a/lib/connector/sabre/principal.php +++ /dev/null @@ -1,128 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend { - /** - * Returns a list of principals based on a prefix. - * - * This prefix will often contain something like 'principals'. You are only - * expected to return principals that are in this base path. - * - * You are expected to return at least a 'uri' for every user, you can - * return any additional properties if you wish so. Common properties are: - * {DAV:}displayname - * - * @param string $prefixPath - * @return array - */ - public function getPrincipalsByPrefix( $prefixPath ) { - $principals = array(); - - if ($prefixPath == 'principals') { - foreach(OC_User::getUsers() as $user) { - $user_uri = 'principals/'.$user; - $principals[] = array( - 'uri' => $user_uri, - '{DAV:}displayname' => $user, - ); - } - } - - return $principals; - } - - /** - * Returns a specific principal, specified by it's path. - * The returned structure should be the exact same as from - * getPrincipalsByPrefix. - * - * @param string $path - * @return array - */ - public function getPrincipalByPath($path) { - list($prefix, $name) = explode('/', $path); - - if ($prefix == 'principals' && OC_User::userExists($name)) { - return array( - 'uri' => 'principals/'.$name, - '{DAV:}displayname' => $name, - ); - } - - return null; - } - - /** - * Returns the list of members for a group-principal - * - * @param string $principal - * @return array - */ - public function getGroupMemberSet($principal) { - // TODO: for now the group principal has only one member, the user itself - $principal = $this->getPrincipalByPath($principal); - if (!$principal) { - throw new Sabre_DAV_Exception('Principal not found'); - } - - return array( - $principal['uri'] - ); - } - - /** - * Returns the list of groups a principal is a member of - * - * @param string $principal - * @return array - */ - public function getGroupMembership($principal) { - list($prefix, $name) = Sabre_DAV_URLUtil::splitPath($principal); - - $group_membership = array(); - if ($prefix == 'principals') { - $principal = $this->getPrincipalByPath($principal); - if (!$principal) { - throw new Sabre_DAV_Exception('Principal not found'); - } - - // TODO: for now the user principal has only its own groups - return array( - 'principals/'.$name.'/calendar-proxy-read', - 'principals/'.$name.'/calendar-proxy-write', - // The addressbook groups are not supported in Sabre, - // see http://groups.google.com/group/sabredav-discuss/browse_thread/thread/ef2fa9759d55f8c#msg_5720afc11602e753 - //'principals/'.$name.'/addressbook-proxy-read', - //'principals/'.$name.'/addressbook-proxy-write', - ); - } - return $group_membership; - } - - /** - * Updates the list of group members for a group principal. - * - * The principals should be passed as a list of uri's. - * - * @param string $principal - * @param array $members - * @return void - */ - public function setGroupMemberSet($principal, array $members) { - throw new Sabre_DAV_Exception('Setting members of the group is not supported yet'); - } - - function updatePrincipal($path, $mutations) { - return 0; - } - - function searchPrincipals($prefixPath, array $searchProperties) { - return array(); - } -} diff --git a/lib/connector/sabre/quotaplugin.php b/lib/connector/sabre/quotaplugin.php deleted file mode 100644 index ea2cb81d1f7..00000000000 --- a/lib/connector/sabre/quotaplugin.php +++ /dev/null @@ -1,97 +0,0 @@ -server = $server; - - $server->subscribeEvent('beforeWriteContent', array($this, 'checkQuota'), 10); - $server->subscribeEvent('beforeCreateFile', array($this, 'checkQuota'), 10); - } - - /** - * This method is called before any HTTP method and validates there is enough free space to store the file - * - * @param string $method - * @throws Sabre_DAV_Exception - * @return bool - */ - public function checkQuota($uri, $data = null) { - $length = $this->getLength(); - if ($length) { - if (substr($uri, 0, 1)!=='/') { - $uri='/'.$uri; - } - list($parentUri, $newName) = Sabre_DAV_URLUtil::splitPath($uri); - $freeSpace = $this->getFreeSpace($parentUri); - if ($freeSpace !== \OC\Files\SPACE_UNKNOWN && $length > $freeSpace) { - throw new Sabre_DAV_Exception_InsufficientStorage(); - } - } - return true; - } - - public function getLength() - { - $req = $this->server->httpRequest; - $length = $req->getHeader('X-Expected-Entity-Length'); - if (!$length) { - $length = $req->getHeader('Content-Length'); - } - - $ocLength = $req->getHeader('OC-Total-Length'); - if ($length && $ocLength) { - return max($length, $ocLength); - } - - return $length; - } - - /** - * @param $parentUri - * @return mixed - */ - public function getFreeSpace($parentUri) - { - if (is_null($this->fileView)) { - // initialize fileView - $this->fileView = \OC\Files\Filesystem::getView(); - } - - $freeSpace = $this->fileView->free_space($parentUri); - return $freeSpace; - } -} diff --git a/lib/connector/sabre/request.php b/lib/connector/sabre/request.php deleted file mode 100644 index d70c25c4e70..00000000000 --- a/lib/connector/sabre/request.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. If not, see . - * - */ - -class OC_Connector_Sabre_Request extends Sabre_HTTP_Request { - /** - * Returns the requested uri - * - * @return string - */ - public function getUri() { - return OC_Request::requestUri(); - } - - /** - * Returns a specific item from the _SERVER array. - * - * Do not rely on this feature, it is for internal use only. - * - * @param string $field - * @return string - */ - public function getRawServerValue($field) { - if($field == 'REQUEST_URI') { - return $this->getUri(); - } - else{ - return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null; - } - } -} diff --git a/lib/contactsmanager.php b/lib/contactsmanager.php deleted file mode 100644 index fc6745b4505..00000000000 --- a/lib/contactsmanager.php +++ /dev/null @@ -1,145 +0,0 @@ -. - * - */ - -namespace OC { - - class ContactsManager implements \OCP\Contacts\IManager { - - /** - * This function is used to search and find contacts within the users address books. - * In case $pattern is empty all contacts will be returned. - * - * @param string $pattern which should match within the $searchProperties - * @param array $searchProperties defines the properties within the query pattern should match - * @param array $options - for future use. One should always have options! - * @return array of contacts which are arrays of key-value-pairs - */ - public function search($pattern, $searchProperties = array(), $options = array()) { - $result = array(); - foreach($this->address_books as $address_book) { - $r = $address_book->search($pattern, $searchProperties, $options); - $result = array_merge($result, $r); - } - - return $result; - } - - /** - * This function can be used to delete the contact identified by the given id - * - * @param object $id the unique identifier to a contact - * @param $address_book_key - * @return bool successful or not - */ - public function delete($id, $address_book_key) { - if (!array_key_exists($address_book_key, $this->address_books)) - return null; - - $address_book = $this->address_books[$address_book_key]; - if ($address_book->getPermissions() & \OCP\PERMISSION_DELETE) - return null; - - return $address_book->delete($id); - } - - /** - * This function is used to create a new contact if 'id' is not given or not present. - * Otherwise the contact will be updated by replacing the entire data set. - * - * @param array $properties this array if key-value-pairs defines a contact - * @param $address_book_key string to identify the address book in which the contact shall be created or updated - * @return array representing the contact just created or updated - */ - public function createOrUpdate($properties, $address_book_key) { - - if (!array_key_exists($address_book_key, $this->address_books)) - return null; - - $address_book = $this->address_books[$address_book_key]; - if ($address_book->getPermissions() & \OCP\PERMISSION_CREATE) - return null; - - return $address_book->createOrUpdate($properties); - } - - /** - * Check if contacts are available (e.g. contacts app enabled) - * - * @return bool true if enabled, false if not - */ - public function isEnabled() { - return !empty($this->address_books); - } - - /** - * @param \OCP\IAddressBook $address_book - */ - public function registerAddressBook(\OCP\IAddressBook $address_book) { - $this->address_books[$address_book->getKey()] = $address_book; - } - - /** - * @param \OCP\IAddressBook $address_book - */ - public function unregisterAddressBook(\OCP\IAddressBook $address_book) { - unset($this->address_books[$address_book->getKey()]); - } - - /** - * @return array - */ - public function getAddressBooks() { - $result = array(); - foreach($this->address_books as $address_book) { - $result[$address_book->getKey()] = $address_book->getDisplayName(); - } - - return $result; - } - - /** - * removes all registered address book instances - */ - public function clear() { - $this->address_books = array(); - } - - /** - * @var \OCP\IAddressBook[] which holds all registered address books - */ - private $address_books = array(); - - /** - * In order to improve lazy loading a closure can be registered which will be called in case - * address books are actually requested - * - * @param string $key - * @param \Closure $callable - */ - function register($key, \Closure $callable) - { - // - //TODO: implement me - // - } - } -} diff --git a/lib/db.php b/lib/db.php deleted file mode 100644 index 1e5d12649df..00000000000 --- a/lib/db.php +++ /dev/null @@ -1,462 +0,0 @@ -. - * - */ - -define('MDB2_SCHEMA_DUMP_STRUCTURE', '1'); - -class DatabaseException extends Exception { - private $query; - - //FIXME getQuery seems to be unused, maybe use parent constructor with $message, $code and $previous - public function __construct($message, $query = null){ - parent::__construct($message); - $this->query = $query; - } - - public function getQuery() { - return $this->query; - } -} - -/** - * This class manages the access to the database. It basically is a wrapper for - * Doctrine with some adaptions. - */ -class OC_DB { - /** - * @var \OC\DB\Connection $connection - */ - static private $connection; //the prefered connection to use, only Doctrine - - static private $prefix=null; - static private $type=null; - - /** - * @brief connects to the database - * @return bool true if connection can be established or false on error - * - * Connects to the database as specified in config.php - */ - public static function connect() { - if(self::$connection) { - return true; - } - - // The global data we need - $name = OC_Config::getValue( "dbname", "owncloud" ); - $host = OC_Config::getValue( "dbhost", "" ); - $user = OC_Config::getValue( "dbuser", "" ); - $pass = OC_Config::getValue( "dbpassword", "" ); - $type = OC_Config::getValue( "dbtype", "sqlite" ); - if(strpos($host, ':')) { - list($host, $port)=explode(':', $host, 2); - } else { - $port=false; - } - - // do nothing if the connection already has been established - if (!self::$connection) { - $config = new \Doctrine\DBAL\Configuration(); - $eventManager = new \Doctrine\Common\EventManager(); - switch($type) { - case 'sqlite': - case 'sqlite3': - $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ); - $connectionParams = array( - 'user' => $user, - 'password' => $pass, - 'path' => $datadir.'/'.$name.'.db', - 'driver' => 'pdo_sqlite', - ); - $connectionParams['adapter'] = '\OC\DB\AdapterSqlite'; - $connectionParams['wrapperClass'] = 'OC\DB\Connection'; - break; - case 'mysql': - $connectionParams = array( - 'user' => $user, - 'password' => $pass, - 'host' => $host, - 'port' => $port, - 'dbname' => $name, - 'charset' => 'UTF8', - 'driver' => 'pdo_mysql', - ); - $connectionParams['adapter'] = '\OC\DB\Adapter'; - $connectionParams['wrapperClass'] = 'OC\DB\Connection'; - break; - case 'pgsql': - $connectionParams = array( - 'user' => $user, - 'password' => $pass, - 'host' => $host, - 'port' => $port, - 'dbname' => $name, - 'driver' => 'pdo_pgsql', - ); - $connectionParams['adapter'] = '\OC\DB\AdapterPgSql'; - $connectionParams['wrapperClass'] = 'OC\DB\Connection'; - break; - case 'oci': - $connectionParams = array( - 'user' => $user, - 'password' => $pass, - 'host' => $host, - 'dbname' => $name, - 'charset' => 'AL32UTF8', - 'driver' => 'oci8', - ); - if (!empty($port)) { - $connectionParams['port'] = $port; - } - $connectionParams['adapter'] = '\OC\DB\AdapterOCI8'; - $connectionParams['wrapperClass'] = 'OC\DB\OracleConnection'; - $eventManager->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\OracleSessionInit); - break; - case 'mssql': - $connectionParams = array( - 'user' => $user, - 'password' => $pass, - 'host' => $host, - 'port' => $port, - 'dbname' => $name, - 'charset' => 'UTF8', - 'driver' => 'pdo_sqlsrv', - ); - $connectionParams['adapter'] = '\OC\DB\AdapterSQLSrv'; - $connectionParams['wrapperClass'] = 'OC\DB\Connection'; - break; - default: - return false; - } - $connectionParams['tablePrefix'] = OC_Config::getValue('dbtableprefix', 'oc_' ); - try { - self::$connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config, $eventManager); - if ($type === 'sqlite' || $type === 'sqlite3') { - // Sqlite doesn't handle query caching and schema changes - // TODO: find a better way to handle this - self::$connection->disableQueryStatementCaching(); - } - } catch(\Doctrine\DBAL\DBALException $e) { - OC_Log::write('core', $e->getMessage(), OC_Log::FATAL); - OC_User::setUserId(null); - - // send http status 503 - header('HTTP/1.1 503 Service Temporarily Unavailable'); - header('Status: 503 Service Temporarily Unavailable'); - OC_Template::printErrorPage('Failed to connect to database'); - die(); - } - } - return true; - } - - /** - * @return \OC\DB\Connection - */ - static public function getConnection() { - self::connect(); - return self::$connection; - } - - /** - * get MDB2 schema manager - * - * @return \OC\DB\MDB2SchemaManager - */ - private static function getMDB2SchemaManager() - { - return new \OC\DB\MDB2SchemaManager(self::getConnection()); - } - - /** - * @brief Prepare a SQL query - * @param string $query Query string - * @param int $limit - * @param int $offset - * @param bool $isManipulation - * @throws DatabaseException - * @return \Doctrine\DBAL\Statement prepared SQL query - * - * SQL query via Doctrine prepare(), needs to be execute()'d! - */ - static public function prepare( $query , $limit = null, $offset = null, $isManipulation = null) { - self::connect(); - - if ($isManipulation === null) { - //try to guess, so we return the number of rows on manipulations - $isManipulation = self::isManipulation($query); - } - - // return the result - try { - $result = self::$connection->prepare($query, $limit, $offset); - } catch (\Doctrine\DBAL\DBALException $e) { - throw new \DatabaseException($e->getMessage(), $query); - } - // differentiate between query and manipulation - $result = new OC_DB_StatementWrapper($result, $isManipulation); - return $result; - } - - /** - * tries to guess the type of statement based on the first 10 characters - * the current check allows some whitespace but does not work with IF EXISTS or other more complex statements - * - * @param string $sql - * @return bool - */ - static public function isManipulation( $sql ) { - $selectOccurrence = stripos($sql, 'SELECT'); - if ($selectOccurrence !== false && $selectOccurrence < 10) { - return false; - } - $insertOccurrence = stripos($sql, 'INSERT'); - if ($insertOccurrence !== false && $insertOccurrence < 10) { - return true; - } - $updateOccurrence = stripos($sql, 'UPDATE'); - if ($updateOccurrence !== false && $updateOccurrence < 10) { - return true; - } - $deleteOccurrence = stripos($sql, 'DELETE'); - if ($deleteOccurrence !== false && $deleteOccurrence < 10) { - return true; - } - return false; - } - - /** - * @brief execute a prepared statement, on error write log and throw exception - * @param mixed $stmt OC_DB_StatementWrapper, - * an array with 'sql' and optionally 'limit' and 'offset' keys - * .. or a simple sql query string - * @param array $parameters - * @return result - * @throws DatabaseException - */ - static public function executeAudited( $stmt, array $parameters = null) { - if (is_string($stmt)) { - // convert to an array with 'sql' - if (stripos($stmt, 'LIMIT') !== false) { //OFFSET requires LIMIT, so we only need to check for LIMIT - // TODO try to convert LIMIT OFFSET notation to parameters, see fixLimitClauseForMSSQL - $message = 'LIMIT and OFFSET are forbidden for portability reasons,' - . ' pass an array with \'limit\' and \'offset\' instead'; - throw new DatabaseException($message); - } - $stmt = array('sql' => $stmt, 'limit' => null, 'offset' => null); - } - if (is_array($stmt)) { - // convert to prepared statement - if ( ! array_key_exists('sql', $stmt) ) { - $message = 'statement array must at least contain key \'sql\''; - throw new DatabaseException($message); - } - if ( ! array_key_exists('limit', $stmt) ) { - $stmt['limit'] = null; - } - if ( ! array_key_exists('limit', $stmt) ) { - $stmt['offset'] = null; - } - $stmt = self::prepare($stmt['sql'], $stmt['limit'], $stmt['offset']); - } - self::raiseExceptionOnError($stmt, 'Could not prepare statement'); - if ($stmt instanceof OC_DB_StatementWrapper) { - $result = $stmt->execute($parameters); - self::raiseExceptionOnError($result, 'Could not execute statement'); - } else { - if (is_object($stmt)) { - $message = 'Expected a prepared statement or array got ' . get_class($stmt); - } else { - $message = 'Expected a prepared statement or array got ' . gettype($stmt); - } - throw new DatabaseException($message); - } - return $result; - } - - /** - * @brief gets last value of autoincrement - * @param string $table The optional table name (will replace *PREFIX*) and add sequence suffix - * @return int id - * @throws DatabaseException - * - * \Doctrine\DBAL\Connection lastInsertId - * - * Call this method right after the insert command or other functions may - * cause trouble! - */ - public static function insertid($table=null) { - self::connect(); - return self::$connection->lastInsertId($table); - } - - /** - * @brief Insert a row if a matching row doesn't exists. - * @param string $table. The table to insert into in the form '*PREFIX*tableName' - * @param array $input. An array of fieldname/value pairs - * @return int number of updated rows - */ - public static function insertIfNotExist($table, $input) { - self::connect(); - return self::$connection->insertIfNotExist($table, $input); - } - - /** - * Start a transaction - */ - public static function beginTransaction() { - self::connect(); - self::$connection->beginTransaction(); - } - - /** - * Commit the database changes done during a transaction that is in progress - */ - public static function commit() { - self::connect(); - self::$connection->commit(); - } - - /** - * @brief saves database schema to xml file - * @param string $file name of file - * @param int $mode - * @return bool - * - * TODO: write more documentation - */ - public static function getDbStructure( $file, $mode = 0) { - $schemaManager = self::getMDB2SchemaManager(); - return $schemaManager->getDbStructure($file); - } - - /** - * @brief Creates tables from XML file - * @param string $file file to read structure from - * @return bool - * - * TODO: write more documentation - */ - public static function createDbFromStructure( $file ) { - $schemaManager = self::getMDB2SchemaManager(); - $result = $schemaManager->createDbFromStructure($file); - return $result; - } - - /** - * @brief update the database schema - * @param string $file file to read structure from - * @throws Exception - * @return bool - */ - public static function updateDbFromStructure($file) { - $schemaManager = self::getMDB2SchemaManager(); - try { - $result = $schemaManager->updateDbFromStructure($file); - } catch (Exception $e) { - OC_Log::write('core', 'Failed to update database structure ('.$e.')', OC_Log::FATAL); - throw $e; - } - return $result; - } - - /** - * @brief drop a table - * @param string $tableName the table to drop - */ - public static function dropTable($tableName) { - $schemaManager = self::getMDB2SchemaManager(); - $schemaManager->dropTable($tableName); - } - - /** - * remove all tables defined in a database structure xml file - * @param string $file the xml file describing the tables - */ - public static function removeDBStructure($file) { - $schemaManager = self::getMDB2SchemaManager(); - $schemaManager->removeDBStructure($file); - } - - /** - * @brief replaces the ownCloud tables with a new set - * @param $file string path to the MDB2 xml db export file - */ - public static function replaceDB( $file ) { - $schemaManager = self::getMDB2SchemaManager(); - $schemaManager->replaceDB($file); - } - - /** - * check if a result is an error, works with Doctrine - * @param mixed $result - * @return bool - */ - public static function isError($result) { - //Doctrine returns false on error (and throws an exception) - return $result === false; - } - /** - * check if a result is an error and throws an exception, works with \Doctrine\DBAL\DBALException - * @param mixed $result - * @param string $message - * @return void - * @throws DatabaseException - */ - public static function raiseExceptionOnError($result, $message = null) { - if(self::isError($result)) { - if ($message === null) { - $message = self::getErrorMessage($result); - } else { - $message .= ', Root cause:' . self::getErrorMessage($result); - } - throw new DatabaseException($message, self::getErrorCode($result)); - } - } - - public static function getErrorCode($error) { - $code = self::$connection->errorCode(); - return $code; - } - /** - * returns the error code and message as a string for logging - * works with DoctrineException - * @param mixed $error - * @return string - */ - public static function getErrorMessage($error) { - if (self::$connection) { - return self::$connection->getError(); - } - return ''; - } - - /** - * @param bool $enabled - */ - static public function enableCaching($enabled) { - if ($enabled) { - self::$connection->enableQueryStatementCaching(); - } else { - self::$connection->disableQueryStatementCaching(); - } - } -} diff --git a/lib/db/adapter.php b/lib/db/adapter.php deleted file mode 100644 index 6b31f37dd98..00000000000 --- a/lib/db/adapter.php +++ /dev/null @@ -1,72 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\DB; - -/** - * This handles the way we use to write queries, into something that can be - * handled by the database abstraction layer. - */ -class Adapter { - - /** - * @var \OC\DB\Connection $conn - */ - protected $conn; - - public function __construct($conn) { - $this->conn = $conn; - } - - /** - * @param string $table name - * @return int id of last insert statement - */ - public function lastInsertId($table) { - return $this->conn->realLastInsertId($table); - } - - /** - * @param string $statement that needs to be changed so the db can handle it - * @return string changed statement - */ - public function fixupStatement($statement) { - return $statement; - } - - /** - * @brief insert the @input values when they do not exist yet - * @param string $table name - * @param array $input key->value pairs - * @return int count of inserted rows - */ - public function insertIfNotExist($table, $input) { - $query = 'INSERT INTO `' .$table . '` (`' - . implode('`,`', array_keys($input)) . '`) SELECT ' - . str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative? - . 'FROM `' . $table . '` WHERE '; - - foreach($input as $key => $value) { - $query .= '`' . $key . '` = ? AND '; - } - $query = substr($query, 0, strlen($query) - 5); - $query .= ' HAVING COUNT(*) = 0'; - $inserts = array_values($input); - $inserts = array_merge($inserts, $inserts); - - try { - return $this->conn->executeUpdate($query, $inserts); - } catch(\Doctrine\DBAL\DBALException $e) { - $entry = 'DB Error: "'.$e->getMessage() . '"
'; - $entry .= 'Offending command was: ' . $query.'
'; - \OC_Log::write('core', $entry, \OC_Log::FATAL); - error_log('DB error: ' . $entry); - \OC_Template::printErrorPage( $entry ); - } - } -} diff --git a/lib/db/adapteroci8.php b/lib/db/adapteroci8.php deleted file mode 100644 index bc226e979ec..00000000000 --- a/lib/db/adapteroci8.php +++ /dev/null @@ -1,28 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - - -namespace OC\DB; - -class AdapterOCI8 extends Adapter { - public function lastInsertId($table) { - if($table !== null) { - $suffix = '_SEQ'; - $table = '"'.$table.$suffix.'"'; - } - return $this->conn->realLastInsertId($table); - } - - const UNIX_TIMESTAMP_REPLACEMENT = "(cast(sys_extract_utc(systimestamp) as date) - date'1970-01-01') * 86400"; - public function fixupStatement($statement) { - $statement = str_replace( '`', '"', $statement ); - $statement = str_ireplace( 'NOW()', 'CURRENT_TIMESTAMP', $statement ); - $statement = str_ireplace( 'UNIX_TIMESTAMP()', self::UNIX_TIMESTAMP_REPLACEMENT, $statement ); - return $statement; - } -} diff --git a/lib/db/adapterpgsql.php b/lib/db/adapterpgsql.php deleted file mode 100644 index 990d71c9f29..00000000000 --- a/lib/db/adapterpgsql.php +++ /dev/null @@ -1,23 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - - -namespace OC\DB; - -class AdapterPgSql extends Adapter { - public function lastInsertId($table) { - return $this->conn->fetchColumn('SELECT lastval()'); - } - - const UNIX_TIMESTAMP_REPLACEMENT = 'cast(extract(epoch from current_timestamp) as integer)'; - public function fixupStatement($statement) { - $statement = str_replace( '`', '"', $statement ); - $statement = str_ireplace( 'UNIX_TIMESTAMP()', self::UNIX_TIMESTAMP_REPLACEMENT, $statement ); - return $statement; - } -} diff --git a/lib/db/adaptersqlite.php b/lib/db/adaptersqlite.php deleted file mode 100644 index fa6d308ae32..00000000000 --- a/lib/db/adaptersqlite.php +++ /dev/null @@ -1,60 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - - -namespace OC\DB; - -class AdapterSqlite extends Adapter { - public function fixupStatement($statement) { - $statement = str_replace( '`', '"', $statement ); - $statement = str_ireplace( 'NOW()', 'datetime(\'now\')', $statement ); - $statement = str_ireplace( 'UNIX_TIMESTAMP()', 'strftime(\'%s\',\'now\')', $statement ); - return $statement; - } - - public function insertIfNotExist($table, $input) { - // NOTE: For SQLite we have to use this clumsy approach - // otherwise all fieldnames used must have a unique key. - $query = 'SELECT COUNT(*) FROM `' . $table . '` WHERE '; - foreach($input as $key => $value) { - $query .= '`' . $key . '` = ? AND '; - } - $query = substr($query, 0, strlen($query) - 5); - try { - $stmt = $this->conn->prepare($query); - $result = $stmt->execute(array_values($input)); - } catch(\Doctrine\DBAL\DBALException $e) { - $entry = 'DB Error: "'.$e->getMessage() . '"
'; - $entry .= 'Offending command was: ' . $query . '
'; - \OC_Log::write('core', $entry, \OC_Log::FATAL); - error_log('DB error: '.$entry); - \OC_Template::printErrorPage( $entry ); - } - - if ($stmt->fetchColumn() === '0') { - $query = 'INSERT INTO `' . $table . '` (`' - . implode('`,`', array_keys($input)) . '`) VALUES(' - . str_repeat('?,', count($input)-1).'? ' . ')'; - } else { - return 0; //no rows updated - } - - try { - $statement = $this->conn->prepare($query); - $result = $statement->execute(array_values($input)); - } catch(\Doctrine\DBAL\DBALException $e) { - $entry = 'DB Error: "'.$e->getMessage() . '"
'; - $entry .= 'Offending command was: ' . $query.'
'; - \OC_Log::write('core', $entry, \OC_Log::FATAL); - error_log('DB error: ' . $entry); - \OC_Template::printErrorPage( $entry ); - } - - return $result; - } -} diff --git a/lib/db/adaptersqlsrv.php b/lib/db/adaptersqlsrv.php deleted file mode 100644 index d0a67af28a7..00000000000 --- a/lib/db/adaptersqlsrv.php +++ /dev/null @@ -1,28 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - - -namespace OC\DB; - -class AdapterSQLSrv extends Adapter { - public function lastInsertId($table) { - if($table !== null) { - $table = $this->conn->replaceTablePrefix( $table ); - } - return $this->conn->lastInsertId($table); - } - - public function fixupStatement($statement) { - $statement = preg_replace( "/\`(.*?)`/", "[$1]", $statement ); - $statement = str_ireplace( 'NOW()', 'CURRENT_TIMESTAMP', $statement ); - $statement = str_replace( 'LENGTH(', 'LEN(', $statement ); - $statement = str_replace( 'SUBSTR(', 'SUBSTRING(', $statement ); - $statement = str_ireplace( 'UNIX_TIMESTAMP()', 'DATEDIFF(second,{d \'1970-01-01\'},GETDATE())', $statement ); - return $statement; - } -} diff --git a/lib/db/connection.php b/lib/db/connection.php deleted file mode 100644 index 2d3193a148a..00000000000 --- a/lib/db/connection.php +++ /dev/null @@ -1,197 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\DB; -use Doctrine\DBAL\Driver; -use Doctrine\DBAL\Configuration; -use Doctrine\DBAL\Cache\QueryCacheProfile; -use Doctrine\Common\EventManager; - -class Connection extends \Doctrine\DBAL\Connection implements \OCP\IDBConnection { - /** - * @var string $tablePrefix - */ - protected $tablePrefix; - - /** - * @var \OC\DB\Adapter $adapter - */ - protected $adapter; - - /** - * @var \Doctrine\DBAL\Driver\Statement[] $preparedQueries - */ - protected $preparedQueries = array(); - - protected $cachingQueryStatementEnabled = true; - - /** - * Initializes a new instance of the Connection class. - * - * @param array $params The connection parameters. - * @param \Doctrine\DBAL\Driver $driver - * @param \Doctrine\DBAL\Configuration $config - * @param \Doctrine\Common\EventManager $eventManager - * @throws \Exception - */ - public function __construct(array $params, Driver $driver, Configuration $config = null, - EventManager $eventManager = null) - { - if (!isset($params['adapter'])) { - throw new \Exception('adapter not set'); - } - if (!isset($params['tablePrefix'])) { - throw new \Exception('tablePrefix not set'); - } - parent::__construct($params, $driver, $config, $eventManager); - $this->adapter = new $params['adapter']($this); - $this->tablePrefix = $params['tablePrefix']; - } - - /** - * Prepares an SQL statement. - * - * @param string $statement The SQL statement to prepare. - * @param int $limit - * @param int $offset - * @return \Doctrine\DBAL\Driver\Statement The prepared statement. - */ - public function prepare( $statement, $limit=null, $offset=null ) { - if ($limit === -1) { - $limit = null; - } - if (!is_null($limit)) { - $platform = $this->getDatabasePlatform(); - $statement = $platform->modifyLimitQuery($statement, $limit, $offset); - } else { - if (isset($this->preparedQueries[$statement]) && $this->cachingQueryStatementEnabled) { - return $this->preparedQueries[$statement]; - } - $origStatement = $statement; - } - $statement = $this->replaceTablePrefix($statement); - $statement = $this->adapter->fixupStatement($statement); - - if(\OC_Config::getValue( 'log_query', false)) { - \OC_Log::write('core', 'DB prepare : '.$statement, \OC_Log::DEBUG); - } - $result = parent::prepare($statement); - if (is_null($limit) && $this->cachingQueryStatementEnabled) { - $this->preparedQueries[$origStatement] = $result; - } - return $result; - } - - /** - * Executes an, optionally parameterized, SQL query. - * - * If the query is parameterized, a prepared statement is used. - * If an SQLLogger is configured, the execution is logged. - * - * @param string $query The SQL query to execute. - * @param array $params The parameters to bind to the query, if any. - * @param array $types The types the previous parameters are in. - * @param QueryCacheProfile $qcp - * @return \Doctrine\DBAL\Driver\Statement The executed statement. - * @internal PERF: Directly prepares a driver statement, not a wrapper. - */ - public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null) - { - $query = $this->replaceTablePrefix($query); - $query = $this->adapter->fixupStatement($query); - return parent::executeQuery($query, $params, $types, $qcp); - } - - /** - * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters - * and returns the number of affected rows. - * - * This method supports PDO binding types as well as DBAL mapping types. - * - * @param string $query The SQL query. - * @param array $params The query parameters. - * @param array $types The parameter types. - * @return integer The number of affected rows. - * @internal PERF: Directly prepares a driver statement, not a wrapper. - */ - public function executeUpdate($query, array $params = array(), array $types = array()) - { - $query = $this->replaceTablePrefix($query); - $query = $this->adapter->fixupStatement($query); - return parent::executeUpdate($query, $params, $types); - } - - /** - * Returns the ID of the last inserted row, or the last value from a sequence object, - * depending on the underlying driver. - * - * Note: This method may not return a meaningful or consistent result across different drivers, - * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY - * columns or sequences. - * - * @param string $seqName Name of the sequence object from which the ID should be returned. - * @return string A string representation of the last inserted ID. - */ - public function lastInsertId($seqName = null) - { - if ($seqName) { - $seqName = $this->replaceTablePrefix($seqName); - } - return $this->adapter->lastInsertId($seqName); - } - - // internal use - public function realLastInsertId($seqName = null) - { - return parent::lastInsertId($seqName); - } - - /** - * @brief Insert a row if a matching row doesn't exists. - * @param string $table. The table to insert into in the form '*PREFIX*tableName' - * @param array $input. An array of fieldname/value pairs - * @return bool The return value from execute() - */ - public function insertIfNotExist($table, $input) { - return $this->adapter->insertIfNotExist($table, $input); - } - - /** - * returns the error code and message as a string for logging - * works with DoctrineException - * @return string - */ - public function getError() { - $msg = $this->errorCode() . ': '; - $errorInfo = $this->errorInfo(); - if (is_array($errorInfo)) { - $msg .= 'SQLSTATE = '.$errorInfo[0] . ', '; - $msg .= 'Driver Code = '.$errorInfo[1] . ', '; - $msg .= 'Driver Message = '.$errorInfo[2]; - } - return $msg; - } - - // internal use - /** - * @param string $statement - * @return string - */ - protected function replaceTablePrefix($statement) { - return str_replace( '*PREFIX*', $this->tablePrefix, $statement ); - } - - public function enableQueryStatementCaching() { - $this->cachingQueryStatementEnabled = true; - } - - public function disableQueryStatementCaching() { - $this->cachingQueryStatementEnabled = false; - $this->preparedQueries = array(); - } -} diff --git a/lib/db/mdb2schemamanager.php b/lib/db/mdb2schemamanager.php deleted file mode 100644 index 8e76f46c78f..00000000000 --- a/lib/db/mdb2schemamanager.php +++ /dev/null @@ -1,150 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\DB; - -class MDB2SchemaManager { - /** - * @var \OC\DB\Connection $conn - */ - protected $conn; - - /** - * @param \OC\DB\Connection $conn - */ - public function __construct($conn) { - $this->conn = $conn; - } - - /** - * @brief saves database scheme to xml file - * @param string $file name of file - * @param int|string $mode - * @return bool - * - * TODO: write more documentation - */ - public function getDbStructure( $file, $mode = MDB2_SCHEMA_DUMP_STRUCTURE) { - $sm = $this->conn->getSchemaManager(); - - return \OC_DB_MDB2SchemaWriter::saveSchemaToFile($file, $sm); - } - - /** - * @brief Creates tables from XML file - * @param string $file file to read structure from - * @return bool - * - * TODO: write more documentation - */ - public function createDbFromStructure( $file ) { - $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); - $toSchema = $schemaReader->loadSchemaFromFile($file); - return $this->executeSchemaChange($toSchema); - } - - /** - * @brief update the database scheme - * @param string $file file to read structure from - * @return bool - */ - public function updateDbFromStructure($file) { - $sm = $this->conn->getSchemaManager(); - $fromSchema = $sm->createSchema(); - - $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); - $toSchema = $schemaReader->loadSchemaFromFile($file); - - // remove tables we don't know about - foreach($fromSchema->getTables() as $table) { - if (!$toSchema->hasTable($table->getName())) { - $fromSchema->dropTable($table->getName()); - } - } - // remove sequences we don't know about - foreach($fromSchema->getSequences() as $table) { - if (!$toSchema->hasSequence($table->getName())) { - $fromSchema->dropSequence($table->getName()); - } - } - - $comparator = new \Doctrine\DBAL\Schema\Comparator(); - $schemaDiff = $comparator->compare($fromSchema, $toSchema); - - $platform = $this->conn->getDatabasePlatform(); - $tables = $schemaDiff->newTables + $schemaDiff->changedTables + $schemaDiff->removedTables; - foreach($tables as $tableDiff) { - $tableDiff->name = $platform->quoteIdentifier($tableDiff->name); - } - - return $this->executeSchemaChange($schemaDiff); - } - - /** - * @brief drop a table - * @param string $tableName the table to drop - */ - public function dropTable($tableName) { - $sm = $this->conn->getSchemaManager(); - $fromSchema = $sm->createSchema(); - $toSchema = clone $fromSchema; - $toSchema->dropTable($tableName); - $sql = $fromSchema->getMigrateToSql($toSchema, $this->conn->getDatabasePlatform()); - $this->conn->executeQuery($sql); - } - - /** - * remove all tables defined in a database structure xml file - * @param string $file the xml file describing the tables - */ - public function removeDBStructure($file) { - $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); - $fromSchema = $schemaReader->loadSchemaFromFile($file); - $toSchema = clone $fromSchema; - foreach($toSchema->getTables() as $table) { - $toSchema->dropTable($table->getName()); - } - $comparator = new \Doctrine\DBAL\Schema\Comparator(); - $schemaDiff = $comparator->compare($fromSchema, $toSchema); - $this->executeSchemaChange($schemaDiff); - } - - /** - * @brief replaces the ownCloud tables with a new set - * @param $file string path to the MDB2 xml db export file - */ - public function replaceDB( $file ) { - $apps = \OC_App::getAllApps(); - $this->conn->beginTransaction(); - // Delete the old tables - $this->removeDBStructure( \OC::$SERVERROOT . '/db_structure.xml' ); - - foreach($apps as $app) { - $path = \OC_App::getAppPath($app).'/appinfo/database.xml'; - if(file_exists($path)) { - $this->removeDBStructure( $path ); - } - } - - // Create new tables - $this->conn->commit(); - } - - /** - * @param \Doctrine\DBAL\Schema\Schema $schema - * @return bool - */ - private function executeSchemaChange($schema) { - $this->conn->beginTransaction(); - foreach($schema->toSql($this->conn->getDatabasePlatform()) as $sql) { - $this->conn->query($sql); - } - $this->conn->commit(); - return true; - } -} diff --git a/lib/db/mdb2schemareader.php b/lib/db/mdb2schemareader.php deleted file mode 100644 index b7128a2f176..00000000000 --- a/lib/db/mdb2schemareader.php +++ /dev/null @@ -1,305 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\DB; - -class MDB2SchemaReader { - /** - * @var string $DBNAME - */ - protected $DBNAME; - - /** - * @var string $DBTABLEPREFIX - */ - protected $DBTABLEPREFIX; - - /** - * @var \Doctrine\DBAL\Platforms\AbstractPlatform $platform - */ - protected $platform; - - /** - * @param \OC\Config $config - * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform - */ - public function __construct($config, $platform) { - $this->platform = $platform; - $this->DBNAME = $config->getValue('dbname', 'owncloud'); - $this->DBTABLEPREFIX = $config->getValue('dbtableprefix', 'oc_'); - } - - /** - * @param string $file - * @return \Doctrine\DBAL\Schema\Schema - * @throws \DomainException - */ - public function loadSchemaFromFile($file) { - $schema = new \Doctrine\DBAL\Schema\Schema(); - $xml = simplexml_load_file($file); - foreach ($xml->children() as $child) { - /** - * @var \SimpleXMLElement $child - */ - switch ($child->getName()) { - case 'name': - case 'create': - case 'overwrite': - case 'charset': - break; - case 'table': - $this->loadTable($schema, $child); - break; - default: - throw new \DomainException('Unknown element: ' . $child->getName()); - - } - } - return $schema; - } - - /** - * @param\Doctrine\DBAL\Schema\Schema $schema - * @param \SimpleXMLElement $xml - * @throws \DomainException - */ - private function loadTable($schema, $xml) { - $table = null; - foreach ($xml->children() as $child) { - /** - * @var \SimpleXMLElement $child - */ - switch ($child->getName()) { - case 'name': - $name = (string)$child; - $name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name); - $name = $this->platform->quoteIdentifier($name); - $table = $schema->createTable($name); - break; - case 'create': - case 'overwrite': - case 'charset': - break; - case 'declaration': - if (is_null($table)) { - throw new \DomainException('Table declaration before table name'); - } - $this->loadDeclaration($table, $child); - break; - default: - throw new \DomainException('Unknown element: ' . $child->getName()); - - } - } - } - - /** - * @param \Doctrine\DBAL\Schema\Table $table - * @param \SimpleXMLElement $xml - * @throws \DomainException - */ - private function loadDeclaration($table, $xml) { - foreach ($xml->children() as $child) { - /** - * @var \SimpleXMLElement $child - */ - switch ($child->getName()) { - case 'field': - $this->loadField($table, $child); - break; - case 'index': - $this->loadIndex($table, $child); - break; - default: - throw new \DomainException('Unknown element: ' . $child->getName()); - - } - } - } - - /** - * @param \Doctrine\DBAL\Schema\Table $table - * @param \SimpleXMLElement $xml - * @throws \DomainException - */ - private function loadField($table, $xml) { - $options = array(); - foreach ($xml->children() as $child) { - /** - * @var \SimpleXMLElement $child - */ - switch ($child->getName()) { - case 'name': - $name = (string)$child; - $name = $this->platform->quoteIdentifier($name); - break; - case 'type': - $type = (string)$child; - switch ($type) { - case 'text': - $type = 'string'; - break; - case 'clob': - $type = 'text'; - break; - case 'timestamp': - $type = 'datetime'; - break; - } - break; - case 'length': - $length = (string)$child; - $options['length'] = $length; - break; - case 'unsigned': - $unsigned = $this->asBool($child); - $options['unsigned'] = $unsigned; - break; - case 'notnull': - $notnull = $this->asBool($child); - $options['notnull'] = $notnull; - break; - case 'autoincrement': - $autoincrement = $this->asBool($child); - $options['autoincrement'] = $autoincrement; - break; - case 'default': - $default = (string)$child; - $options['default'] = $default; - break; - case 'comments': - $comment = (string)$child; - $options['comment'] = $comment; - break; - case 'primary': - $primary = $this->asBool($child); - $options['primary'] = $primary; - break; - default: - throw new \DomainException('Unknown element: ' . $child->getName()); - - } - } - if (isset($name) && isset($type)) { - if (empty($options['default'])) { - if (empty($options['notnull']) || !$options['notnull']) { - unset($options['default']); - $options['notnull'] = false; - } else { - $options['default'] = ''; - } - if ($type == 'integer') { - $options['default'] = 0; - } elseif ($type == 'boolean') { - $options['default'] = false; - } - if (!empty($options['autoincrement']) && $options['autoincrement']) { - unset($options['default']); - } - } - if ($type === 'integer' && isset($options['default'])) { - $options['default'] = (int)$options['default']; - } - if ($type === 'integer' && isset($options['length'])) { - $length = $options['length']; - if ($length < 4) { - $type = 'smallint'; - } else if ($length > 4) { - $type = 'bigint'; - } - } - if ($type === 'boolean' && isset($options['default'])) { - $options['default'] = $this->asBool($options['default']); - } - if (!empty($options['autoincrement']) - && !empty($options['notnull']) - ) { - $options['primary'] = true; - } - $table->addColumn($name, $type, $options); - if (!empty($options['primary']) && $options['primary']) { - $table->setPrimaryKey(array($name)); - } - } - } - - /** - * @param \Doctrine\DBAL\Schema\Table $table - * @param \SimpleXMLElement $xml - * @throws \DomainException - */ - private function loadIndex($table, $xml) { - $name = null; - $fields = array(); - foreach ($xml->children() as $child) { - /** - * @var \SimpleXMLElement $child - */ - switch ($child->getName()) { - case 'name': - $name = (string)$child; - break; - case 'primary': - $primary = $this->asBool($child); - break; - case 'unique': - $unique = $this->asBool($child); - break; - case 'field': - foreach ($child->children() as $field) { - /** - * @var \SimpleXMLElement $field - */ - switch ($field->getName()) { - case 'name': - $field_name = (string)$field; - $field_name = $this->platform->quoteIdentifier($field_name); - $fields[] = $field_name; - break; - case 'sorting': - break; - default: - throw new \DomainException('Unknown element: ' . $field->getName()); - - } - } - break; - default: - throw new \DomainException('Unknown element: ' . $child->getName()); - - } - } - if (!empty($fields)) { - if (isset($primary) && $primary) { - $table->setPrimaryKey($fields, $name); - } else - if (isset($unique) && $unique) { - $table->addUniqueIndex($fields, $name); - } else { - $table->addIndex($fields, $name); - } - } else { - throw new \DomainException('Empty index definition: ' . $name . ' options:' . print_r($fields, true)); - } - } - - /** - * @param \SimpleXMLElement | string $xml - * @return bool - */ - private function asBool($xml) { - $result = (string)$xml; - if ($result == 'true') { - $result = true; - } elseif ($result == 'false') { - $result = false; - } - return (bool)$result; - } - -} diff --git a/lib/db/mdb2schemawriter.php b/lib/db/mdb2schemawriter.php deleted file mode 100644 index 21b43cbfe80..00000000000 --- a/lib/db/mdb2schemawriter.php +++ /dev/null @@ -1,133 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_DB_MDB2SchemaWriter { - - /** - * @param $file - * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $sm - * @return bool - */ - static public function saveSchemaToFile($file, $sm) { - $xml = new SimpleXMLElement(''); - $xml->addChild('name', OC_Config::getValue( "dbname", "owncloud" )); - $xml->addChild('create', 'true'); - $xml->addChild('overwrite', 'false'); - $xml->addChild('charset', 'utf8'); - foreach ($sm->listTables() as $table) { - self::saveTable($table, $xml->addChild('table')); - } - file_put_contents($file, $xml->asXML()); - return true; - } - - private static function saveTable($table, $xml) { - $xml->addChild('name', $table->getName()); - $declaration = $xml->addChild('declaration'); - foreach($table->getColumns() as $column) { - self::saveColumn($column, $declaration->addChild('field')); - } - foreach($table->getIndexes() as $index) { - if ($index->getName() == 'PRIMARY') { - $autoincrement = false; - foreach($index->getColumns() as $column) { - if ($table->getColumn($column)->getAutoincrement()) { - $autoincrement = true; - } - } - if ($autoincrement) { - continue; - } - } - self::saveIndex($index, $declaration->addChild('index')); - } - } - - private static function saveColumn($column, $xml) { - $xml->addChild('name', $column->getName()); - switch($column->getType()) { - case 'SmallInt': - case 'Integer': - case 'BigInt': - $xml->addChild('type', 'integer'); - $default = $column->getDefault(); - if (is_null($default) && $column->getAutoincrement()) { - $default = '0'; - } - $xml->addChild('default', $default); - $xml->addChild('notnull', self::toBool($column->getNotnull())); - if ($column->getAutoincrement()) { - $xml->addChild('autoincrement', '1'); - } - if ($column->getUnsigned()) { - $xml->addChild('unsigned', 'true'); - } - $length = '4'; - if ($column->getType() == 'SmallInt') { - $length = '2'; - } - elseif ($column->getType() == 'BigInt') { - $length = '8'; - } - $xml->addChild('length', $length); - break; - case 'String': - $xml->addChild('type', 'text'); - $default = trim($column->getDefault()); - if ($default === '') { - $default = false; - } - $xml->addChild('default', $default); - $xml->addChild('notnull', self::toBool($column->getNotnull())); - $xml->addChild('length', $column->getLength()); - break; - case 'Text': - $xml->addChild('type', 'clob'); - $xml->addChild('notnull', self::toBool($column->getNotnull())); - break; - case 'Decimal': - $xml->addChild('type', 'decimal'); - $xml->addChild('default', $column->getDefault()); - $xml->addChild('notnull', self::toBool($column->getNotnull())); - $xml->addChild('length', '15'); - break; - case 'Boolean': - $xml->addChild('type', 'integer'); - $xml->addChild('default', $column->getDefault()); - $xml->addChild('notnull', self::toBool($column->getNotnull())); - $xml->addChild('length', '1'); - break; - case 'DateTime': - $xml->addChild('type', 'timestamp'); - $xml->addChild('default', $column->getDefault()); - $xml->addChild('notnull', self::toBool($column->getNotnull())); - break; - - } - } - - private static function saveIndex($index, $xml) { - $xml->addChild('name', $index->getName()); - if ($index->isPrimary()) { - $xml->addChild('primary', 'true'); - } - elseif ($index->isUnique()) { - $xml->addChild('unique', 'true'); - } - foreach($index->getColumns() as $column) { - $field = $xml->addChild('field'); - $field->addChild('name', $column); - $field->addChild('sorting', 'ascending'); - - } - } - - private static function toBool($bool) { - return $bool ? 'true' : 'false'; - } -} diff --git a/lib/db/oracleconnection.php b/lib/db/oracleconnection.php deleted file mode 100644 index e2fc4644f47..00000000000 --- a/lib/db/oracleconnection.php +++ /dev/null @@ -1,50 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\DB; - -class OracleConnection extends Connection { - /** - * Quote the keys of the array - */ - private function quoteKeys(array $data) { - $return = array(); - foreach($data as $key => $value) { - $return[$this->quoteIdentifier($key)] = $value; - } - return $return; - } - - /* - * {@inheritDoc} - */ - public function insert($tableName, array $data, array $types = array()) { - $tableName = $this->quoteIdentifier($tableName); - $data = $this->quoteKeys($data); - return parent::insert($tableName, $data, $types); - } - - /* - * {@inheritDoc} - */ - public function update($tableName, array $data, array $identifier, array $types = array()) { - $tableName = $this->quoteIdentifier($tableName); - $data = $this->quoteKeys($data); - $identifier = $this->quoteKeys($identifier); - return parent::update($tableName, $data, $identifier, $types); - } - - /* - * {@inheritDoc} - */ - public function delete($tableName, array $identifier) { - $tableName = $this->quoteIdentifier($tableName); - $identifier = $this->quoteKeys($identifier); - return parent::delete($tableName, $identifier); - } -} diff --git a/lib/db/statementwrapper.php b/lib/db/statementwrapper.php deleted file mode 100644 index b8da1afc0e5..00000000000 --- a/lib/db/statementwrapper.php +++ /dev/null @@ -1,191 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * small wrapper around \Doctrine\DBAL\Driver\Statement to make it behave, more like an MDB2 Statement - */ -class OC_DB_StatementWrapper { - /** - * @var \Doctrine\DBAL\Driver\Statement - */ - private $statement = null; - private $isManipulation = false; - private $lastArguments = array(); - - public function __construct($statement, $isManipulation) { - $this->statement = $statement; - $this->isManipulation = $isManipulation; - } - - /** - * pass all other function directly to the \Doctrine\DBAL\Driver\Statement - */ - public function __call($name,$arguments) { - return call_user_func_array(array($this->statement,$name), $arguments); - } - - /** - * provide numRows - */ - public function numRows() { - $type = OC_Config::getValue( "dbtype", "sqlite" ); - if ($type == 'oci') { - // OCI doesn't have a queryString, just do a rowCount for now - return $this->statement->rowCount(); - } - $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i'; - $queryString = $this->statement->getWrappedStatement()->queryString; - if (preg_match($regex, $queryString, $output) > 0) { - $query = OC_DB::prepare("SELECT COUNT(*) FROM {$output[1]}"); - return $query->execute($this->lastArguments)->fetchColumn(); - }else{ - return $this->statement->rowCount(); - } - } - - /** - * make execute return the result instead of a bool - */ - public function execute($input=array()) { - if(OC_Config::getValue( "log_query", false)) { - $params_str = str_replace("\n", " ", var_export($input, true)); - OC_Log::write('core', 'DB execute with arguments : '.$params_str, OC_Log::DEBUG); - } - $this->lastArguments = $input; - if (count($input) > 0) { - - if (!isset($type)) { - $type = OC_Config::getValue( "dbtype", "sqlite" ); - } - - if ($type == 'mssql') { - $input = $this->tryFixSubstringLastArgumentDataForMSSQL($input); - } - - $result = $this->statement->execute($input); - } else { - $result = $this->statement->execute(); - } - - if ($result === false) { - return false; - } - if ($this->isManipulation) { - return $this->statement->rowCount(); - } else { - return $this; - } - } - - private function tryFixSubstringLastArgumentDataForMSSQL($input) { - $query = $this->statement->getWrappedStatement()->queryString; - $pos = stripos ($query, 'SUBSTRING'); - - if ( $pos === false) { - return $input; - } - - try { - $newQuery = ''; - - $cArg = 0; - - $inSubstring = false; - - // Create new query - for ($i = 0; $i < strlen ($query); $i++) { - if ($inSubstring == false) { - // Defines when we should start inserting values - if (substr ($query, $i, 9) == 'SUBSTRING') { - $inSubstring = true; - } - } else { - // Defines when we should stop inserting values - if (substr ($query, $i, 1) == ')') { - $inSubstring = false; - } - } - - if (substr ($query, $i, 1) == '?') { - // We found a question mark - if ($inSubstring) { - $newQuery .= $input[$cArg]; - - // - // Remove from input array - // - array_splice ($input, $cArg, 1); - } else { - $newQuery .= substr ($query, $i, 1); - $cArg++; - } - } else { - $newQuery .= substr ($query, $i, 1); - } - } - - // The global data we need - $name = OC_Config::getValue( "dbname", "owncloud" ); - $host = OC_Config::getValue( "dbhost", "" ); - $user = OC_Config::getValue( "dbuser", "" ); - $pass = OC_Config::getValue( "dbpassword", "" ); - if (strpos($host, ':')) { - list($host, $port) = explode(':', $host, 2); - } else { - $port = false; - } - $opts = array(); - - if ($port) { - $dsn = 'sqlsrv:Server='.$host.','.$port.';Database='.$name; - } else { - $dsn = 'sqlsrv:Server='.$host.';Database='.$name; - } - - $PDO = new PDO($dsn, $user, $pass, $opts); - $PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); - $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - - $this->statement = $PDO->prepare($newQuery); - - $this->lastArguments = $input; - - return $input; - } catch (PDOException $e){ - $entry = 'PDO DB Error: "'.$e->getMessage().'"
'; - $entry .= 'Offending command was: '.$this->statement->queryString .'
'; - $entry .= 'Input parameters: ' .print_r($input, true).'
'; - $entry .= 'Stack trace: ' .$e->getTraceAsString().'
'; - OC_Log::write('core', $entry, OC_Log::FATAL); - OC_User::setUserId(null); - - // send http status 503 - header('HTTP/1.1 503 Service Temporarily Unavailable'); - header('Status: 503 Service Temporarily Unavailable'); - OC_Template::printErrorPage('Failed to connect to database'); - die ($entry); - } - } - - /** - * provide an alias for fetch - */ - public function fetchRow() { - return $this->statement->fetch(); - } - - /** - * Provide a simple fetchOne. - * fetch single column from the next row - * @param int $colnum the column number to fetch - * @return string - */ - public function fetchOne($colnum = 0) { - return $this->statement->fetchColumn($colnum); - } -} diff --git a/lib/defaults.php b/lib/defaults.php deleted file mode 100644 index 10813a3e8d8..00000000000 --- a/lib/defaults.php +++ /dev/null @@ -1,135 +0,0 @@ -defaultEntity = "ownCloud"; /* e.g. company name, used for footers and copyright notices */ - $this->defaultName = "ownCloud"; /* short name, used when referring to the software */ - $this->defaultTitle = "ownCloud"; /* can be a longer name, for titles */ - $this->defaultBaseUrl = "http://owncloud.org"; - $this->defaultSyncClientUrl = " http://owncloud.org/sync-clients/"; - $this->defaultDocBaseUrl = "http://doc.owncloud.org"; - $this->defaultSlogan = $l->t("web services under your control"); - $this->defaultLogoClaim = ""; - - if (class_exists("OC_Theme")) { - $this->theme = new OC_Theme(); - } - } - - private function themeExist($method) { - if (OC_Util::getTheme() !== '' && method_exists('OC_Theme', $method)) { - return true; - } - return false; - } - - public function getBaseUrl() { - if ($this->themeExist('getBaseUrl')) { - return $this->theme->getBaseUrl(); - } else { - return $this->defaultBaseUrl; - } - } - - public function getSyncClientUrl() { - if ($this->themeExist('getSyncClientUrl')) { - return $this->theme->getSyncClientUrl(); - } else { - return $this->defaultSyncClientUrl; - } - } - - public function getDocBaseUrl() { - if ($this->themeExist('getDocBaseUrl')) { - return $this->theme->getDocBaseUrl(); - } else { - return $this->defaultDocBaseUrl; - } - } - - public function getTitle() { - if ($this->themeExist('getTitle')) { - return $this->theme->getTitle(); - } else { - return $this->defaultTitle; - } - } - - public function getName() { - if ($this->themeExist('getName')) { - return $this->theme->getName(); - } else { - return $this->defaultName; - } - } - - public function getEntity() { - if ($this->themeExist('getEntity')) { - return $this->theme->getEntity(); - } else { - return $this->defaultEntity; - } - } - - public function getSlogan() { - if ($this->themeExist('getSlogan')) { - return $this->theme->getSlogan(); - } else { - return $this->defaultSlogan; - } - } - - public function getLogoClaim() { - if ($this->themeExist('getLogoClaim')) { - return $this->theme->getLogoClaim(); - } else { - return $this->defaultLogoClaim; - } - } - - public function getShortFooter() { - if ($this->themeExist('getShortFooter')) { - $footer = $this->theme->getShortFooter(); - } else { - $footer = "getBaseUrl() . "\" target=\"_blank\">" .$this->getEntity() . "". - ' – ' . $this->getSlogan(); - } - - return $footer; - } - - public function getLongFooter() { - if ($this->themeExist('getLongFooter')) { - $footer = $this->theme->getLongFooter(); - } else { - $footer = $this->getShortFooter(); - } - - return $footer; - } - -} diff --git a/lib/eventsource.php b/lib/eventsource.php deleted file mode 100644 index a83084d9251..00000000000 --- a/lib/eventsource.php +++ /dev/null @@ -1,85 +0,0 @@ -. -* -*/ - -/** - * wrapper for server side events (http://en.wikipedia.org/wiki/Server-sent_events) - * includes a fallback for older browsers and IE - * - * use server side events with caution, to many open requests can hang the server - */ -class OC_EventSource{ - private $fallback; - private $fallBackId=0; - - public function __construct() { - OC_Util::obEnd(); - header('Cache-Control: no-cache'); - $this->fallback=isset($_GET['fallback']) and $_GET['fallback']=='true'; - if($this->fallback) { - $this->fallBackId=$_GET['fallback_id']; - header("Content-Type: text/html"); - echo str_repeat(''.PHP_EOL, 10); //dummy data to keep IE happy - }else{ - header("Content-Type: text/event-stream"); - } - if( !OC_Util::isCallRegistered()) { - $this->send('error', 'Possible CSRF attack. Connection will be closed.'); - exit(); - } - flush(); - - } - - /** - * send a message to the client - * @param string $type - * @param mixed $data - * - * if only one parameter is given, a typeless message will be send with that parameter as data - */ - public function send($type, $data=null) { - if(is_null($data)) { - $data=$type; - $type=null; - } - if($this->fallback) { - $response=''.PHP_EOL; - echo $response; - }else{ - if($type) { - echo 'event: '.$type.PHP_EOL; - } - echo 'data: '.json_encode($data).PHP_EOL; - } - echo PHP_EOL; - flush(); - } - - /** - * close the connection of the even source - */ - public function close() { - $this->send('__internal__', 'close');//server side closing can be an issue, let the client do it - } -} diff --git a/lib/filechunking.php b/lib/filechunking.php deleted file mode 100644 index 313a6ee87d2..00000000000 --- a/lib/filechunking.php +++ /dev/null @@ -1,149 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - - -class OC_FileChunking { - protected $info; - protected $cache; - - static public function decodeName($name) { - preg_match('/(?P.*)-chunking-(?P\d+)-(?P\d+)-(?P\d+)/', $name, $matches); - return $matches; - } - - public function __construct($info) { - $this->info = $info; - } - - public function getPrefix() { - $name = $this->info['name']; - $transferid = $this->info['transferid']; - - return $name.'-chunking-'.$transferid.'-'; - } - - protected function getCache() { - if (!isset($this->cache)) { - $this->cache = new \OC\Cache\File(); - } - return $this->cache; - } - - public function store($index, $data) { - $cache = $this->getCache(); - $name = $this->getPrefix().$index; - $cache->set($name, $data); - } - - public function isComplete() { - $prefix = $this->getPrefix(); - $parts = 0; - $cache = $this->getCache(); - for($i=0; $i < $this->info['chunkcount']; $i++) { - if ($cache->hasKey($prefix.$i)) { - $parts ++; - } - } - return $parts == $this->info['chunkcount']; - } - - public function assemble($f) { - $cache = $this->getCache(); - $prefix = $this->getPrefix(); - $count = 0; - for($i=0; $i < $this->info['chunkcount']; $i++) { - $chunk = $cache->get($prefix.$i); - $cache->remove($prefix.$i); - $count += fwrite($f, $chunk); - } - return $count; - } - - public function signature_split($orgfile, $input) { - $info = unpack('n', fread($input, 2)); - $blocksize = $info[1]; - $this->info['transferid'] = mt_rand(); - $count = 0; - $needed = array(); - $cache = $this->getCache(); - $prefix = $this->getPrefix(); - while (!feof($orgfile)) { - $new_md5 = fread($input, 16); - if (feof($input)) { - break; - } - $data = fread($orgfile, $blocksize); - $org_md5 = md5($data, true); - if ($org_md5 == $new_md5) { - $cache->set($prefix.$count, $data); - } else { - $needed[] = $count; - } - $count++; - } - return array( - 'transferid' => $this->info['transferid'], - 'needed' => $needed, - 'count' => $count, - ); - } - - public function file_assemble($path) { - $absolutePath = \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getView()->getAbsolutePath($path)); - $data = ''; - // use file_put_contents as method because that best matches what this function does - if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) - && \OC\Files\Filesystem::isValidPath($path)) { - $path = \OC\Files\Filesystem::getView()->getRelativePath($absolutePath); - $exists = \OC\Files\Filesystem::file_exists($path); - $run = true; - if(!$exists) { - OC_Hook::emit( - \OC\Files\Filesystem::CLASSNAME, - \OC\Files\Filesystem::signal_create, - array( - \OC\Files\Filesystem::signal_param_path => $path, - \OC\Files\Filesystem::signal_param_run => &$run - ) - ); - } - OC_Hook::emit( - \OC\Files\Filesystem::CLASSNAME, - \OC\Files\Filesystem::signal_write, - array( - \OC\Files\Filesystem::signal_param_path => $path, - \OC\Files\Filesystem::signal_param_run => &$run - ) - ); - if(!$run) { - return false; - } - $target = \OC\Files\Filesystem::fopen($path, 'w'); - if($target) { - $count = $this->assemble($target); - fclose($target); - if(!$exists) { - OC_Hook::emit( - \OC\Files\Filesystem::CLASSNAME, - \OC\Files\Filesystem::signal_post_create, - array( \OC\Files\Filesystem::signal_param_path => $path) - ); - } - OC_Hook::emit( - \OC\Files\Filesystem::CLASSNAME, - \OC\Files\Filesystem::signal_post_write, - array( \OC\Files\Filesystem::signal_param_path => $path) - ); - OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); - return $count > 0; - }else{ - return false; - } - } - } -} diff --git a/lib/fileproxy.php b/lib/fileproxy.php deleted file mode 100644 index 52ec79b4bdb..00000000000 --- a/lib/fileproxy.php +++ /dev/null @@ -1,115 +0,0 @@ -. -* -*/ - -/** - * Class for manipulating filesystem requests - * - * Manipulation happens by using 2 kind of proxy operations, pre and post proxies - * that manipulate the filesystem call and the result of the call respectively - * - * A pre-proxy recieves the filepath as arugments (or 2 filespaths in case of - * operations like copy or move) and return a boolean - * If a pre-proxy returns false the file operation will be canceled - * All filesystem operations have a pre-proxy - * - * A post-proxy recieves 2 arguments, the filepath and the result of the operation. - * The return value of the post-proxy will be used as the new result of the operation - * The operations that have a post-proxy are: - * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, - * is_writable, filemtime, filectime, file_get_contents, - * getMimeType, hash, fopen, free_space and search - */ - -class OC_FileProxy{ - private static $proxies=array(); - public static $enabled=true; - - /** - * fallback function when a proxy operation is not implemented - * @param string $function the name of the proxy operation - * @param mixed - * - * this implements a dummy proxy for all operations - */ - public function __call($function, $arguments) { - if(substr($function, 0, 3)=='pre') { - return true; - }else{ - return $arguments[1]; - } - } - - /** - * register a proxy to be used - * @param OC_FileProxy $proxy - */ - public static function register($proxy) { - self::$proxies[]=$proxy; - } - - public static function getProxies($operation) { - $proxies=array(); - foreach(self::$proxies as $proxy) { - if(method_exists($proxy, $operation)) { - $proxies[]=$proxy; - } - } - return $proxies; - } - - public static function runPreProxies($operation,&$filepath,&$filepath2=null) { - if(!self::$enabled) { - return true; - } - $operation='pre'.$operation; - $proxies=self::getProxies($operation); - foreach($proxies as $proxy) { - if(!is_null($filepath2)) { - if($proxy->$operation($filepath, $filepath2)===false) { - return false; - } - }else{ - if($proxy->$operation($filepath)===false) { - return false; - } - } - } - return true; - } - - public static function runPostProxies($operation, $path, $result) { - if(!self::$enabled) { - return $result; - } - $operation='post'.$operation; - $proxies=self::getProxies($operation); - foreach($proxies as $proxy) { - $result=$proxy->$operation($path, $result); - } - return $result; - } - - public static function clearProxies() { - self::$proxies=array(); - } -} diff --git a/lib/fileproxy/fileoperations.php b/lib/fileproxy/fileoperations.php deleted file mode 100644 index b2ff2e7e5e9..00000000000 --- a/lib/fileproxy/fileoperations.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. If not, see . - * - */ - -/** - * check if standard file operations - */ - -class OC_FileProxy_FileOperations extends OC_FileProxy{ - static $rootView; - - public function premkdir($path) { - if(!self::$rootView) { - self::$rootView = new \OC\Files\View(''); - } - return !self::$rootView->file_exists($path); - } - -} diff --git a/lib/files.php b/lib/files.php deleted file mode 100644 index c705d2adb1a..00000000000 --- a/lib/files.php +++ /dev/null @@ -1,321 +0,0 @@ -. - * - */ - -/** - * Class for fileserver access - * - */ -class OC_Files { - static $tmpFiles = array(); - - static public function getFileInfo($path){ - return \OC\Files\Filesystem::getFileInfo($path); - } - - static public function getDirectoryContent($path){ - return \OC\Files\Filesystem::getDirectoryContent($path); - } - - /** - * return the content of a file or return a zip file containing multiple files - * - * @param string $dir - * @param string $file ; separated list of files to download - * @param boolean $only_header ; boolean to only send header of the request - */ - public static function get($dir, $files, $only_header = false) { - $xsendfile = false; - if (isset($_SERVER['MOD_X_SENDFILE_ENABLED']) || - isset($_SERVER['MOD_X_SENDFILE2_ENABLED']) || - isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) { - $xsendfile = true; - } - - if (is_array($files) && count($files) == 1) { - $files = $files[0]; - } - - if (is_array($files)) { - self::validateZipDownload($dir, $files); - $executionTime = intval(ini_get('max_execution_time')); - set_time_limit(0); - $zip = new ZipArchive(); - $filename = OC_Helper::tmpFile('.zip'); - if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { - $l = OC_L10N::get('lib'); - throw new Exception($l->t('cannot open "%s"', array($filename))); - } - foreach ($files as $file) { - $file = $dir . '/' . $file; - if (\OC\Files\Filesystem::is_file($file)) { - $tmpFile = \OC\Files\Filesystem::toTmpFile($file); - self::$tmpFiles[] = $tmpFile; - $zip->addFile($tmpFile, basename($file)); - } elseif (\OC\Files\Filesystem::is_dir($file)) { - self::zipAddDir($file, $zip); - } - } - $zip->close(); - if ($xsendfile) { - $filename = OC_Helper::moveToNoClean($filename); - } - $basename = basename($dir); - if ($basename) { - $name = $basename . '.zip'; - } else { - $name = 'owncloud.zip'; - } - - set_time_limit($executionTime); - } elseif (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) { - self::validateZipDownload($dir, $files); - $executionTime = intval(ini_get('max_execution_time')); - set_time_limit(0); - $zip = new ZipArchive(); - $filename = OC_Helper::tmpFile('.zip'); - if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { - $l = OC_L10N::get('lib'); - throw new Exception($l->t('cannot open "%s"', array($filename))); - } - $file = $dir . '/' . $files; - self::zipAddDir($file, $zip); - $zip->close(); - if ($xsendfile) { - $filename = OC_Helper::moveToNoClean($filename); - } - $name = $files . '.zip'; - set_time_limit($executionTime); - } else { - $zip = false; - $filename = $dir . '/' . $files; - $name = $files; - } - OC_Util::obEnd(); - if ($zip or \OC\Files\Filesystem::isReadable($filename)) { - if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) { - header( 'Content-Disposition: attachment; filename="' . rawurlencode($name) . '"' ); - } else { - header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode($name) - . '; filename="' . rawurlencode($name) . '"' ); - } - header('Content-Transfer-Encoding: binary'); - OC_Response::disableCaching(); - if ($zip) { - ini_set('zlib.output_compression', 'off'); - header('Content-Type: application/zip'); - header('Content-Length: ' . filesize($filename)); - self::addSendfileHeader($filename); - }else{ - $filesize = \OC\Files\Filesystem::filesize($filename); - header('Content-Type: '.\OC\Files\Filesystem::getMimeType($filename)); - if ($filesize > -1) { - header("Content-Length: ".$filesize); - } - list($storage) = \OC\Files\Filesystem::resolvePath($filename); - if ($storage instanceof \OC\Files\Storage\Local) { - self::addSendfileHeader(\OC\Files\Filesystem::getLocalFile($filename)); - } - } - } elseif ($zip or !\OC\Files\Filesystem::file_exists($filename)) { - header("HTTP/1.0 404 Not Found"); - $tmpl = new OC_Template('', '404', 'guest'); - $tmpl->assign('file', $name); - $tmpl->printPage(); - } else { - header("HTTP/1.0 403 Forbidden"); - die('403 Forbidden'); - } - if($only_header) { - return ; - } - if ($zip) { - $handle = fopen($filename, 'r'); - if ($handle) { - $chunkSize = 8 * 1024; // 1 MB chunks - while (!feof($handle)) { - echo fread($handle, $chunkSize); - flush(); - } - } - if (!$xsendfile) { - unlink($filename); - } - }else{ - \OC\Files\Filesystem::readfile($filename); - } - foreach (self::$tmpFiles as $tmpFile) { - if (file_exists($tmpFile) and is_file($tmpFile)) { - unlink($tmpFile); - } - } - } - - private static function addSendfileHeader($filename) { - if (isset($_SERVER['MOD_X_SENDFILE_ENABLED'])) { - header("X-Sendfile: " . $filename); - } - if (isset($_SERVER['MOD_X_SENDFILE2_ENABLED'])) { - if (isset($_SERVER['HTTP_RANGE']) && - preg_match("/^bytes=([0-9]+)-([0-9]*)$/", $_SERVER['HTTP_RANGE'], $range)) { - $filelength = filesize($filename); - if ($range[2] == "") { - $range[2] = $filelength - 1; - } - header("Content-Range: bytes $range[1]-$range[2]/" . $filelength); - header("HTTP/1.1 206 Partial content"); - header("X-Sendfile2: " . str_replace(",", "%2c", rawurlencode($filename)) . " $range[1]-$range[2]"); - } else { - header("X-Sendfile: " . $filename); - } - } - - if (isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) { - header("X-Accel-Redirect: " . $filename); - } - } - - public static function zipAddDir($dir, $zip, $internalDir='') { - $dirname=basename($dir); - $zip->addEmptyDir($internalDir.$dirname); - $internalDir.=$dirname.='/'; - $files=OC_Files::getDirectoryContent($dir); - foreach($files as $file) { - $filename=$file['name']; - $file=$dir.'/'.$filename; - if(\OC\Files\Filesystem::is_file($file)) { - $tmpFile=\OC\Files\Filesystem::toTmpFile($file); - OC_Files::$tmpFiles[]=$tmpFile; - $zip->addFile($tmpFile, $internalDir.$filename); - }elseif(\OC\Files\Filesystem::is_dir($file)) { - self::zipAddDir($file, $zip, $internalDir); - } - } - } - - /** - * checks if the selected files are within the size constraint. If not, outputs an error page. - * - * @param dir $dir - * @param files $files - */ - static function validateZipDownload($dir, $files) { - if (!OC_Config::getValue('allowZipDownload', true)) { - $l = OC_L10N::get('lib'); - header("HTTP/1.0 409 Conflict"); - OC_Template::printErrorPage( - $l->t('ZIP download is turned off.'), - $l->t('Files need to be downloaded one by one.') - . '
' . $l->t('Back to Files') . '' - ); - exit; - } - - $zipLimit = OC_Config::getValue('maxZipInputSize', OC_Helper::computerFileSize('800 MB')); - if ($zipLimit > 0) { - $totalsize = 0; - if(!is_array($files)) { - $files = array($files); - } - foreach ($files as $file) { - $path = $dir . '/' . $file; - if(\OC\Files\Filesystem::is_dir($path)) { - foreach (\OC\Files\Filesystem::getDirectoryContent($path) as $i) { - $totalsize += $i['size']; - } - } else { - $totalsize += \OC\Files\Filesystem::filesize($path); - } - } - if ($totalsize > $zipLimit) { - $l = OC_L10N::get('lib'); - header("HTTP/1.0 409 Conflict"); - OC_Template::printErrorPage( - $l->t('Selected files too large to generate zip file.'), - $l->t('Download the files in smaller chunks, seperately or kindly ask your administrator.') - .'
' - . $l->t('Back to Files') . '' - ); - exit; - } - } - } - - /** - * set the maximum upload size limit for apache hosts using .htaccess - * - * @param int size filesisze in bytes - * @return false on failure, size on success - */ - static function setUploadLimit($size) { - //don't allow user to break his config -- upper boundary - if ($size > PHP_INT_MAX) { - //max size is always 1 byte lower than computerFileSize returns - if ($size > PHP_INT_MAX + 1) - return false; - $size -= 1; - } else { - $size = OC_Helper::humanFileSize($size); - $size = substr($size, 0, -1); //strip the B - $size = str_replace(' ', '', $size); //remove the space between the size and the postfix - } - - //don't allow user to break his config -- broken or malicious size input - if (intval($size) == 0) { - return false; - } - - $htaccess = @file_get_contents(OC::$SERVERROOT . '/.htaccess'); //supress errors in case we don't have permissions for - if (!$htaccess) { - return false; - } - - $phpValueKeys = array( - 'upload_max_filesize', - 'post_max_size' - ); - - foreach ($phpValueKeys as $key) { - $pattern = '/php_value ' . $key . ' (\S)*/'; - $setting = 'php_value ' . $key . ' ' . $size; - $hasReplaced = 0; - $content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced); - if ($content !== null) { - $htaccess = $content; - } - if ($hasReplaced == 0) { - $htaccess .= "\n" . $setting; - } - } - - //check for write permissions - if (is_writable(OC::$SERVERROOT . '/.htaccess')) { - file_put_contents(OC::$SERVERROOT . '/.htaccess', $htaccess); - return OC_Helper::computerFileSize($size); - } else { - OC_Log::write('files', - 'Can\'t write upload limit to ' . OC::$SERVERROOT . '/.htaccess. Please check the file permissions', - OC_Log::WARN); - } - return false; - } -} diff --git a/lib/files/cache/backgroundwatcher.php b/lib/files/cache/backgroundwatcher.php deleted file mode 100644 index 923804f48d0..00000000000 --- a/lib/files/cache/backgroundwatcher.php +++ /dev/null @@ -1,104 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -use \OC\Files\Mount; -use \OC\Files\Filesystem; - -class BackgroundWatcher { - static $folderMimetype = null; - - static private function getFolderMimetype() { - if (!is_null(self::$folderMimetype)) { - return self::$folderMimetype; - } - $sql = 'SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'; - $result = \OC_DB::executeAudited($sql, array('httpd/unix-directory')); - $row = $result->fetchRow(); - return $row['id']; - } - - static private function checkUpdate($id) { - $cacheItem = Cache::getById($id); - if (is_null($cacheItem)) { - return; - } - list($storageId, $internalPath) = $cacheItem; - $mounts = Filesystem::getMountByStorageId($storageId); - - if (count($mounts) === 0) { - //if the storage we need isn't mounted on default, try to find a user that has access to the storage - $permissionsCache = new Permissions($storageId); - $users = $permissionsCache->getUsers($id); - if (count($users) === 0) { - return; - } - Filesystem::initMountPoints($users[0]); - $mounts = Filesystem::getMountByStorageId($storageId); - if (count($mounts) === 0) { - return; - } - } - $storage = $mounts[0]->getStorage(); - $watcher = new Watcher($storage); - $watcher->checkUpdate($internalPath); - } - - /** - * get the next fileid in the cache - * - * @param int $previous - * @param bool $folder - * @return int - */ - static private function getNextFileId($previous, $folder) { - if ($folder) { - $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` = ? ORDER BY `fileid` ASC', 1); - } else { - $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` != ? ORDER BY `fileid` ASC', 1); - } - $result = \OC_DB::executeAudited($stmt, array($previous,self::getFolderMimetype())); - if ($row = $result->fetchRow()) { - return $row['fileid']; - } else { - return 0; - } - } - - static public function checkNext() { - // check both 1 file and 1 folder, this way new files are detected quicker because there are less folders than files usually - $previousFile = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_file', 0); - $previousFolder = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_folder', 0); - $nextFile = self::getNextFileId($previousFile, false); - $nextFolder = self::getNextFileId($previousFolder, true); - \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_file', $nextFile); - \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_folder', $nextFolder); - if ($nextFile > 0) { - self::checkUpdate($nextFile); - } - if ($nextFolder > 0) { - self::checkUpdate($nextFolder); - } - } - - static public function checkAll() { - $previous = 0; - $next = 1; - while ($next != 0) { - $next = self::getNextFileId($previous, true); - self::checkUpdate($next); - } - $previous = 0; - $next = 1; - while ($next != 0) { - $next = self::getNextFileId($previous, false); - self::checkUpdate($next); - } - } -} diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php deleted file mode 100644 index e69733727af..00000000000 --- a/lib/files/cache/cache.php +++ /dev/null @@ -1,582 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -/** - * Metadata cache for the filesystem - * - * don't use this class directly if you need to get metadata, use \OC\Files\Filesystem::getFileInfo instead - */ -class Cache { - const NOT_FOUND = 0; - const PARTIAL = 1; //only partial data available, file not cached in the database - const SHALLOW = 2; //folder in cache, but not all child files are completely scanned - const COMPLETE = 3; - - /** - * @var array partial data for the cache - */ - private $partial = array(); - - /** - * @var string - */ - private $storageId; - - /** - * @var Storage $storageCache - */ - private $storageCache; - - private $mimetypeIds = array(); - private $mimetypes = array(); - - /** - * @param \OC\Files\Storage\Storage|string $storage - */ - public function __construct($storage) { - if ($storage instanceof \OC\Files\Storage\Storage) { - $this->storageId = $storage->getId(); - } else { - $this->storageId = $storage; - } - if (strlen($this->storageId) > 64) { - $this->storageId = md5($this->storageId); - } - - $this->storageCache = new Storage($storage); - } - - public function getNumericStorageId() { - return $this->storageCache->getNumericId(); - } - - /** - * normalize mimetypes - * - * @param string $mime - * @return int - */ - public function getMimetypeId($mime) { - if (!isset($this->mimetypeIds[$mime])) { - $result = \OC_DB::executeAudited('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?', array($mime)); - if ($row = $result->fetchRow()) { - $this->mimetypeIds[$mime] = $row['id']; - } else { - $result = \OC_DB::executeAudited('INSERT INTO `*PREFIX*mimetypes`(`mimetype`) VALUES(?)', array($mime)); - $this->mimetypeIds[$mime] = \OC_DB::insertid('*PREFIX*mimetypes'); - } - $this->mimetypes[$this->mimetypeIds[$mime]] = $mime; - } - return $this->mimetypeIds[$mime]; - } - - public function getMimetype($id) { - if (!isset($this->mimetypes[$id])) { - $sql = 'SELECT `mimetype` FROM `*PREFIX*mimetypes` WHERE `id` = ?'; - $result = \OC_DB::executeAudited($sql, array($id)); - if ($row = $result->fetchRow()) { - $this->mimetypes[$id] = $row['mimetype']; - } else { - return null; - } - } - return $this->mimetypes[$id]; - } - - /** - * get the stored metadata of a file or folder - * - * @param string/int $file - * @return array | false - */ - public function get($file) { - if (is_string($file) or $file == '') { - // normalize file - $file = $this->normalize($file); - - $where = 'WHERE `storage` = ? AND `path_hash` = ?'; - $params = array($this->getNumericStorageId(), md5($file)); - } else { //file id - $where = 'WHERE `fileid` = ?'; - $params = array($file); - } - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, - `storage_mtime`, `encrypted`, `unencrypted_size`, `etag` - FROM `*PREFIX*filecache` ' . $where; - $result = \OC_DB::executeAudited($sql, $params); - $data = $result->fetchRow(); - - //FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO - //PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false - if ($data === null) { - $data = false; - } - - //merge partial data - if (!$data and is_string($file)) { - if (isset($this->partial[$file])) { - $data = $this->partial[$file]; - } - } else { - //fix types - $data['fileid'] = (int)$data['fileid']; - $data['size'] = (int)$data['size']; - $data['mtime'] = (int)$data['mtime']; - $data['encrypted'] = (bool)$data['encrypted']; - $data['unencrypted_size'] = (int)$data['unencrypted_size']; - $data['storage'] = $this->storageId; - $data['mimetype'] = $this->getMimetype($data['mimetype']); - $data['mimepart'] = $this->getMimetype($data['mimepart']); - if ($data['storage_mtime'] == 0) { - $data['storage_mtime'] = $data['mtime']; - } - } - - return $data; - } - - /** - * get the metadata of all files stored in $folder - * - * @param string $folder - * @return array - */ - public function getFolderContents($folder) { - $fileId = $this->getId($folder); - if ($fileId > -1) { - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, - `storage_mtime`, `encrypted`, `unencrypted_size`, `etag` - FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC'; - $result = \OC_DB::executeAudited($sql,array($fileId)); - $files = $result->fetchAll(); - foreach ($files as &$file) { - $file['mimetype'] = $this->getMimetype($file['mimetype']); - $file['mimepart'] = $this->getMimetype($file['mimepart']); - if ($file['storage_mtime'] == 0) { - $file['storage_mtime'] = $file['mtime']; - } - } - return $files; - } else { - return array(); - } - } - - /** - * store meta data for a file or folder - * - * @param string $file - * @param array $data - * - * @return int file id - */ - public function put($file, array $data) { - if (($id = $this->getId($file)) > -1) { - $this->update($id, $data); - return $id; - } else { - // normalize file - $file = $this->normalize($file); - - if (isset($this->partial[$file])) { //add any saved partial data - $data = array_merge($this->partial[$file], $data); - unset($this->partial[$file]); - } - - $requiredFields = array('size', 'mtime', 'mimetype'); - foreach ($requiredFields as $field) { - if (!isset($data[$field])) { //data not complete save as partial and return - $this->partial[$file] = $data; - return -1; - } - } - - $data['path'] = $file; - $data['parent'] = $this->getParentId($file); - $data['name'] = \OC_Util::basename($file); - - list($queryParts, $params) = $this->buildParts($data); - $queryParts[] = '`storage`'; - $params[] = $this->getNumericStorageId(); - $valuesPlaceholder = array_fill(0, count($queryParts), '?'); - - $sql = 'INSERT INTO `*PREFIX*filecache` (' . implode(', ', $queryParts) . ')' - . ' VALUES (' . implode(', ', $valuesPlaceholder) . ')'; - \OC_DB::executeAudited($sql, $params); - - return (int)\OC_DB::insertid('*PREFIX*filecache'); - } - } - - /** - * update the metadata in the cache - * - * @param int $id - * @param array $data - */ - public function update($id, array $data) { - - if(isset($data['path'])) { - // normalize path - $data['path'] = $this->normalize($data['path']); - } - - if(isset($data['name'])) { - // normalize path - $data['name'] = $this->normalize($data['name']); - } - - list($queryParts, $params) = $this->buildParts($data); - $params[] = $id; - - $sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? WHERE `fileid` = ?'; - \OC_DB::executeAudited($sql, $params); - } - - /** - * extract query parts and params array from data array - * - * @param array $data - * @return array - */ - function buildParts(array $data) { - $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'unencrypted_size', 'etag'); - $params = array(); - $queryParts = array(); - foreach ($data as $name => $value) { - if (array_search($name, $fields) !== false) { - if ($name === 'path') { - $params[] = md5($value); - $queryParts[] = '`path_hash`'; - } elseif ($name === 'mimetype') { - $params[] = $this->getMimetypeId(substr($value, 0, strpos($value, '/'))); - $queryParts[] = '`mimepart`'; - $value = $this->getMimetypeId($value); - } elseif ($name === 'storage_mtime') { - if (!isset($data['mtime'])) { - $params[] = $value; - $queryParts[] = '`mtime`'; - } - } elseif ($name === 'encrypted') { - // Boolean to integer conversion - $value = $value ? 1 : 0; - } - $params[] = $value; - $queryParts[] = '`' . $name . '`'; - } - } - return array($queryParts, $params); - } - - /** - * get the file id for a file - * - * @param string $file - * @return int - */ - public function getId($file) { - // normalize file - $file = $this->normalize($file); - - $pathHash = md5($file); - - $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'; - $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $pathHash)); - if ($row = $result->fetchRow()) { - return $row['fileid']; - } else { - return -1; - } - } - - /** - * get the id of the parent folder of a file - * - * @param string $file - * @return int - */ - public function getParentId($file) { - if ($file === '') { - return -1; - } else { - $parent = dirname($file); - if ($parent === '.') { - $parent = ''; - } - return $this->getId($parent); - } - } - - /** - * check if a file is available in the cache - * - * @param string $file - * @return bool - */ - public function inCache($file) { - return $this->getId($file) != -1; - } - - /** - * remove a file or folder from the cache - * - * @param string $file - */ - public function remove($file) { - $entry = $this->get($file); - if ($entry['mimetype'] === 'httpd/unix-directory') { - $children = $this->getFolderContents($file); - foreach ($children as $child) { - $this->remove($child['path']); - } - } - - $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?'; - \OC_DB::executeAudited($sql, array($entry['fileid'])); - - $permissionsCache = new Permissions($this->storageId); - $permissionsCache->remove($entry['fileid']); - } - - /** - * Move a file or folder in the cache - * - * @param string $source - * @param string $target - */ - public function move($source, $target) { - // normalize source and target - $source = $this->normalize($source); - $target = $this->normalize($target); - - $sourceData = $this->get($source); - $sourceId = $sourceData['fileid']; - $newParentId = $this->getParentId($target); - - if ($sourceData['mimetype'] === 'httpd/unix-directory') { - //find all child entries - $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?'; - $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $source . '/%')); - $childEntries = $result->fetchAll(); - $sourceLength = strlen($source); - $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); - - foreach ($childEntries as $child) { - $targetPath = $target . substr($child['path'], $sourceLength); - \OC_DB::executeAudited($query, array($targetPath, md5($targetPath), $child['fileid'])); - } - } - - $sql = 'UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?'; - \OC_DB::executeAudited($sql, array($target, md5($target), basename($target), $newParentId, $sourceId)); - } - - /** - * remove all entries for files that are stored on the storage from the cache - */ - public function clear() { - $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?'; - \OC_DB::executeAudited($sql, array($this->getNumericStorageId())); - - $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'; - \OC_DB::executeAudited($sql, array($this->storageId)); - } - - /** - * @param string $file - * - * @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE - */ - public function getStatus($file) { - // normalize file - $file = $this->normalize($file); - - $pathHash = md5($file); - $sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'; - $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $pathHash)); - if ($row = $result->fetchRow()) { - if ((int)$row['size'] === -1) { - return self::SHALLOW; - } else { - return self::COMPLETE; - } - } else { - if (isset($this->partial[$file])) { - return self::PARTIAL; - } else { - return self::NOT_FOUND; - } - } - } - - /** - * search for files matching $pattern - * - * @param string $pattern - * @return array of file data - */ - public function search($pattern) { - - // normalize pattern - $pattern = $this->normalize($pattern); - - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` - FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?'; - $result = \OC_DB::executeAudited($sql, array($pattern, $this->getNumericStorageId())); - $files = array(); - while ($row = $result->fetchRow()) { - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); - $files[] = $row; - } - return $files; - } - - /** - * search for files by mimetype - * - * @param string $mimetype - * @return array - */ - public function searchByMime($mimetype) { - if (strpos($mimetype, '/')) { - $where = '`mimetype` = ?'; - } else { - $where = '`mimepart` = ?'; - } - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` - FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'; - $mimetype = $this->getMimetypeId($mimetype); - $result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId())); - $files = array(); - while ($row = $result->fetchRow()) { - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); - $files[] = $row; - } - return $files; - } - - /** - * update the folder size and the size of all parent folders - * - * @param $path - */ - public function correctFolderSize($path) { - $this->calculateFolderSize($path); - if ($path !== '') { - $parent = dirname($path); - if ($parent === '.' or $parent === '/') { - $parent = ''; - } - $this->correctFolderSize($parent); - } - } - - /** - * get the size of a folder and set it in the cache - * - * @param string $path - * @return int - */ - public function calculateFolderSize($path) { - $totalSize = 0; - $entry = $this->get($path); - if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { - $id = $entry['fileid']; - $sql = 'SELECT SUM(`size`), MIN(`size`) FROM `*PREFIX*filecache` '. - 'WHERE `parent` = ? AND `storage` = ?'; - $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); - if ($row = $result->fetchRow()) { - list($sum, $min) = array_values($row); - $sum = (int)$sum; - $min = (int)$min; - if ($min === -1) { - $totalSize = $min; - } else { - $totalSize = $sum; - } - if ($entry['size'] !== $totalSize) { - $this->update($id, array('size' => $totalSize)); - } - - } - } - return $totalSize; - } - - /** - * get all file ids on the files on the storage - * - * @return int[] - */ - public function getAll() { - $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?'; - $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId())); - $ids = array(); - while ($row = $result->fetchRow()) { - $ids[] = $row['fileid']; - } - return $ids; - } - - /** - * find a folder in the cache which has not been fully scanned - * - * If multiply incomplete folders are in the cache, the one with the highest id will be returned, - * use the one with the highest id gives the best result with the background scanner, since that is most - * likely the folder where we stopped scanning previously - * - * @return string|bool the path of the folder or false when no folder matched - */ - public function getIncomplete() { - $query = \OC_DB::prepare('SELECT `path` FROM `*PREFIX*filecache`' - . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC',1); - $result = \OC_DB::executeAudited($query, array($this->getNumericStorageId())); - if ($row = $result->fetchRow()) { - return $row['path']; - } else { - return false; - } - } - - /** - * get the storage id of the storage for a file and the internal path of the file - * - * @param int $id - * @return array, first element holding the storage id, second the path - */ - static public function getById($id) { - $sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?'; - $result = \OC_DB::executeAudited($sql, array($id)); - if ($row = $result->fetchRow()) { - $numericId = $row['storage']; - $path = $row['path']; - } else { - return null; - } - - if ($id = Storage::getStorageId($numericId)) { - return array($id, $path); - } else { - return null; - } - } - - /** - * normalize the given path - * @param $path - * @return string - */ - public function normalize($path) { - - return \OC_Util::normalizeUnicode($path); - } -} diff --git a/lib/files/cache/legacy.php b/lib/files/cache/legacy.php deleted file mode 100644 index 8eed1f67a5d..00000000000 --- a/lib/files/cache/legacy.php +++ /dev/null @@ -1,136 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -/** - * Provide read only support for the old filecache - */ -class Legacy { - private $user; - - private $cacheHasItems = null; - - public function __construct($user) { - $this->user = $user; - } - - /** - * get the numbers of items in the legacy cache - * - * @return int - */ - function getCount() { - $sql = 'SELECT COUNT(`id`) AS `count` FROM `*PREFIX*fscache` WHERE `user` = ?'; - $result = \OC_DB::executeAudited($sql, array($this->user)); - if ($row = $result->fetchRow()) { - return $row['count']; - } else { - return 0; - } - } - - /** - * check if a legacy cache is present and holds items - * - * @return bool - */ - function hasItems() { - if (!is_null($this->cacheHasItems)) { - return $this->cacheHasItems; - } - try { - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `user` = ?',1); - } catch (\Exception $e) { - $this->cacheHasItems = false; - return false; - } - try { - $result = $query->execute(array($this->user)); - } catch (\Exception $e) { - $this->cacheHasItems = false; - return false; - } - - if ($result === false || property_exists($result, 'error_message_prefix')) { - $this->cacheHasItems = false; - return false; - } - - $this->cacheHasItems = (bool)$result->fetchRow(); - return $this->cacheHasItems; - } - - /** - * get an item from the legacy cache - * - * @param string|int $path - * @return array - */ - function get($path) { - if (is_numeric($path)) { - $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `id` = ?'; - } else { - $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?'; - } - $result = \OC_DB::executeAudited($sql, array($path)); - $data = $result->fetchRow(); - $data['etag'] = $this->getEtag($data['path'], $data['user']); - return $data; - } - - /** - * Get the ETag for the given path - * - * @param type $path - * @return string - */ - function getEtag($path, $user = null) { - static $query = null; - - $pathDetails = explode('/', $path, 4); - if((!$user) && !isset($pathDetails[1])) { - //no user!? Too odd, return empty string. - return ''; - } else if(!$user) { - //guess user from path, if no user passed. - $user = $pathDetails[1]; - } - - if(!isset($pathDetails[3]) || is_null($pathDetails[3])) { - $relativePath = ''; - } else { - $relativePath = $pathDetails[3]; - } - - if(is_null($query)){ - $query = \OC_DB::prepare('SELECT `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = \'{DAV:}getetag\''); - } - $result = \OC_DB::executeAudited($query,array($user, '/' . $relativePath)); - if ($row = $result->fetchRow()) { - return trim($row['propertyvalue'], '"'); - } else { - return ''; - } - } - - /** - * get all child items of an item from the legacy cache - * - * @param int $id - * @return array - */ - function getChildren($id) { - $result = \OC_DB::executeAudited('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?', array($id)); - $data = $result->fetchAll(); - foreach ($data as $i => $item) { - $data[$i]['etag'] = $this->getEtag($item['path'], $item['user']); - } - return $data; - } -} diff --git a/lib/files/cache/permissions.php b/lib/files/cache/permissions.php deleted file mode 100644 index 2e2bdb20b78..00000000000 --- a/lib/files/cache/permissions.php +++ /dev/null @@ -1,143 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -class Permissions { - /** - * @var string $storageId - */ - private $storageId; - - /** - * @param \OC\Files\Storage\Storage|string $storage - */ - public function __construct($storage) { - if ($storage instanceof \OC\Files\Storage\Storage) { - $this->storageId = $storage->getId(); - } else { - $this->storageId = $storage; - } - } - - /** - * get the permissions for a single file - * - * @param int $fileId - * @param string $user - * @return int (-1 if file no permissions set) - */ - public function get($fileId, $user) { - $sql = 'SELECT `permissions` FROM `*PREFIX*permissions` WHERE `user` = ? AND `fileid` = ?'; - $result = \OC_DB::executeAudited($sql, array($user, $fileId)); - if ($row = $result->fetchRow()) { - return $row['permissions']; - } else { - return -1; - } - } - - /** - * set the permissions of a file - * - * @param int $fileId - * @param string $user - * @param int $permissions - */ - public function set($fileId, $user, $permissions) { - if (self::get($fileId, $user) !== -1) { - $sql = 'UPDATE `*PREFIX*permissions` SET `permissions` = ? WHERE `user` = ? AND `fileid` = ?'; - } else { - $sql = 'INSERT INTO `*PREFIX*permissions`(`permissions`, `user`, `fileid`) VALUES(?, ?,? )'; - } - \OC_DB::executeAudited($sql, array($permissions, $user, $fileId)); - } - - /** - * get the permissions of multiply files - * - * @param int[] $fileIds - * @param string $user - * @return int[] - */ - public function getMultiple($fileIds, $user) { - if (count($fileIds) === 0) { - return array(); - } - $params = $fileIds; - $params[] = $user; - $inPart = implode(', ', array_fill(0, count($fileIds), '?')); - - $sql = 'SELECT `fileid`, `permissions` FROM `*PREFIX*permissions`' - . ' WHERE `fileid` IN (' . $inPart . ') AND `user` = ?'; - $result = \OC_DB::executeAudited($sql, $params); - $filePermissions = array(); - while ($row = $result->fetchRow()) { - $filePermissions[$row['fileid']] = $row['permissions']; - } - return $filePermissions; - } - - /** - * get the permissions for all files in a folder - * - * @param int $parentId - * @param string $user - * @return int[] - */ - public function getDirectoryPermissions($parentId, $user) { - $sql = 'SELECT `*PREFIX*permissions`.`fileid`, `permissions` - FROM `*PREFIX*permissions` - INNER JOIN `*PREFIX*filecache` ON `*PREFIX*permissions`.`fileid` = `*PREFIX*filecache`.`fileid` - WHERE `*PREFIX*filecache`.`parent` = ? AND `*PREFIX*permissions`.`user` = ?'; - - $result = \OC_DB::executeAudited($sql, array($parentId, $user)); - $filePermissions = array(); - while ($row = $result->fetchRow()) { - $filePermissions[$row['fileid']] = $row['permissions']; - } - return $filePermissions; - } - - /** - * remove the permissions for a file - * - * @param int $fileId - * @param string $user - */ - public function remove($fileId, $user = null) { - if (is_null($user)) { - \OC_DB::executeAudited('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ?', array($fileId)); - } else { - $sql = 'DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'; - \OC_DB::executeAudited($sql, array($fileId, $user)); - } - } - - public function removeMultiple($fileIds, $user) { - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'); - foreach ($fileIds as $fileId) { - \OC_DB::executeAudited($query, array($fileId, $user)); - } - } - - /** - * get the list of users which have permissions stored for a file - * - * @param int $fileId - */ - public function getUsers($fileId) { - $sql = 'SELECT `user` FROM `*PREFIX*permissions` WHERE `fileid` = ?'; - $result = \OC_DB::executeAudited($sql, array($fileId)); - $users = array(); - while ($row = $result->fetchRow()) { - $users[] = $row['user']; - } - return $users; - } -} diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php deleted file mode 100644 index 96f84609cf2..00000000000 --- a/lib/files/cache/scanner.php +++ /dev/null @@ -1,258 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -use OC\Files\Filesystem; -use OC\Hooks\BasicEmitter; - -/** - * Class Scanner - * - * Hooks available in scope \OC\Files\Cache\Scanner: - * - scanFile(string $path, string $storageId) - * - scanFolder(string $path, string $storageId) - * - * @package OC\Files\Cache - */ -class Scanner extends BasicEmitter { - /** - * @var \OC\Files\Storage\Storage $storage - */ - private $storage; - - /** - * @var string $storageId - */ - private $storageId; - - /** - * @var \OC\Files\Cache\Cache $cache - */ - private $cache; - - /** - * @var \OC\Files\Cache\Permissions $permissionsCache - */ - private $permissionsCache; - - const SCAN_RECURSIVE = true; - const SCAN_SHALLOW = false; - - const REUSE_ETAG = 1; - const REUSE_SIZE = 2; - - public function __construct(\OC\Files\Storage\Storage $storage) { - $this->storage = $storage; - $this->storageId = $this->storage->getId(); - $this->cache = $storage->getCache(); - $this->permissionsCache = $storage->getPermissionsCache(); - } - - /** - * get all the metadata of a file or folder - * * - * - * @param string $path - * @return array with metadata of the file - */ - public function getData($path) { - $data = array(); - if (!$this->storage->isReadable($path)) return null; //cant read, nothing we can do - $data['mimetype'] = $this->storage->getMimeType($path); - $data['mtime'] = $this->storage->filemtime($path); - if ($data['mimetype'] == 'httpd/unix-directory') { - $data['size'] = -1; //unknown - } else { - $data['size'] = $this->storage->filesize($path); - } - $data['etag'] = $this->storage->getETag($path); - $data['storage_mtime'] = $data['mtime']; - return $data; - } - - /** - * scan a single file and store it in the cache - * - * @param string $file - * @param int $reuseExisting - * @param bool $parentExistsInCache - * @return array with metadata of the scanned file - */ - public function scanFile($file, $reuseExisting = 0, $parentExistsInCache = false) { - if (!self::isPartialFile($file) - and !Filesystem::isFileBlacklisted($file) - ) { - $this->emit('\OC\Files\Cache\Scanner', 'scanFile', array($file, $this->storageId)); - \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId)); - $data = $this->getData($file); - if ($data) { - if ($file and !$parentExistsInCache) { - $parent = dirname($file); - if ($parent === '.' or $parent === '/') { - $parent = ''; - } - if (!$this->cache->inCache($parent)) { - $this->scanFile($parent); - } - } - $newData = $data; - $cacheData = $this->cache->get($file); - if ($cacheData) { - $this->permissionsCache->remove($cacheData['fileid']); - if ($reuseExisting) { - // prevent empty etag - $etag = $cacheData['etag']; - $propagateETagChange = false; - if (empty($etag)) { - $etag = $data['etag']; - $propagateETagChange = true; - } - // only reuse data if the file hasn't explicitly changed - if (isset($data['mtime']) && isset($cacheData['mtime']) && $data['mtime'] === $cacheData['mtime']) { - if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { - $data['size'] = $cacheData['size']; - } - if ($reuseExisting & self::REUSE_ETAG) { - $data['etag'] = $etag; - if ($propagateETagChange) { - $parent = $file; - while ($parent !== '') { - $parent = dirname($parent); - if ($parent === '.') { - $parent = ''; - } - $parentCacheData = $this->cache->get($parent); - $this->cache->update($parentCacheData['fileid'], array( - 'etag' => $this->storage->getETag($parent), - )); - } - } - } - } - // Only update metadata that has changed - $newData = array_diff($data, $cacheData); - } - } - if (!empty($newData)) { - $this->cache->put($file, $newData); - } - } else { - $this->cache->remove($file); - } - return $data; - } - return null; - } - - /** - * scan a folder and all it's children - * - * @param string $path - * @param bool $recursive - * @param int $reuse - * @return int the size of the scanned folder or -1 if the size is unknown at this stage - */ - public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) { - if ($reuse === -1) { - $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : 0; - } - $this->scanFile($path, $reuse); - return $this->scanChildren($path, $recursive, $reuse); - } - - /** - * scan all the files and folders in a folder - * - * @param string $path - * @param bool $recursive - * @param int $reuse - * @return int the size of the scanned folder or -1 if the size is unknown at this stage - */ - public function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) { - if ($reuse === -1) { - $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : 0; - } - $this->emit('\OC\Files\Cache\Scanner', 'scanFolder', array($path, $this->storageId)); - $size = 0; - $childQueue = array(); - $existingChildren = array(); - if ($this->cache->inCache($path)) { - $children = $this->cache->getFolderContents($path); - foreach ($children as $child) { - $existingChildren[] = $child['name']; - } - } - $newChildren = array(); - if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) { - \OC_DB::beginTransaction(); - if (is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - $child = ($path) ? $path . '/' . $file : $file; - if (!Filesystem::isIgnoredDir($file)) { - $newChildren[] = $file; - $data = $this->scanFile($child, $reuse, true); - if ($data) { - if ($data['size'] === -1) { - if ($recursive === self::SCAN_RECURSIVE) { - $childQueue[] = $child; - } else { - $size = -1; - } - } else if ($size !== -1) { - $size += $data['size']; - } - } - } - } - } - $removedChildren = \array_diff($existingChildren, $newChildren); - foreach ($removedChildren as $childName) { - $child = ($path) ? $path . '/' . $childName : $childName; - $this->cache->remove($child); - } - \OC_DB::commit(); - foreach ($childQueue as $child) { - $childSize = $this->scanChildren($child, self::SCAN_RECURSIVE, $reuse); - if ($childSize === -1) { - $size = -1; - } else { - $size += $childSize; - } - } - $this->cache->put($path, array('size' => $size)); - } - return $size; - } - - /** - * @brief check if the file should be ignored when scanning - * NOTE: files with a '.part' extension are ignored as well! - * prevents unfinished put requests to be scanned - * @param String $file - * @return boolean - */ - public static function isPartialFile($file) { - if (pathinfo($file, PATHINFO_EXTENSION) === 'part') { - return true; - } - return false; - } - - /** - * walk over any folders that are not fully scanned yet and scan them - */ - public function backgroundScan() { - $lastPath = null; - while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) { - $this->scan($path); - $this->cache->correctFolderSize($path); - $lastPath = $path; - } - } -} diff --git a/lib/files/cache/storage.php b/lib/files/cache/storage.php deleted file mode 100644 index 8a9e47ca36d..00000000000 --- a/lib/files/cache/storage.php +++ /dev/null @@ -1,60 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -/** - * Class Storage - * - * cache storage specific data - * - * @package OC\Files\Cache - */ -class Storage { - private $storageId; - private $numericId; - - /** - * @param \OC\Files\Storage\Storage|string $storage - */ - public function __construct($storage) { - if ($storage instanceof \OC\Files\Storage\Storage) { - $this->storageId = $storage->getId(); - } else { - $this->storageId = $storage; - } - if (strlen($this->storageId) > 64) { - $this->storageId = md5($this->storageId); - } - - $sql = 'SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'; - $result = \OC_DB::executeAudited($sql, array($this->storageId)); - if ($row = $result->fetchRow()) { - $this->numericId = $row['numeric_id']; - } else { - $sql = 'INSERT INTO `*PREFIX*storages` (`id`) VALUES(?)'; - \OC_DB::executeAudited($sql, array($this->storageId)); - $this->numericId = \OC_DB::insertid('*PREFIX*storages'); - } - } - - public function getNumericId() { - return $this->numericId; - } - - public static function getStorageId($numericId) { - - $sql = 'SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?'; - $result = \OC_DB::executeAudited($sql, array($numericId)); - if ($row = $result->fetchRow()) { - return $row['id']; - } else { - return null; - } - } -} diff --git a/lib/files/cache/updater.php b/lib/files/cache/updater.php deleted file mode 100644 index 1f30173a8f8..00000000000 --- a/lib/files/cache/updater.php +++ /dev/null @@ -1,161 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; -use OCP\Util; - -/** - * listen to filesystem hooks and change the cache accordingly - */ -class Updater { - - /** - * resolve a path to a storage and internal path - * - * @param string $path the relative path - * @return array consisting of the storage and the internal path - */ - static public function resolvePath($path) { - $view = \OC\Files\Filesystem::getView(); - return $view->resolvePath($path); - } - - /** - * perform a write update - * - * @param string $path the relative path of the file - */ - static public function writeUpdate($path) { - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = self::resolvePath($path); - if ($storage) { - $cache = $storage->getCache($internalPath); - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Scanner::SCAN_SHALLOW); - $cache->correctFolderSize($internalPath); - self::correctFolder($path, $storage->filemtime($internalPath)); - } - } - - /** - * perform a delete update - * - * @param string $path the relative path of the file - */ - static public function deleteUpdate($path) { - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = self::resolvePath($path); - if ($storage) { - $cache = $storage->getCache($internalPath); - $cache->remove($internalPath); - $cache->correctFolderSize($internalPath); - self::correctFolder($path, time()); - } - } - - /** - * preform a rename update - * - * @param string $from the relative path of the source file - * @param string $to the relative path of the target file - */ - static public function renameUpdate($from, $to) { - /** - * @var \OC\Files\Storage\Storage $storageFrom - * @var \OC\Files\Storage\Storage $storageTo - * @var string $internalFrom - * @var string $internalTo - */ - list($storageFrom, $internalFrom) = self::resolvePath($from); - list($storageTo, $internalTo) = self::resolvePath($to); - if ($storageFrom && $storageTo) { - if ($storageFrom === $storageTo) { - $cache = $storageFrom->getCache($internalFrom); - $cache->move($internalFrom, $internalTo); - $cache->correctFolderSize($internalFrom); - $cache->correctFolderSize($internalTo); - self::correctFolder($from, time()); - self::correctFolder($to, time()); - } else { - self::deleteUpdate($from); - self::writeUpdate($to); - } - } - } - - /** - * Update the mtime and ETag of all parent folders - * - * @param string $path - * @param string $time - */ - static public function correctFolder($path, $time) { - if ($path !== '' && $path !== '/') { - $parent = dirname($path); - if ($parent === '.' || $parent === '\\') { - $parent = ''; - } - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = self::resolvePath($parent); - if ($storage) { - $cache = $storage->getCache(); - $id = $cache->getId($internalPath); - if ($id !== -1) { - $cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath))); - self::correctFolder($parent, $time); - } else { - Util::writeLog('core', 'Path not in cache: '.$internalPath, Util::ERROR); - } - } - } - } - - /** - * @param array $params - */ - static public function writeHook($params) { - self::writeUpdate($params['path']); - } - - /** - * @param array $params - */ - static public function touchHook($params) { - $path = $params['path']; - list($storage, $internalPath) = self::resolvePath($path); - $cache = $storage->getCache(); - $id = $cache->getId($internalPath); - if ($id !== -1) { - $cache->update($id, array('etag' => $storage->getETag($internalPath))); - } - self::writeUpdate($path); - } - - /** - * @param array $params - */ - static public function renameHook($params) { - self::renameUpdate($params['oldpath'], $params['newpath']); - } - - /** - * @param array $params - */ - static public function deleteHook($params) { - self::deleteUpdate($params['path']); - } -} diff --git a/lib/files/cache/upgrade.php b/lib/files/cache/upgrade.php deleted file mode 100644 index cfb9a117311..00000000000 --- a/lib/files/cache/upgrade.php +++ /dev/null @@ -1,227 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -class Upgrade { - /** - * @var Legacy $legacy - */ - private $legacy; - - private $numericIds = array(); - - private $mimeTypeIds = array(); - - /** - * @param Legacy $legacy - */ - public function __construct($legacy) { - $this->legacy = $legacy; - } - - /** - * Preform a upgrade a path and it's childs - * - * @param string $path - * @param bool $mode - */ - function upgradePath($path, $mode = Scanner::SCAN_RECURSIVE) { - if (!$this->legacy->hasItems()) { - return; - } - \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $path); - if ($row = $this->legacy->get($path)) { - $data = $this->getNewData($row); - if ($data) { - $this->insert($data); - $this->upgradeChilds($data['id'], $mode); - } - } - } - - /** - * upgrade all child elements of an item - * - * @param int $id - * @param bool $mode - */ - function upgradeChilds($id, $mode = Scanner::SCAN_RECURSIVE) { - $children = $this->legacy->getChildren($id); - foreach ($children as $child) { - $childData = $this->getNewData($child); - \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $child['path']); - if ($childData) { - $this->insert($childData); - if ($mode == Scanner::SCAN_RECURSIVE) { - $this->upgradeChilds($child['id']); - } - } - } - } - - /** - * insert data into the new cache - * - * @param array $data the data for the new cache - */ - function insert($data) { - static $insertQuery = null; - if(is_null($insertQuery)) { - $insertQuery = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` - ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` ) - VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); - } - if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) { - \OC_DB::executeAudited($insertQuery, array($data['id'], $data['storage'], - $data['path'], $data['path_hash'], $data['parent'], $data['name'], - $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'], $data['etag'])); - } - } - - /** - * check if an item is already in the new cache - * - * @param string $storage - * @param string $pathHash - * @param string $id - * @return bool - */ - function inCache($storage, $pathHash, $id) { - static $query = null; - if(is_null($query)) { - $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?'); - } - $result = \OC_DB::executeAudited($query, array($storage, $pathHash, $id)); - return (bool)$result->fetchRow(); - } - - /** - * get the new data array from the old one - * - * @param array $data the data from the old cache - * Example data array - * Array - * ( - * [id] => 418 - * [path] => /tina/files/picture.jpg //relative to datadir - * [path_hash] => 66d4547e372888deed80b24fec9b192b - * [parent] => 234 - * [name] => picture.jpg - * [user] => tina - * [size] => 1265283 - * [ctime] => 1363909709 - * [mtime] => 1363909709 - * [mimetype] => image/jpeg - * [mimepart] => image - * [encrypted] => 0 - * [versioned] => 0 - * [writable] => 1 - * ) - * - * @return array - */ - function getNewData($data) { - //Make sure there is a path, otherwise we can do nothing. - if(!isset($data['path'])) { - return false; - } - $newData = $data; - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath; - */ - list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']); - if ($storage) { - $newData['etag'] = $data['etag']; - $newData['path_hash'] = md5($internalPath); - $newData['path'] = $internalPath; - $newData['storage'] = $this->getNumericId($storage); - $newData['parent'] = ($internalPath === '') ? -1 : $data['parent']; - $newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ; - $newData['storage_object'] = $storage; - $newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage); - $newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage); - return $newData; - } else { - \OC_Log::write('core', 'Unable to migrate data from old cache for '.$data['path'].' because the storage was not found', \OC_Log::ERROR); - return false; - } - } - - /** - * get the numeric storage id - * - * @param \OC\Files\Storage\Storage $storage - * @return int - */ - function getNumericId($storage) { - $storageId = $storage->getId(); - if (!isset($this->numericIds[$storageId])) { - $cache = $storage->getCache(); - $this->numericIds[$storageId] = $cache->getNumericStorageId(); - } - return $this->numericIds[$storageId]; - } - - /** - * get the numeric id for a mimetype - * - * @param string $mimetype - * @param \OC\Files\Storage\Storage $storage - * @return int - */ - function getMimetypeId($mimetype, $storage) { - if (!isset($this->mimeTypeIds[$mimetype])) { - $cache = new Cache($storage); - $this->mimeTypeIds[$mimetype] = $cache->getMimetypeId($mimetype); - } - return $this->mimeTypeIds[$mimetype]; - } - - /** - * check if a cache upgrade is required for $user - * - * @param string $user - * @return bool - */ - static function needUpgrade($user) { - $cacheVersion = (int)\OCP\Config::getUserValue($user, 'files', 'cache_version', 4); - return $cacheVersion < 5; - } - - /** - * mark the filecache as upgrade - * - * @param string $user - */ - static function upgradeDone($user) { - \OCP\Config::setUserValue($user, 'files', 'cache_version', 5); - } - - /** - * Does a "silent" upgrade, i.e. without an Event-Source as triggered - * on User-Login via Ajax. This method is called within the regular - * ownCloud upgrade. - * - * @param string $user a User ID - */ - public static function doSilentUpgrade($user) { - if(!self::needUpgrade($user)) { - return; - } - $legacy = new \OC\Files\Cache\Legacy($user); - if ($legacy->hasItems()) { - \OC_DB::beginTransaction(); - $upgrade = new \OC\Files\Cache\Upgrade($legacy); - $upgrade->upgradePath('/' . $user . '/files'); - \OC_DB::commit(); - } - \OC\Files\Cache\Upgrade::upgradeDone($user); - } -} diff --git a/lib/files/cache/watcher.php b/lib/files/cache/watcher.php deleted file mode 100644 index 8bfd4602f3a..00000000000 --- a/lib/files/cache/watcher.php +++ /dev/null @@ -1,72 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -/** - * check the storage backends for updates and change the cache accordingly - */ -class Watcher { - /** - * @var \OC\Files\Storage\Storage $storage - */ - private $storage; - - /** - * @var Cache $cache - */ - private $cache; - - /** - * @var Scanner $scanner; - */ - private $scanner; - - /** - * @param \OC\Files\Storage\Storage $storage - */ - public function __construct(\OC\Files\Storage\Storage $storage) { - $this->storage = $storage; - $this->cache = $storage->getCache(); - $this->scanner = $storage->getScanner(); - } - - /** - * check $path for updates - * - * @param string $path - */ - public function checkUpdate($path) { - $cachedEntry = $this->cache->get($path); - if ($this->storage->hasUpdated($path, $cachedEntry['storage_mtime'])) { - if ($this->storage->is_dir($path)) { - $this->scanner->scan($path, Scanner::SCAN_SHALLOW); - } else { - $this->scanner->scanFile($path); - } - if ($cachedEntry['mimetype'] === 'httpd/unix-directory') { - $this->cleanFolder($path); - } - $this->cache->correctFolderSize($path); - } - } - - /** - * remove deleted files in $path from the cache - * - * @param string $path - */ - public function cleanFolder($path) { - $cachedContent = $this->cache->getFolderContents($path); - foreach ($cachedContent as $entry) { - if (!$this->storage->file_exists($entry['path'])) { - $this->cache->remove($entry['path']); - } - } - } -} diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php deleted file mode 100644 index 10ec5c41d11..00000000000 --- a/lib/files/filesystem.php +++ /dev/null @@ -1,770 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * Class for abstraction of filesystem functions - * This class won't call any filesystem functions for itself but will pass them to the correct OC_Filestorage object - * this class should also handle all the file permission related stuff - * - * Hooks provided: - * read(path) - * write(path, &run) - * post_write(path) - * create(path, &run) (when a file is created, both create and write will be emitted in that order) - * post_create(path) - * delete(path, &run) - * post_delete(path) - * rename(oldpath,newpath, &run) - * post_rename(oldpath,newpath) - * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order) - * post_rename(oldpath,newpath) - * post_initMountPoints(user, user_dir) - * - * the &run parameter can be set to false to prevent the operation from occurring - */ - -namespace OC\Files; - -use OC\Files\Storage\Loader; -const SPACE_NOT_COMPUTED = -1; -const SPACE_UNKNOWN = -2; -const SPACE_UNLIMITED = -3; - -class Filesystem { - /** - * @var Mount\Manager $mounts - */ - private static $mounts; - - public static $loaded = false; - /** - * @var \OC\Files\View $defaultInstance - */ - static private $defaultInstance; - - - /** - * classname which used for hooks handling - * used as signalclass in OC_Hooks::emit() - */ - const CLASSNAME = 'OC_Filesystem'; - - /** - * signalname emitted before file renaming - * - * @param string $oldpath - * @param string $newpath - */ - const signal_rename = 'rename'; - - /** - * signal emitted after file renaming - * - * @param string $oldpath - * @param string $newpath - */ - const signal_post_rename = 'post_rename'; - - /** - * signal emitted before file/dir creation - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_create = 'create'; - - /** - * signal emitted after file/dir creation - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_post_create = 'post_create'; - - /** - * signal emits before file/dir copy - * - * @param string $oldpath - * @param string $newpath - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_copy = 'copy'; - - /** - * signal emits after file/dir copy - * - * @param string $oldpath - * @param string $newpath - */ - const signal_post_copy = 'post_copy'; - - /** - * signal emits before file/dir save - * - * @param string $path - * @param bool $run changing this flag to false in hook handler will cancel event - */ - const signal_write = 'write'; - - /** - * signal emits after file/dir save - * - * @param string $path - */ - const signal_post_write = 'post_write'; - - /** - * signal emits when reading file/dir - * - * @param string $path - */ - const signal_read = 'read'; - - /** - * signal emits when removing file/dir - * - * @param string $path - */ - const signal_delete = 'delete'; - - /** - * parameters definitions for signals - */ - const signal_param_path = 'path'; - const signal_param_oldpath = 'oldpath'; - const signal_param_newpath = 'newpath'; - - /** - * run - changing this flag to false in hook handler will cancel event - */ - const signal_param_run = 'run'; - - /** - * @var \OC\Files\Storage\Loader $loader - */ - private static $loader; - - /** - * @param callable $wrapper - */ - public static function addStorageWrapper($wrapper) { - self::getLoader()->addStorageWrapper($wrapper); - - $mounts = self::getMountManager()->getAll(); - foreach ($mounts as $mount) { - $mount->wrapStorage($wrapper); - } - } - - public static function getLoader() { - if (!self::$loader) { - self::$loader = new Loader(); - } - return self::$loader; - } - - public static function getMountManager() { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - return self::$mounts; - } - - /** - * get the mountpoint of the storage object for a path - * ( note: because a storage is not always mounted inside the fakeroot, the - * returned mountpoint is relative to the absolute root of the filesystem - * and doesn't take the chroot into account ) - * - * @param string $path - * @return string - */ - static public function getMountPoint($path) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = self::$mounts->find($path); - if ($mount) { - return $mount->getMountPoint(); - } else { - return ''; - } - } - - /** - * get a list of all mount points in a directory - * - * @param string $path - * @return string[] - */ - static public function getMountPoints($path) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $result = array(); - $mounts = self::$mounts->findIn($path); - foreach ($mounts as $mount) { - $result[] = $mount->getMountPoint(); - } - return $result; - } - - /** - * get the storage mounted at $mountPoint - * - * @param string $mountPoint - * @return \OC\Files\Storage\Storage - */ - public static function getStorage($mountPoint) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = self::$mounts->find($mountPoint); - return $mount->getStorage(); - } - - /** - * @param $id - * @return Mount\Mount[] - */ - public static function getMountByStorageId($id) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - return self::$mounts->findByStorageId($id); - } - - /** - * @param $id - * @return Mount\Mount[] - */ - public static function getMountByNumericId($id) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - return self::$mounts->findByNumericId($id); - } - - /** - * resolve a path to a storage and internal path - * - * @param string $path - * @return array consisting of the storage and the internal path - */ - static public function resolvePath($path) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = self::$mounts->find($path); - if ($mount) { - return array($mount->getStorage(), $mount->getInternalPath($path)); - } else { - return array(null, null); - } - } - - static public function init($user, $root) { - if (self::$defaultInstance) { - return false; - } - self::getLoader(); - self::$defaultInstance = new View($root); - - if (!self::$mounts) { - self::$mounts = new Mount\Manager(); - } - - //load custom mount config - self::initMountPoints($user); - - self::$loaded = true; - - return true; - } - - static public function initMounts() { - if (!self::$mounts) { - self::$mounts = new Mount\Manager(); - } - } - - /** - * Initialize system and personal mount points for a user - * - * @param string $user - */ - public static function initMountPoints($user = '') { - if ($user == '') { - $user = \OC_User::getUser(); - } - $parser = new \OC\ArrayParser(); - - $root = \OC_User::getHome($user); - self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user); - $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data"); - - //move config file to it's new position - if (is_file(\OC::$SERVERROOT . '/config/mount.json')) { - rename(\OC::$SERVERROOT . '/config/mount.json', $datadir . '/mount.json'); - } - // Load system mount points - if (is_file(\OC::$SERVERROOT . '/config/mount.php') or is_file($datadir . '/mount.json')) { - if (is_file($datadir . '/mount.json')) { - $mountConfig = json_decode(file_get_contents($datadir . '/mount.json'), true); - } elseif (is_file(\OC::$SERVERROOT . '/config/mount.php')) { - $mountConfig = $parser->parsePHP(file_get_contents(\OC::$SERVERROOT . '/config/mount.php')); - } - if (isset($mountConfig['global'])) { - foreach ($mountConfig['global'] as $mountPoint => $options) { - self::mount($options['class'], $options['options'], $mountPoint); - } - } - if (isset($mountConfig['group'])) { - foreach ($mountConfig['group'] as $group => $mounts) { - if (\OC_Group::inGroup($user, $group)) { - foreach ($mounts as $mountPoint => $options) { - $mountPoint = self::setUserVars($user, $mountPoint); - foreach ($options as &$option) { - $option = self::setUserVars($user, $option); - } - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } - } - if (isset($mountConfig['user'])) { - foreach ($mountConfig['user'] as $mountUser => $mounts) { - if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) { - foreach ($mounts as $mountPoint => $options) { - $mountPoint = self::setUserVars($user, $mountPoint); - foreach ($options as &$option) { - $option = self::setUserVars($user, $option); - } - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } - } - } - // Load personal mount points - if (is_file($root . '/mount.php') or is_file($root . '/mount.json')) { - if (is_file($root . '/mount.json')) { - $mountConfig = json_decode(file_get_contents($root . '/mount.json'), true); - } elseif (is_file($root . '/mount.php')) { - $mountConfig = $parser->parsePHP(file_get_contents($root . '/mount.php')); - } - if (isset($mountConfig['user'][$user])) { - foreach ($mountConfig['user'][$user] as $mountPoint => $options) { - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } - - // Chance to mount for other storages - \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root)); - } - - /** - * fill in the correct values for $user - * - * @param string $user - * @param string $input - * @return string - */ - private static function setUserVars($user, $input) { - return str_replace('$user', $user, $input); - } - - /** - * get the default filesystem view - * - * @return View - */ - static public function getView() { - return self::$defaultInstance; - } - - /** - * tear down the filesystem, removing all storage providers - */ - static public function tearDown() { - self::clearMounts(); - self::$defaultInstance = null; - } - - /** - * @brief get the relative path of the root data directory for the current user - * @return string - * - * Returns path like /admin/files - */ - static public function getRoot() { - return self::$defaultInstance->getRoot(); - } - - /** - * clear all mounts and storage backends - */ - public static function clearMounts() { - if (self::$mounts) { - self::$mounts->clear(); - } - } - - /** - * mount an \OC\Files\Storage\Storage in our virtual filesystem - * - * @param \OC\Files\Storage\Storage|string $class - * @param array $arguments - * @param string $mountpoint - */ - static public function mount($class, $arguments, $mountpoint) { - if (!self::$mounts) { - \OC_Util::setupFS(); - } - $mount = new Mount\Mount($class, $mountpoint, $arguments, self::getLoader()); - self::$mounts->addMount($mount); - } - - /** - * return the path to a local version of the file - * we need this because we can't know if a file is stored local or not from - * outside the filestorage and for some purposes a local file is needed - * - * @param string $path - * @return string - */ - static public function getLocalFile($path) { - return self::$defaultInstance->getLocalFile($path); - } - - /** - * @param string $path - * @return string - */ - static public function getLocalFolder($path) { - return self::$defaultInstance->getLocalFolder($path); - } - - /** - * return path to file which reflects one visible in browser - * - * @param string $path - * @return string - */ - static public function getLocalPath($path) { - $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files'; - $newpath = $path; - if (strncmp($newpath, $datadir, strlen($datadir)) == 0) { - $newpath = substr($path, strlen($datadir)); - } - return $newpath; - } - - /** - * check if the requested path is valid - * - * @param string $path - * @return bool - */ - static public function isValidPath($path) { - $path = self::normalizePath($path); - if (!$path || $path[0] !== '/') { - $path = '/' . $path; - } - if (strstr($path, '/../') || strrchr($path, '/') === '/..') { - return false; - } - return true; - } - - /** - * checks if a file is blacklisted for storage in the filesystem - * Listens to write and rename hooks - * - * @param array $data from hook - */ - static public function isBlacklisted($data) { - if (isset($data['path'])) { - $path = $data['path']; - } else if (isset($data['newpath'])) { - $path = $data['newpath']; - } - if (isset($path)) { - if (self::isFileBlacklisted($path)) { - $data['run'] = false; - } - } - } - - /** - * @param string $filename - * @return bool - */ - static public function isFileBlacklisted($filename) { - $blacklist = \OC_Config::getValue('blacklisted_files', array('.htaccess')); - $filename = strtolower(basename($filename)); - return (in_array($filename, $blacklist)); - } - - /** - * @brief check if the directory should be ignored when scanning - * NOTE: the special directories . and .. would cause never ending recursion - * @param String $dir - * @return boolean - */ - static public function isIgnoredDir($dir) { - if ($dir === '.' || $dir === '..') { - return true; - } - return false; - } - - /** - * following functions are equivalent to their php builtin equivalents for arguments/return values. - */ - static public function mkdir($path) { - return self::$defaultInstance->mkdir($path); - } - - static public function rmdir($path) { - return self::$defaultInstance->rmdir($path); - } - - static public function opendir($path) { - return self::$defaultInstance->opendir($path); - } - - static public function readdir($path) { - return self::$defaultInstance->readdir($path); - } - - static public function is_dir($path) { - return self::$defaultInstance->is_dir($path); - } - - static public function is_file($path) { - return self::$defaultInstance->is_file($path); - } - - static public function stat($path) { - return self::$defaultInstance->stat($path); - } - - static public function filetype($path) { - return self::$defaultInstance->filetype($path); - } - - static public function filesize($path) { - return self::$defaultInstance->filesize($path); - } - - static public function readfile($path) { - return self::$defaultInstance->readfile($path); - } - - static public function isCreatable($path) { - return self::$defaultInstance->isCreatable($path); - } - - static public function isReadable($path) { - return self::$defaultInstance->isReadable($path); - } - - static public function isUpdatable($path) { - return self::$defaultInstance->isUpdatable($path); - } - - static public function isDeletable($path) { - return self::$defaultInstance->isDeletable($path); - } - - static public function isSharable($path) { - return self::$defaultInstance->isSharable($path); - } - - static public function file_exists($path) { - return self::$defaultInstance->file_exists($path); - } - - static public function filemtime($path) { - return self::$defaultInstance->filemtime($path); - } - - static public function touch($path, $mtime = null) { - return self::$defaultInstance->touch($path, $mtime); - } - - static public function file_get_contents($path) { - return self::$defaultInstance->file_get_contents($path); - } - - static public function file_put_contents($path, $data) { - return self::$defaultInstance->file_put_contents($path, $data); - } - - static public function unlink($path) { - return self::$defaultInstance->unlink($path); - } - - static public function rename($path1, $path2) { - return self::$defaultInstance->rename($path1, $path2); - } - - static public function copy($path1, $path2) { - return self::$defaultInstance->copy($path1, $path2); - } - - static public function fopen($path, $mode) { - return self::$defaultInstance->fopen($path, $mode); - } - - static public function toTmpFile($path) { - return self::$defaultInstance->toTmpFile($path); - } - - static public function fromTmpFile($tmpFile, $path) { - return self::$defaultInstance->fromTmpFile($tmpFile, $path); - } - - static public function getMimeType($path) { - return self::$defaultInstance->getMimeType($path); - } - - static public function hash($type, $path, $raw = false) { - return self::$defaultInstance->hash($type, $path, $raw); - } - - static public function free_space($path = '/') { - return self::$defaultInstance->free_space($path); - } - - static public function search($query) { - return self::$defaultInstance->search($query); - } - - static public function searchByMime($query) { - return self::$defaultInstance->searchByMime($query); - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - */ - static public function hasUpdated($path, $time) { - return self::$defaultInstance->hasUpdated($path, $time); - } - - /** - * @brief Fix common problems with a file path - * @param string $path - * @param bool $stripTrailingSlash - * @return string - */ - public static function normalizePath($path, $stripTrailingSlash = true) { - if ($path == '') { - return '/'; - } - //no windows style slashes - $path = str_replace('\\', '/', $path); - //add leading slash - if ($path[0] !== '/') { - $path = '/' . $path; - } - //remove duplicate slashes - while (strpos($path, '//') !== false) { - $path = str_replace('//', '/', $path); - } - //remove trailing slash - if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') { - $path = substr($path, 0, -1); - } - //normalize unicode if possible - $path = \OC_Util::normalizeUnicode($path); - - return $path; - } - - /** - * get the filesystem info - * - * @param string $path - * @return array - * - * returns an associative array with the following keys: - * - size - * - mtime - * - mimetype - * - encrypted - * - versioned - */ - public static function getFileInfo($path) { - return self::$defaultInstance->getFileInfo($path); - } - - /** - * change file metadata - * - * @param string $path - * @param array $data - * @return int - * - * returns the fileid of the updated file - */ - public static function putFileInfo($path, $data) { - return self::$defaultInstance->putFileInfo($path, $data); - } - - /** - * get the content of a directory - * - * @param string $directory path under datadirectory - * @param string $mimetype_filter limit returned content to this mimetype or mimepart - * @return array - */ - public static function getDirectoryContent($directory, $mimetype_filter = '') { - return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter); - } - - /** - * Get the path of a file by id - * - * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file - * - * @param int $id - * @return string - */ - public static function getPath($id) { - return self::$defaultInstance->getPath($id); - } - - /** - * Get the owner for a file or folder - * - * @param string $path - * @return string - */ - public static function getOwner($path) { - return self::$defaultInstance->getOwner($path); - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - static public function getETag($path) { - return self::$defaultInstance->getETag($path); - } -} - -\OC_Util::setupFS(); diff --git a/lib/files/mapper.php b/lib/files/mapper.php deleted file mode 100644 index 47abd4e52fe..00000000000 --- a/lib/files/mapper.php +++ /dev/null @@ -1,239 +0,0 @@ -unchangedPhysicalRoot = $rootDir; - } - - /** - * @param string $logicPath - * @param bool $create indicates if the generated physical name shall be stored in the database or not - * @return string the physical path - */ - public function logicToPhysical($logicPath, $create) { - $physicalPath = $this->resolveLogicPath($logicPath); - if ($physicalPath !== null) { - return $physicalPath; - } - - return $this->create($logicPath, $create); - } - - /** - * @param string $physicalPath - * @return string - */ - public function physicalToLogic($physicalPath) { - $logicPath = $this->resolvePhysicalPath($physicalPath); - if ($logicPath !== null) { - return $logicPath; - } - - $this->insert($physicalPath, $physicalPath); - return $physicalPath; - } - - /** - * @param string $path - * @param bool $isLogicPath indicates if $path is logical or physical - * @param $recursive - * @return void - */ - public function removePath($path, $isLogicPath, $recursive) { - if ($recursive) { - $path=$path.'%'; - } - - if ($isLogicPath) { - \OC_DB::executeAudited('DELETE FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?', array($path)); - } else { - \OC_DB::executeAudited('DELETE FROM `*PREFIX*file_map` WHERE `physic_path` LIKE ?', array($path)); - } - } - - /** - * @param $path1 - * @param $path2 - * @throws \Exception - */ - public function copy($path1, $path2) - { - $path1 = $this->stripLast($path1); - $path2 = $this->stripLast($path2); - $physicPath1 = $this->logicToPhysical($path1, true); - $physicPath2 = $this->logicToPhysical($path2, true); - - $sql = 'SELECT * FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?'; - $result = \OC_DB::executeAudited($sql, array($path1.'%')); - $updateQuery = \OC_DB::prepare('UPDATE `*PREFIX*file_map`' - .' SET `logic_path` = ?' - .' , `logic_path_hash` = ?' - .' , `physic_path` = ?' - .' , `physic_path_hash` = ?' - .' WHERE `logic_path` = ?'); - while( $row = $result->fetchRow()) { - $currentLogic = $row['logic_path']; - $currentPhysic = $row['physic_path']; - $newLogic = $path2.$this->stripRootFolder($currentLogic, $path1); - $newPhysic = $physicPath2.$this->stripRootFolder($currentPhysic, $physicPath1); - if ($path1 !== $currentLogic) { - try { - \OC_DB::executeAudited($updateQuery, array($newLogic, md5($newLogic), $newPhysic, md5($newPhysic), - $currentLogic)); - } catch (\Exception $e) { - error_log('Mapper::Copy failed '.$currentLogic.' -> '.$newLogic.'\n'.$e); - throw $e; - } - } - } - } - - /** - * @param $path - * @param $root - * @return bool|string - */ - public function stripRootFolder($path, $root) { - if (strpos($path, $root) !== 0) { - // throw exception ??? - return false; - } - if (strlen($path) > strlen($root)) { - return substr($path, strlen($root)); - } - - return ''; - } - - private function stripLast($path) { - if (substr($path, -1) == '/') { - $path = substr_replace($path, '', -1); - } - return $path; - } - - private function resolveLogicPath($logicPath) { - $logicPath = $this->stripLast($logicPath); - $sql = 'SELECT * FROM `*PREFIX*file_map` WHERE `logic_path_hash` = ?'; - $result = \OC_DB::executeAudited($sql, array(md5($logicPath))); - $result = $result->fetchRow(); - if ($result === false) { - return null; - } - - return $result['physic_path']; - } - - private function resolvePhysicalPath($physicalPath) { - $physicalPath = $this->stripLast($physicalPath); - $sql = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `physic_path_hash` = ?'); - $result = \OC_DB::executeAudited($sql, array(md5($physicalPath))); - $result = $result->fetchRow(); - - return $result['logic_path']; - } - - private function create($logicPath, $store) { - $logicPath = $this->stripLast($logicPath); - $index = 0; - - // create the slugified path - $physicalPath = $this->slugifyPath($logicPath); - - // detect duplicates - while ($this->resolvePhysicalPath($physicalPath) !== null) { - $physicalPath = $this->slugifyPath($logicPath, $index++); - } - - // insert the new path mapping if requested - if ($store) { - $this->insert($logicPath, $physicalPath); - } - - return $physicalPath; - } - - private function insert($logicPath, $physicalPath) { - $sql = 'INSERT INTO `*PREFIX*file_map` (`logic_path`, `physic_path`, `logic_path_hash`, `physic_path_hash`) - VALUES (?, ?, ?, ?)'; - \OC_DB::executeAudited($sql, array($logicPath, $physicalPath, md5($logicPath), md5($physicalPath))); - } - - public function slugifyPath($path, $index=null) { - $path = $this->stripRootFolder($path, $this->unchangedPhysicalRoot); - - $pathElements = explode('/', $path); - $sluggedElements = array(); - - $last= end($pathElements); - - foreach ($pathElements as $pathElement) { - // remove empty elements - if (empty($pathElement)) { - continue; - } - - $sluggedElements[] = self::slugify($pathElement); - } - - // apply index to file name - if ($index !== null) { - $last= array_pop($sluggedElements); - - // if filename contains periods - add index number before last period - if (preg_match('~\.[^\.]+$~i',$last,$extension)){ - array_push($sluggedElements, substr($last,0,-(strlen($extension[0]))).'-'.$index.$extension[0]); - } else { - // if filename doesn't contain periods add index ofter the last char - array_push($sluggedElements, $last.'-'.$index); - } - - } - - $sluggedPath = $this->unchangedPhysicalRoot.implode('/', $sluggedElements); - return $this->stripLast($sluggedPath); - } - - /** - * Modifies a string to remove all non ASCII characters and spaces. - * - * @param string $text - * @return string - */ - private function slugify($text) - { - // replace non letter or digits or dots by - - $text = preg_replace('~[^\\pL\d\.]+~u', '-', $text); - - // trim - $text = trim($text, '-'); - - // transliterate - if (function_exists('iconv')) { - $text = iconv('utf-8', 'us-ascii//TRANSLIT//IGNORE', $text); - } - - // lowercase - $text = strtolower($text); - - // remove unwanted characters - $text = preg_replace('~[^-\w\.]+~', '', $text); - - // trim ending dots (for security reasons and win compatibility) - $text = preg_replace('~\.+$~', '', $text); - - if (empty($text)) { - return uniqid(); - } - - return $text; - } -} diff --git a/lib/files/mount/manager.php b/lib/files/mount/manager.php deleted file mode 100644 index 4c432dcf724..00000000000 --- a/lib/files/mount/manager.php +++ /dev/null @@ -1,127 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Mount; - -use \OC\Files\Filesystem; - -class Manager { - /** - * @var Mount[] - */ - private $mounts = array(); - - /** - * @param Mount $mount - */ - public function addMount($mount) { - $this->mounts[$mount->getMountPoint()] = $mount; - } - - /** - * Find the mount for $path - * - * @param $path - * @return Mount - */ - public function find($path) { - \OC_Util::setupFS(); - $path = $this->formatPath($path); - if (isset($this->mounts[$path])) { - return $this->mounts[$path]; - } - - \OC_Hook::emit('OC_Filesystem', 'get_mountpoint', array('path' => $path)); - $foundMountPoint = ''; - $mountPoints = array_keys($this->mounts); - foreach ($mountPoints as $mountpoint) { - if (strpos($path, $mountpoint) === 0 and strlen($mountpoint) > strlen($foundMountPoint)) { - $foundMountPoint = $mountpoint; - } - } - if (isset($this->mounts[$foundMountPoint])) { - return $this->mounts[$foundMountPoint]; - } else { - return null; - } - } - - /** - * Find all mounts in $path - * - * @param $path - * @return Mount[] - */ - public function findIn($path) { - \OC_Util::setupFS(); - $path = $this->formatPath($path); - $result = array(); - $pathLength = strlen($path); - $mountPoints = array_keys($this->mounts); - foreach ($mountPoints as $mountPoint) { - if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) { - $result[] = $this->mounts[$mountPoint]; - } - } - return $result; - } - - public function clear() { - $this->mounts = array(); - } - - /** - * Find mounts by storage id - * - * @param string $id - * @return Mount[] - */ - public function findByStorageId($id) { - \OC_Util::setupFS(); - if (strlen($id) > 64) { - $id = md5($id); - } - $result = array(); - foreach ($this->mounts as $mount) { - if ($mount->getStorageId() === $id) { - $result[] = $mount; - } - } - return $result; - } - - /** - * @return Mount[] - */ - public function getAll() { - return $this->mounts; - } - - /** - * Find mounts by numeric storage id - * - * @param string $id - * @return Mount - */ - public function findByNumericId($id) { - $storageId = \OC\Files\Cache\Storage::getStorageId($id); - return $this->findByStorageId($storageId); - } - - /** - * @param string $path - * @return string - */ - private function formatPath($path) { - $path = Filesystem::normalizePath($path); - if (strlen($path) > 1) { - $path .= '/'; - } - return $path; - } -} diff --git a/lib/files/mount/mount.php b/lib/files/mount/mount.php deleted file mode 100644 index 0ce2f5975c7..00000000000 --- a/lib/files/mount/mount.php +++ /dev/null @@ -1,148 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Mount; - -use \OC\Files\Filesystem; -use OC\Files\Storage\Loader; -use OC\Files\Storage\Storage; - -class Mount { - /** - * @var \OC\Files\Storage\Storage $storage - */ - private $storage = null; - private $class; - private $storageId; - private $arguments = array(); - private $mountPoint; - - /** - * @var \OC\Files\Storage\Loader $loader - */ - private $loader; - - /** - * @param string | \OC\Files\Storage\Storage $storage - * @param string $mountpoint - * @param array $arguments (optional)\ - * @param \OC\Files\Storage\Loader $loader - */ - public function __construct($storage, $mountpoint, $arguments = null, $loader = null) { - if (is_null($arguments)) { - $arguments = array(); - } - if (is_null($loader)) { - $this->loader = new Loader(); - } else { - $this->loader = $loader; - } - - $mountpoint = $this->formatPath($mountpoint); - if ($storage instanceof Storage) { - $this->class = get_class($storage); - $this->storage = $this->loader->wrap($mountpoint, $storage); - } else { - // Update old classes to new namespace - if (strpos($storage, 'OC_Filestorage_') !== false) { - $storage = '\OC\Files\Storage\\' . substr($storage, 15); - } - $this->class = $storage; - $this->arguments = $arguments; - } - $this->mountPoint = $mountpoint; - } - - /** - * @return string - */ - public function getMountPoint() { - return $this->mountPoint; - } - - /** - * create the storage that is mounted - * - * @return \OC\Files\Storage\Storage - */ - private function createStorage() { - if (class_exists($this->class)) { - try { - return $this->loader->load($this->mountPoint, $this->class, $this->arguments); - } catch (\Exception $exception) { - \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR); - return null; - } - } else { - \OC_Log::write('core', 'storage backend ' . $this->class . ' not found', \OC_Log::ERROR); - return null; - } - } - - /** - * @return \OC\Files\Storage\Storage - */ - public function getStorage() { - if (is_null($this->storage)) { - $this->storage = $this->createStorage(); - } - return $this->storage; - } - - /** - * @return string - */ - public function getStorageId() { - if (!$this->storageId) { - if (is_null($this->storage)) { - $storage = $this->createStorage(); //FIXME: start using exceptions - if (is_null($storage)) { - return null; - } - $this->storage = $storage; - } - $this->storageId = $this->storage->getId(); - if (strlen($this->storageId) > 64) { - $this->storageId = md5($this->storageId); - } - } - return $this->storageId; - } - - /** - * @param string $path - * @return string - */ - public function getInternalPath($path) { - if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) { - $internalPath = ''; - } else { - $internalPath = substr($path, strlen($this->mountPoint)); - } - return $internalPath; - } - - /** - * @param string $path - * @return string - */ - private function formatPath($path) { - $path = Filesystem::normalizePath($path); - if (strlen($path) > 1) { - $path .= '/'; - } - return $path; - } - - /** - * @param callable $wrapper - */ - public function wrapStorage($wrapper) { - $this->storage = $wrapper($this->mountPoint, $this->storage); - } -} diff --git a/lib/files/node/file.php b/lib/files/node/file.php deleted file mode 100644 index 75d5e0166b6..00000000000 --- a/lib/files/node/file.php +++ /dev/null @@ -1,155 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Node; - -use OCP\Files\NotPermittedException; - -class File extends Node implements \OCP\Files\File { - /** - * @return string - * @throws \OCP\Files\NotPermittedException - */ - public function getContent() { - if ($this->checkPermissions(\OCP\PERMISSION_READ)) { - /** - * @var \OC\Files\Storage\Storage $storage; - */ - return $this->view->file_get_contents($this->path); - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $data - * @throws \OCP\Files\NotPermittedException - */ - public function putContent($data) { - if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { - $this->sendHooks(array('preWrite')); - $this->view->file_put_contents($this->path, $data); - $this->sendHooks(array('postWrite')); - } else { - throw new NotPermittedException(); - } - } - - /** - * @return string - */ - public function getMimeType() { - return $this->view->getMimeType($this->path); - } - - /** - * @param string $mode - * @return resource - * @throws \OCP\Files\NotPermittedException - */ - public function fopen($mode) { - $preHooks = array(); - $postHooks = array(); - $requiredPermissions = \OCP\PERMISSION_READ; - switch ($mode) { - case 'r+': - case 'rb+': - case 'w+': - case 'wb+': - case 'x+': - case 'xb+': - case 'a+': - case 'ab+': - case 'w': - case 'wb': - case 'x': - case 'xb': - case 'a': - case 'ab': - $preHooks[] = 'preWrite'; - $postHooks[] = 'postWrite'; - $requiredPermissions |= \OCP\PERMISSION_UPDATE; - break; - } - - if ($this->checkPermissions($requiredPermissions)) { - $this->sendHooks($preHooks); - $result = $this->view->fopen($this->path, $mode); - $this->sendHooks($postHooks); - return $result; - } else { - throw new NotPermittedException(); - } - } - - public function delete() { - if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { - $this->sendHooks(array('preDelete')); - $this->view->unlink($this->path); - $nonExisting = new NonExistingFile($this->root, $this->view, $this->path); - $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); - $this->exists = false; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function copy($targetPath) { - $targetPath = $this->normalizePath($targetPath); - $parent = $this->root->get(dirname($targetPath)); - if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { - $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath); - $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting)); - $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); - $this->view->copy($this->path, $targetPath); - $targetNode = $this->root->get($targetPath); - $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode)); - $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); - return $targetNode; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function move($targetPath) { - $targetPath = $this->normalizePath($targetPath); - $parent = $this->root->get(dirname($targetPath)); - if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { - $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath); - $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting)); - $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); - $this->view->rename($this->path, $targetPath); - $targetNode = $this->root->get($targetPath); - $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode)); - $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); - $this->path = $targetPath; - return $targetNode; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $type - * @param bool $raw - * @return string - */ - public function hash($type, $raw = false) { - return $this->view->hash($type, $this->path, $raw); - } -} diff --git a/lib/files/node/folder.php b/lib/files/node/folder.php deleted file mode 100644 index 923f53821b2..00000000000 --- a/lib/files/node/folder.php +++ /dev/null @@ -1,382 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Node; - -use OC\Files\Cache\Cache; -use OC\Files\Cache\Scanner; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; - -class Folder extends Node implements \OCP\Files\Folder { - /** - * @param string $path path relative to the folder - * @return string - * @throws \OCP\Files\NotPermittedException - */ - public function getFullPath($path) { - if (!$this->isValidPath($path)) { - throw new NotPermittedException(); - } - return $this->path . $this->normalizePath($path); - } - - /** - * @param string $path - * @throws \OCP\Files\NotFoundException - * @return string - */ - public function getRelativePath($path) { - if ($this->path === '' or $this->path === '/') { - return $this->normalizePath($path); - } - if (strpos($path, $this->path) !== 0) { - throw new NotFoundException(); - } else { - $path = substr($path, strlen($this->path)); - if (strlen($path) === 0) { - return '/'; - } else { - return $this->normalizePath($path); - } - } - } - - /** - * check if a node is a (grand-)child of the folder - * - * @param \OC\Files\Node\Node $node - * @return bool - */ - public function isSubNode($node) { - return strpos($node->getPath(), $this->path . '/') === 0; - } - - /** - * get the content of this directory - * - * @throws \OCP\Files\NotFoundException - * @return Node[] - */ - public function getDirectoryListing() { - $result = array(); - - /** - * @var \OC\Files\Storage\Storage $storage - */ - list($storage, $internalPath) = $this->view->resolvePath($this->path); - if ($storage) { - $cache = $storage->getCache($internalPath); - $permissionsCache = $storage->getPermissionsCache($internalPath); - - //trigger cache update check - $this->view->getFileInfo($this->path); - - $files = $cache->getFolderContents($internalPath); - $permissions = $permissionsCache->getDirectoryPermissions($this->getId(), $this->root->getUser()->getUID()); - } else { - $files = array(); - } - - //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders - $mounts = $this->root->getMountsIn($this->path); - $dirLength = strlen($this->path); - foreach ($mounts as $mount) { - $subStorage = $mount->getStorage(); - if ($subStorage) { - $subCache = $subStorage->getCache(''); - - if ($subCache->getStatus('') === Cache::NOT_FOUND) { - $subScanner = $subStorage->getScanner(''); - $subScanner->scanFile(''); - } - - $rootEntry = $subCache->get(''); - if ($rootEntry) { - $relativePath = trim(substr($mount->getMountPoint(), $dirLength), '/'); - if ($pos = strpos($relativePath, '/')) { - //mountpoint inside subfolder add size to the correct folder - $entryName = substr($relativePath, 0, $pos); - foreach ($files as &$entry) { - if ($entry['name'] === $entryName) { - if ($rootEntry['size'] >= 0) { - $entry['size'] += $rootEntry['size']; - } else { - $entry['size'] = -1; - } - } - } - } else { //mountpoint in this folder, add an entry for it - $rootEntry['name'] = $relativePath; - $rootEntry['storageObject'] = $subStorage; - - //remove any existing entry with the same name - foreach ($files as $i => $file) { - if ($file['name'] === $rootEntry['name']) { - $files[$i] = null; - break; - } - } - $files[] = $rootEntry; - } - } - } - } - - foreach ($files as $file) { - if ($file) { - if (isset($permissions[$file['fileid']])) { - $file['permissions'] = $permissions[$file['fileid']]; - } - $node = $this->createNode($this->path . '/' . $file['name'], $file); - $result[] = $node; - } - } - - return $result; - } - - /** - * @param string $path - * @param array $info - * @return File|Folder - */ - protected function createNode($path, $info = array()) { - if (!isset($info['mimetype'])) { - $isDir = $this->view->is_dir($path); - } else { - $isDir = $info['mimetype'] === 'httpd/unix-directory'; - } - if ($isDir) { - return new Folder($this->root, $this->view, $path); - } else { - return new File($this->root, $this->view, $path); - } - } - - /** - * Get the node at $path - * - * @param string $path - * @return \OC\Files\Node\Node - * @throws \OCP\Files\NotFoundException - */ - public function get($path) { - return $this->root->get($this->getFullPath($path)); - } - - /** - * @param string $path - * @return bool - */ - public function nodeExists($path) { - try { - $this->get($path); - return true; - } catch (NotFoundException $e) { - return false; - } - } - - /** - * @param string $path - * @return \OC\Files\Node\Folder - * @throws \OCP\Files\NotPermittedException - */ - public function newFolder($path) { - if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { - $fullPath = $this->getFullPath($path); - $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath); - $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); - $this->root->emit('\OC\Files', 'preCreate', array($nonExisting)); - $this->view->mkdir($fullPath); - $node = new Folder($this->root, $this->view, $fullPath); - $this->root->emit('\OC\Files', 'postWrite', array($node)); - $this->root->emit('\OC\Files', 'postCreate', array($node)); - return $node; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $path - * @return \OC\Files\Node\File - * @throws \OCP\Files\NotPermittedException - */ - public function newFile($path) { - if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { - $fullPath = $this->getFullPath($path); - $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath); - $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); - $this->root->emit('\OC\Files', 'preCreate', array($nonExisting)); - $this->view->touch($fullPath); - $node = new File($this->root, $this->view, $fullPath); - $this->root->emit('\OC\Files', 'postWrite', array($node)); - $this->root->emit('\OC\Files', 'postCreate', array($node)); - return $node; - } else { - throw new NotPermittedException(); - } - } - - /** - * search for files with the name matching $query - * - * @param string $query - * @return \OC\Files\Node\Node[] - */ - public function search($query) { - return $this->searchCommon('%' . $query . '%', 'search'); - } - - /** - * search for files by mimetype - * - * @param string $mimetype - * @return Node[] - */ - public function searchByMime($mimetype) { - return $this->searchCommon($mimetype, 'searchByMime'); - } - - /** - * @param string $query - * @param string $method - * @return \OC\Files\Node\Node[] - */ - private function searchCommon($query, $method) { - $files = array(); - $rootLength = strlen($this->path); - /** - * @var \OC\Files\Storage\Storage $storage - */ - list($storage, $internalPath) = $this->view->resolvePath($this->path); - $internalRootLength = strlen($internalPath); - - $cache = $storage->getCache(''); - - $results = $cache->$method($query); - foreach ($results as $result) { - if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) { - $result['internalPath'] = $result['path']; - $result['path'] = substr($result['path'], $internalRootLength); - $result['storage'] = $storage; - $files[] = $result; - } - } - - $mounts = $this->root->getMountsIn($this->path); - foreach ($mounts as $mount) { - $storage = $mount->getStorage(); - if ($storage) { - $cache = $storage->getCache(''); - - $relativeMountPoint = substr($mount->getMountPoint(), $rootLength); - $results = $cache->$method($query); - foreach ($results as $result) { - $result['internalPath'] = $result['path']; - $result['path'] = $relativeMountPoint . $result['path']; - $result['storage'] = $storage; - $files[] = $result; - } - } - } - - $result = array(); - foreach ($files as $file) { - $result[] = $this->createNode($this->normalizePath($this->path . '/' . $file['path']), $file); - } - - return $result; - } - - /** - * @param $id - * @return \OC\Files\Node\Node[] - */ - public function getById($id) { - $nodes = $this->root->getById($id); - $result = array(); - foreach ($nodes as $node) { - $pathPart = substr($node->getPath(), 0, strlen($this->getPath()) + 1); - if ($this->path === '/' or $pathPart === $this->getPath() . '/') { - $result[] = $node; - } - } - return $result; - } - - public function getFreeSpace() { - return $this->view->free_space($this->path); - } - - /** - * @return bool - */ - public function isCreatable() { - return $this->checkPermissions(\OCP\PERMISSION_CREATE); - } - - public function delete() { - if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { - $this->sendHooks(array('preDelete')); - $this->view->rmdir($this->path); - $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path); - $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); - $this->exists = false; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function copy($targetPath) { - $targetPath = $this->normalizePath($targetPath); - $parent = $this->root->get(dirname($targetPath)); - if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { - $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath); - $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting)); - $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); - $this->view->copy($this->path, $targetPath); - $targetNode = $this->root->get($targetPath); - $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode)); - $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); - return $targetNode; - } else { - throw new NotPermittedException(); - } - } - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function move($targetPath) { - $targetPath = $this->normalizePath($targetPath); - $parent = $this->root->get(dirname($targetPath)); - if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { - $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath); - $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting)); - $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); - $this->view->rename($this->path, $targetPath); - $targetNode = $this->root->get($targetPath); - $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode)); - $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); - $this->path = $targetPath; - return $targetNode; - } else { - throw new NotPermittedException(); - } - } -} diff --git a/lib/files/node/node.php b/lib/files/node/node.php deleted file mode 100644 index 063e2424a64..00000000000 --- a/lib/files/node/node.php +++ /dev/null @@ -1,245 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Node; - -use OC\Files\Cache\Cache; -use OC\Files\Cache\Scanner; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; - -class Node implements \OCP\Files\Node { - /** - * @var \OC\Files\View $view - */ - protected $view; - - /** - * @var \OC\Files\Node\Root $root - */ - protected $root; - - /** - * @var string $path - */ - protected $path; - - /** - * @param \OC\Files\View $view - * @param \OC\Files\Node\Root Root $root - * @param string $path - */ - public function __construct($root, $view, $path) { - $this->view = $view; - $this->root = $root; - $this->path = $path; - } - - /** - * @param string[] $hooks - */ - protected function sendHooks($hooks) { - foreach ($hooks as $hook) { - $this->root->emit('\OC\Files', $hook, array($this)); - } - } - - /** - * @param int $permissions - * @return bool - */ - protected function checkPermissions($permissions) { - return ($this->getPermissions() & $permissions) === $permissions; - } - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function move($targetPath) { - return; - } - - public function delete() { - return; - } - - /** - * @param string $targetPath - * @return \OC\Files\Node\Node - */ - public function copy($targetPath) { - return; - } - - /** - * @param int $mtime - * @throws \OCP\Files\NotPermittedException - */ - public function touch($mtime = null) { - if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { - $this->sendHooks(array('preTouch')); - $this->view->touch($this->path, $mtime); - $this->sendHooks(array('postTouch')); - } else { - throw new NotPermittedException(); - } - } - - /** - * @return \OC\Files\Storage\Storage - * @throws \OCP\Files\NotFoundException - */ - public function getStorage() { - list($storage,) = $this->view->resolvePath($this->path); - return $storage; - } - - /** - * @return string - */ - public function getPath() { - return $this->path; - } - - /** - * @return string - */ - public function getInternalPath() { - list(, $internalPath) = $this->view->resolvePath($this->path); - return $internalPath; - } - - /** - * @return int - */ - public function getId() { - $info = $this->view->getFileInfo($this->path); - return $info['fileid']; - } - - /** - * @return array - */ - public function stat() { - return $this->view->stat($this->path); - } - - /** - * @return int - */ - public function getMTime() { - return $this->view->filemtime($this->path); - } - - /** - * @return int - */ - public function getSize() { - return $this->view->filesize($this->path); - } - - /** - * @return string - */ - public function getEtag() { - $info = $this->view->getFileInfo($this->path); - return $info['etag']; - } - - /** - * @return int - */ - public function getPermissions() { - $info = $this->view->getFileInfo($this->path); - return $info['permissions']; - } - - /** - * @return bool - */ - public function isReadable() { - return $this->checkPermissions(\OCP\PERMISSION_READ); - } - - /** - * @return bool - */ - public function isUpdateable() { - return $this->checkPermissions(\OCP\PERMISSION_UPDATE); - } - - /** - * @return bool - */ - public function isDeletable() { - return $this->checkPermissions(\OCP\PERMISSION_DELETE); - } - - /** - * @return bool - */ - public function isShareable() { - return $this->checkPermissions(\OCP\PERMISSION_SHARE); - } - - /** - * @return Node - */ - public function getParent() { - return $this->root->get(dirname($this->path)); - } - - /** - * @return string - */ - public function getName() { - return basename($this->path); - } - - /** - * @param string $path - * @return string - */ - protected function normalizePath($path) { - if ($path === '' or $path === '/') { - return '/'; - } - //no windows style slashes - $path = str_replace('\\', '/', $path); - //add leading slash - if ($path[0] !== '/') { - $path = '/' . $path; - } - //remove duplicate slashes - while (strpos($path, '//') !== false) { - $path = str_replace('//', '/', $path); - } - //remove trailing slash - $path = rtrim($path, '/'); - - return $path; - } - - /** - * check if the requested path is valid - * - * @param string $path - * @return bool - */ - public function isValidPath($path) { - if (!$path || $path[0] !== '/') { - $path = '/' . $path; - } - if (strstr($path, '/../') || strrchr($path, '/') === '/..') { - return false; - } - return true; - } -} diff --git a/lib/files/node/nonexistingfile.php b/lib/files/node/nonexistingfile.php deleted file mode 100644 index d45076f7fee..00000000000 --- a/lib/files/node/nonexistingfile.php +++ /dev/null @@ -1,89 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Node; - -use OCP\Files\NotFoundException; - -class NonExistingFile extends File { - /** - * @param string $newPath - * @throws \OCP\Files\NotFoundException - */ - public function rename($newPath) { - throw new NotFoundException(); - } - - public function delete() { - throw new NotFoundException(); - } - - public function copy($newPath) { - throw new NotFoundException(); - } - - public function touch($mtime = null) { - throw new NotFoundException(); - } - - public function getId() { - throw new NotFoundException(); - } - - public function stat() { - throw new NotFoundException(); - } - - public function getMTime() { - throw new NotFoundException(); - } - - public function getSize() { - throw new NotFoundException(); - } - - public function getEtag() { - throw new NotFoundException(); - } - - public function getPermissions() { - throw new NotFoundException(); - } - - public function isReadable() { - throw new NotFoundException(); - } - - public function isUpdateable() { - throw new NotFoundException(); - } - - public function isDeletable() { - throw new NotFoundException(); - } - - public function isShareable() { - throw new NotFoundException(); - } - - public function getContent() { - throw new NotFoundException(); - } - - public function putContent($data) { - throw new NotFoundException(); - } - - public function getMimeType() { - throw new NotFoundException(); - } - - public function fopen($mode) { - throw new NotFoundException(); - } -} diff --git a/lib/files/node/nonexistingfolder.php b/lib/files/node/nonexistingfolder.php deleted file mode 100644 index 0346cbf1e21..00000000000 --- a/lib/files/node/nonexistingfolder.php +++ /dev/null @@ -1,113 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Node; - -use OCP\Files\NotFoundException; - -class NonExistingFolder extends Folder { - /** - * @param string $newPath - * @throws \OCP\Files\NotFoundException - */ - public function rename($newPath) { - throw new NotFoundException(); - } - - public function delete() { - throw new NotFoundException(); - } - - public function copy($newPath) { - throw new NotFoundException(); - } - - public function touch($mtime = null) { - throw new NotFoundException(); - } - - public function getId() { - throw new NotFoundException(); - } - - public function stat() { - throw new NotFoundException(); - } - - public function getMTime() { - throw new NotFoundException(); - } - - public function getSize() { - throw new NotFoundException(); - } - - public function getEtag() { - throw new NotFoundException(); - } - - public function getPermissions() { - throw new NotFoundException(); - } - - public function isReadable() { - throw new NotFoundException(); - } - - public function isUpdateable() { - throw new NotFoundException(); - } - - public function isDeletable() { - throw new NotFoundException(); - } - - public function isShareable() { - throw new NotFoundException(); - } - - public function get($path) { - throw new NotFoundException(); - } - - public function getDirectoryListing() { - throw new NotFoundException(); - } - - public function nodeExists($path) { - return false; - } - - public function newFolder($path) { - throw new NotFoundException(); - } - - public function newFile($path) { - throw new NotFoundException(); - } - - public function search($pattern) { - throw new NotFoundException(); - } - - public function searchByMime($mime) { - throw new NotFoundException(); - } - - public function getById($id) { - throw new NotFoundException(); - } - - public function getFreeSpace() { - throw new NotFoundException(); - } - - public function isCreatable() { - throw new NotFoundException(); - } -} diff --git a/lib/files/node/root.php b/lib/files/node/root.php deleted file mode 100644 index e3d58476e9c..00000000000 --- a/lib/files/node/root.php +++ /dev/null @@ -1,337 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Node; - -use OC\Files\Cache\Cache; -use OC\Files\Cache\Scanner; -use OC\Files\Mount\Manager; -use OC\Files\Mount\Mount; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; -use OC\Hooks\Emitter; -use OC\Hooks\PublicEmitter; - -/** - * Class Root - * - * Hooks available in scope \OC\Files - * - preWrite(\OCP\Files\Node $node) - * - postWrite(\OCP\Files\Node $node) - * - preCreate(\OCP\Files\Node $node) - * - postCreate(\OCP\Files\Node $node) - * - preDelete(\OCP\Files\Node $node) - * - postDelete(\OCP\Files\Node $node) - * - preTouch(\OC\FilesP\Node $node, int $mtime) - * - postTouch(\OCP\Files\Node $node) - * - preCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) - * - postCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) - * - preRename(\OCP\Files\Node $source, \OCP\Files\Node $target) - * - postRename(\OCP\Files\Node $source, \OCP\Files\Node $target) - * - * @package OC\Files\Node - */ -class Root extends Folder implements Emitter { - - /** - * @var \OC\Files\Mount\Manager $mountManager - */ - private $mountManager; - - /** - * @var \OC\Hooks\PublicEmitter - */ - private $emitter; - - /** - * @var \OC\User\User $user - */ - private $user; - - /** - * @param \OC\Files\Mount\Manager $manager - * @param \OC\Files\View $view - * @param \OC\User\User $user - */ - public function __construct($manager, $view, $user) { - parent::__construct($this, $view, ''); - $this->mountManager = $manager; - $this->user = $user; - $this->emitter = new PublicEmitter(); - } - - /** - * Get the user for which the filesystem is setup - * - * @return \OC\User\User - */ - public function getUser() { - return $this->user; - } - - /** - * @param string $scope - * @param string $method - * @param callable $callback - */ - public function listen($scope, $method, $callback) { - $this->emitter->listen($scope, $method, $callback); - } - - /** - * @param string $scope optional - * @param string $method optional - * @param callable $callback optional - */ - public function removeListener($scope = null, $method = null, $callback = null) { - $this->emitter->removeListener($scope, $method, $callback); - } - - /** - * @param string $scope - * @param string $method - * @param array $arguments - */ - public function emit($scope, $method, $arguments = array()) { - $this->emitter->emit($scope, $method, $arguments); - } - - /** - * @param \OC\Files\Storage\Storage $storage - * @param string $mountPoint - * @param array $arguments - */ - public function mount($storage, $mountPoint, $arguments = array()) { - $mount = new Mount($storage, $mountPoint, $arguments); - $this->mountManager->addMount($mount); - } - - /** - * @param string $mountPoint - * @return \OC\Files\Mount\Mount - */ - public function getMount($mountPoint) { - return $this->mountManager->find($mountPoint); - } - - /** - * @param string $mountPoint - * @return \OC\Files\Mount\Mount[] - */ - public function getMountsIn($mountPoint) { - return $this->mountManager->findIn($mountPoint); - } - - /** - * @param string $storageId - * @return \OC\Files\Mount\Mount[] - */ - public function getMountByStorageId($storageId) { - return $this->mountManager->findByStorageId($storageId); - } - - /** - * @param int $numericId - * @return Mount[] - */ - public function getMountByNumericStorageId($numericId) { - return $this->mountManager->findByNumericId($numericId); - } - - /** - * @param \OC\Files\Mount\Mount $mount - */ - public function unMount($mount) { - $this->mountManager->remove($mount); - } - - /** - * @param string $path - * @throws \OCP\Files\NotFoundException - * @throws \OCP\Files\NotPermittedException - * @return Node - */ - public function get($path) { - $path = $this->normalizePath($path); - if ($this->isValidPath($path)) { - $fullPath = $this->getFullPath($path); - if ($this->view->file_exists($fullPath)) { - return $this->createNode($fullPath); - } else { - throw new NotFoundException(); - } - } else { - throw new NotPermittedException(); - } - } - - /** - * search file by id - * - * An array is returned because in the case where a single storage is mounted in different places the same file - * can exist in different places - * - * @param int $id - * @throws \OCP\Files\NotFoundException - * @return Node[] - */ - public function getById($id) { - $result = Cache::getById($id); - if (is_null($result)) { - throw new NotFoundException(); - } else { - list($storageId, $internalPath) = $result; - $nodes = array(); - $mounts = $this->mountManager->findByStorageId($storageId); - foreach ($mounts as $mount) { - $nodes[] = $this->get($mount->getMountPoint() . $internalPath); - } - return $nodes; - } - - } - - //most operations cant be done on the root - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function rename($targetPath) { - throw new NotPermittedException(); - } - - public function delete() { - throw new NotPermittedException(); - } - - /** - * @param string $targetPath - * @throws \OCP\Files\NotPermittedException - * @return \OC\Files\Node\Node - */ - public function copy($targetPath) { - throw new NotPermittedException(); - } - - /** - * @param int $mtime - * @throws \OCP\Files\NotPermittedException - */ - public function touch($mtime = null) { - throw new NotPermittedException(); - } - - /** - * @return \OC\Files\Storage\Storage - * @throws \OCP\Files\NotFoundException - */ - public function getStorage() { - throw new NotFoundException(); - } - - /** - * @return string - */ - public function getPath() { - return '/'; - } - - /** - * @return string - */ - public function getInternalPath() { - return ''; - } - - /** - * @return int - */ - public function getId() { - return null; - } - - /** - * @return array - */ - public function stat() { - return null; - } - - /** - * @return int - */ - public function getMTime() { - return null; - } - - /** - * @return int - */ - public function getSize() { - return null; - } - - /** - * @return string - */ - public function getEtag() { - return null; - } - - /** - * @return int - */ - public function getPermissions() { - return \OCP\PERMISSION_CREATE; - } - - /** - * @return bool - */ - public function isReadable() { - return false; - } - - /** - * @return bool - */ - public function isUpdateable() { - return false; - } - - /** - * @return bool - */ - public function isDeletable() { - return false; - } - - /** - * @return bool - */ - public function isShareable() { - return false; - } - - /** - * @return Node - * @throws \OCP\Files\NotFoundException - */ - public function getParent() { - throw new NotFoundException(); - } - - /** - * @return string - */ - public function getName() { - return ''; - } -} diff --git a/lib/files/storage/common.php b/lib/files/storage/common.php deleted file mode 100644 index a5b79f0e967..00000000000 --- a/lib/files/storage/common.php +++ /dev/null @@ -1,374 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Storage; - -/** - * Storage backend class for providing common filesystem operation methods - * which are not storage-backend specific. - * - * \OC\Files\Storage\Common is never used directly; it is extended by all other - * storage backends, where its methods may be overridden, and additional - * (backend-specific) methods are defined. - * - * Some \OC\Files\Storage\Common methods call functions which are first defined - * in classes which extend it, e.g. $this->stat() . - */ - -abstract class Common implements \OC\Files\Storage\Storage { - private $cache; - private $scanner; - private $permissioncache; - private $watcher; - private $storageCache; - - public function __construct($parameters) { - } - - public function is_dir($path) { - return $this->filetype($path) == 'dir'; - } - - public function is_file($path) { - return $this->filetype($path) == 'file'; - } - - public function filesize($path) { - if ($this->is_dir($path)) { - return 0; //by definition - } else { - $stat = $this->stat($path); - if (isset($stat['size'])) { - return $stat['size']; - } else { - return 0; - } - } - } - - public function isCreatable($path) { - if ($this->is_dir($path) && $this->isUpdatable($path)) { - return true; - } - return false; - } - - public function isDeletable($path) { - return $this->isUpdatable($path); - } - - public function isSharable($path) { - return $this->isReadable($path); - } - - public function getPermissions($path) { - $permissions = 0; - if ($this->isCreatable($path)) { - $permissions |= \OCP\PERMISSION_CREATE; - } - if ($this->isReadable($path)) { - $permissions |= \OCP\PERMISSION_READ; - } - if ($this->isUpdatable($path)) { - $permissions |= \OCP\PERMISSION_UPDATE; - } - if ($this->isDeletable($path)) { - $permissions |= \OCP\PERMISSION_DELETE; - } - if ($this->isSharable($path)) { - $permissions |= \OCP\PERMISSION_SHARE; - } - return $permissions; - } - - public function filemtime($path) { - $stat = $this->stat($path); - if (isset($stat['mtime'])) { - return $stat['mtime']; - } else { - return 0; - } - } - - public function file_get_contents($path) { - $handle = $this->fopen($path, "r"); - if (!$handle) { - return false; - } - $size = $this->filesize($path); - if ($size == 0) { - return ''; - } - return fread($handle, $size); - } - - public function file_put_contents($path, $data) { - $handle = $this->fopen($path, "w"); - return fwrite($handle, $data); - } - - public function rename($path1, $path2) { - if ($this->copy($path1, $path2)) { - return $this->unlink($path1); - } else { - return false; - } - } - - public function copy($path1, $path2) { - $source = $this->fopen($path1, 'r'); - $target = $this->fopen($path2, 'w'); - list($count, $result) = \OC_Helper::streamCopy($source, $target); - return $result; - } - - /** - * @brief Deletes all files and folders recursively within a directory - * @param string $directory The directory whose contents will be deleted - * @param bool $empty Flag indicating whether directory will be emptied - * @returns bool - * - * @note By default the directory specified by $directory will be - * deleted together with its contents. To avoid this set $empty to true - */ - public function deleteAll($directory, $empty = false) { - $directory = trim($directory, '/'); - if (!$this->is_dir($directory) || !$this->isReadable($directory)) { - return false; - } else { - $directoryHandle = $this->opendir($directory); - if(is_resource($directoryHandle)) { - while (($contents = readdir($directoryHandle)) !== false) { - if (!\OC\Files\Filesystem::isIgnoredDir($contents)) { - $path = $directory . '/' . $contents; - if ($this->is_dir($path)) { - $this->deleteAll($path); - } else { - $this->unlink($path); - } - } - } - } - if ($empty === false) { - if (!$this->rmdir($directory)) { - return false; - } - } - return true; - } - - } - - public function getMimeType($path) { - if (!$this->file_exists($path)) { - return false; - } - if ($this->is_dir($path)) { - return 'httpd/unix-directory'; - } - $source = $this->fopen($path, 'r'); - if (!$source) { - return false; - } - $head = fread($source, 8192); //8kb should suffice to determine a mimetype - if ($pos = strrpos($path, '.')) { - $extension = substr($path, $pos); - } else { - $extension = ''; - } - $tmpFile = \OC_Helper::tmpFile($extension); - file_put_contents($tmpFile, $head); - $mime = \OC_Helper::getMimeType($tmpFile); - unlink($tmpFile); - return $mime; - } - - public function hash($type, $path, $raw = false) { - $tmpFile = $this->getLocalFile($path); - $hash = hash($type, $tmpFile, $raw); - unlink($tmpFile); - return $hash; - } - - public function search($query) { - return $this->searchInDir($query); - } - - public function getLocalFile($path) { - return $this->toTmpFile($path); - } - - private function toTmpFile($path) { //no longer in the storage api, still useful here - $source = $this->fopen($path, 'r'); - if (!$source) { - return false; - } - if ($pos = strrpos($path, '.')) { - $extension = substr($path, $pos); - } else { - $extension = ''; - } - $tmpFile = \OC_Helper::tmpFile($extension); - $target = fopen($tmpFile, 'w'); - \OC_Helper::streamCopy($source, $target); - return $tmpFile; - } - - public function getLocalFolder($path) { - $baseDir = \OC_Helper::tmpFolder(); - $this->addLocalFolder($path, $baseDir); - return $baseDir; - } - - private function addLocalFolder($path, $target) { - $dh = $this->opendir($path); - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if ($file !== '.' and $file !== '..') { - if ($this->is_dir($path . '/' . $file)) { - mkdir($target . '/' . $file); - $this->addLocalFolder($path . '/' . $file, $target . '/' . $file); - } else { - $tmp = $this->toTmpFile($path . '/' . $file); - rename($tmp, $target . '/' . $file); - } - } - } - } - } - - protected function searchInDir($query, $dir = '') { - $files = array(); - $dh = $this->opendir($dir); - if (is_resource($dh)) { - while (($item = readdir($dh)) !== false) { - if ($item == '.' || $item == '..') continue; - if (strstr(strtolower($item), strtolower($query)) !== false) { - $files[] = $dir . '/' . $item; - } - if ($this->is_dir($dir . '/' . $item)) { - $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); - } - } - } - return $files; - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - return $this->filemtime($path) > $time; - } - - public function getCache($path = '') { - if (!isset($this->cache)) { - $this->cache = new \OC\Files\Cache\Cache($this); - } - return $this->cache; - } - - public function getScanner($path = '') { - if (!isset($this->scanner)) { - $this->scanner = new \OC\Files\Cache\Scanner($this); - } - return $this->scanner; - } - - public function getPermissionsCache($path = '') { - if (!isset($this->permissioncache)) { - $this->permissioncache = new \OC\Files\Cache\Permissions($this); - } - return $this->permissioncache; - } - - public function getWatcher($path = '') { - if (!isset($this->watcher)) { - $this->watcher = new \OC\Files\Cache\Watcher($this); - } - return $this->watcher; - } - - public function getStorageCache(){ - if (!isset($this->storageCache)) { - $this->storageCache = new \OC\Files\Cache\Storage($this); - } - return $this->storageCache; - } - - /** - * get the owner of a path - * - * @param string $path The path to get the owner - * @return string uid or false - */ - public function getOwner($path) { - return \OC_User::getUser(); - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path) { - $ETagFunction = \OC_Connector_Sabre_Node::$ETagFunction; - if ($ETagFunction) { - $hash = call_user_func($ETagFunction, $path); - return $hash; - } else { - return uniqid(); - } - } - - /** - * clean a path, i.e. remove all redundant '.' and '..' - * making sure that it can't point to higher than '/' - * - * @param $path The path to clean - * @return string cleaned path - */ - public function cleanPath($path) { - if (strlen($path) == 0 or $path[0] != '/') { - $path = '/' . $path; - } - - $output = array(); - foreach (explode('/', $path) as $chunk) { - if ($chunk == '..') { - array_pop($output); - } else if ($chunk == '.') { - } else { - $output[] = $chunk; - } - } - return implode('/', $output); - } - - public function test() { - if ($this->stat('')) { - return true; - } - return false; - } - - /** - * get the free space in the storage - * - * @param $path - * @return int - */ - public function free_space($path) { - return \OC\Files\SPACE_UNKNOWN; - } -} diff --git a/lib/files/storage/commontest.php b/lib/files/storage/commontest.php deleted file mode 100644 index c3f1eb31955..00000000000 --- a/lib/files/storage/commontest.php +++ /dev/null @@ -1,80 +0,0 @@ -. -* -*/ - -/** - * test implementation for \OC\Files\Storage\Common with \OC\Files\Storage\Local - */ - -namespace OC\Files\Storage; - -class CommonTest extends \OC\Files\Storage\Common{ - /** - * underlying local storage used for missing functions - * @var \OC\Files\Storage\Local - */ - private $storage; - - public function __construct($params) { - $this->storage=new \OC\Files\Storage\Local($params); - } - - public function getId(){ - return 'test::'.$this->storage->getId(); - } - public function mkdir($path) { - return $this->storage->mkdir($path); - } - public function rmdir($path) { - return $this->storage->rmdir($path); - } - public function opendir($path) { - return $this->storage->opendir($path); - } - public function stat($path) { - return $this->storage->stat($path); - } - public function filetype($path) { - return $this->storage->filetype($path); - } - public function isReadable($path) { - return $this->storage->isReadable($path); - } - public function isUpdatable($path) { - return $this->storage->isUpdatable($path); - } - public function file_exists($path) { - return $this->storage->file_exists($path); - } - public function unlink($path) { - return $this->storage->unlink($path); - } - public function fopen($path, $mode) { - return $this->storage->fopen($path, $mode); - } - public function free_space($path) { - return $this->storage->free_space($path); - } - public function touch($path, $mtime=null) { - return $this->storage->touch($path, $mtime); - } -} diff --git a/lib/files/storage/loader.php b/lib/files/storage/loader.php deleted file mode 100644 index 2572ef443bc..00000000000 --- a/lib/files/storage/loader.php +++ /dev/null @@ -1,38 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Storage; - -class Loader { - /** - * @var callable[] $storageWrappers - */ - private $storageWrappers = array(); - - /** - * allow modifier storage behaviour by adding wrappers around storages - * - * $callback should be a function of type (string $mountPoint, Storage $storage) => Storage - * - * @param callable $callback - */ - public function addStorageWrapper($callback) { - $this->storageWrappers[] = $callback; - } - - public function load($mountPoint, $class, $arguments) { - return $this->wrap($mountPoint, new $class($arguments)); - } - - public function wrap($mountPoint, $storage) { - foreach ($this->storageWrappers as $wrapper) { - $storage = $wrapper($mountPoint, $storage); - } - return $storage; - } -} diff --git a/lib/files/storage/local.php b/lib/files/storage/local.php deleted file mode 100644 index 5209fabc30a..00000000000 --- a/lib/files/storage/local.php +++ /dev/null @@ -1,310 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Storage; - -if (\OC_Util::runningOnWindows()) { - class Local extends MappedLocal { - - } -} else { - - /** - * for local filestore, we only have to map the paths - */ - class Local extends \OC\Files\Storage\Common { - protected $datadir; - - public function __construct($arguments) { - $this->datadir = $arguments['datadir']; - if (substr($this->datadir, -1) !== '/') { - $this->datadir .= '/'; - } - } - - public function __destruct() { - } - - public function getId() { - return 'local::' . $this->datadir; - } - - public function mkdir($path) { - return @mkdir($this->datadir . $path); - } - - public function rmdir($path) { - try { - $it = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator($this->datadir . $path), - \RecursiveIteratorIterator::CHILD_FIRST - ); - foreach ($it as $file) { - /** - * @var \SplFileInfo $file - */ - if (in_array($file->getBasename(), array('.', '..'))) { - continue; - } elseif ($file->isDir()) { - rmdir($file->getPathname()); - } elseif ($file->isFile() || $file->isLink()) { - unlink($file->getPathname()); - } - } - return rmdir($this->datadir . $path); - } catch (\UnexpectedValueException $e) { - return false; - } - } - - public function opendir($path) { - return opendir($this->datadir . $path); - } - - public function is_dir($path) { - if (substr($path, -1) == '/') { - $path = substr($path, 0, -1); - } - return is_dir($this->datadir . $path); - } - - public function is_file($path) { - return is_file($this->datadir . $path); - } - - public function stat($path) { - $fullPath = $this->datadir . $path; - $statResult = stat($fullPath); - - if ($statResult['size'] < 0) { - $size = self::getFileSizeFromOS($fullPath); - $statResult['size'] = $size; - $statResult[7] = $size; - } - return $statResult; - } - - public function filetype($path) { - $filetype = filetype($this->datadir . $path); - if ($filetype == 'link') { - $filetype = filetype(realpath($this->datadir . $path)); - } - return $filetype; - } - - public function filesize($path) { - if ($this->is_dir($path)) { - return 0; - } else { - $fullPath = $this->datadir . $path; - $fileSize = filesize($fullPath); - if ($fileSize < 0) { - return self::getFileSizeFromOS($fullPath); - } - - return $fileSize; - } - } - - public function isReadable($path) { - return is_readable($this->datadir . $path); - } - - public function isUpdatable($path) { - return is_writable($this->datadir . $path); - } - - public function file_exists($path) { - return file_exists($this->datadir . $path); - } - - public function filemtime($path) { - return filemtime($this->datadir . $path); - } - - public function touch($path, $mtime = null) { - // sets the modification time of the file to the given value. - // If mtime is nil the current time is set. - // note that the access time of the file always changes to the current time. - if ($this->file_exists($path) and !$this->isUpdatable($path)) { - return false; - } - if (!is_null($mtime)) { - $result = touch($this->datadir . $path, $mtime); - } else { - $result = touch($this->datadir . $path); - } - if ($result) { - clearstatcache(true, $this->datadir . $path); - } - - return $result; - } - - public function file_get_contents($path) { - return file_get_contents($this->datadir . $path); - } - - public function file_put_contents($path, $data) { //trigger_error("$path = ".var_export($path, 1)); - return file_put_contents($this->datadir . $path, $data); - } - - public function unlink($path) { - return $this->delTree($path); - } - - public function rename($path1, $path2) { - if (!$this->isUpdatable($path1)) { - \OC_Log::write('core', 'unable to rename, file is not writable : ' . $path1, \OC_Log::ERROR); - return false; - } - if (!$this->file_exists($path1)) { - \OC_Log::write('core', 'unable to rename, file does not exists : ' . $path1, \OC_Log::ERROR); - return false; - } - - if ($return = rename($this->datadir . $path1, $this->datadir . $path2)) { - } - return $return; - } - - public function copy($path1, $path2) { - if ($this->is_dir($path2)) { - if (!$this->file_exists($path2)) { - $this->mkdir($path2); - } - $source = substr($path1, strrpos($path1, '/') + 1); - $path2 .= $source; - } - return copy($this->datadir . $path1, $this->datadir . $path2); - } - - public function fopen($path, $mode) { - if ($return = fopen($this->datadir . $path, $mode)) { - switch ($mode) { - case 'r': - break; - case 'r+': - case 'w+': - case 'x+': - case 'a+': - break; - case 'w': - case 'x': - case 'a': - break; - } - } - return $return; - } - - public function getMimeType($path) { - if ($this->isReadable($path)) { - return \OC_Helper::getMimeType($this->datadir . $path); - } else { - return false; - } - } - - private function delTree($dir) { - $dirRelative = $dir; - $dir = $this->datadir . $dir; - if (!file_exists($dir)) return true; - if (!is_dir($dir) || is_link($dir)) return unlink($dir); - foreach (scandir($dir) as $item) { - if ($item == '.' || $item == '..') continue; - if (is_file($dir . '/' . $item)) { - if (unlink($dir . '/' . $item)) { - } - } elseif (is_dir($dir . '/' . $item)) { - if (!$this->delTree($dirRelative . "/" . $item)) { - return false; - }; - } - } - if ($return = rmdir($dir)) { - } - return $return; - } - - private static function getFileSizeFromOS($fullPath) { - $name = strtolower(php_uname('s')); - // Windows OS: we use COM to access the filesystem - if (strpos($name, 'win') !== false) { - if (class_exists('COM')) { - $fsobj = new \COM("Scripting.FileSystemObject"); - $f = $fsobj->GetFile($fullPath); - return $f->Size; - } - } else if (strpos($name, 'bsd') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); - } - } else if (strpos($name, 'linux') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); - } - } else { - \OC_Log::write('core', - 'Unable to determine file size of "' . $fullPath . '". Unknown OS: ' . $name, - \OC_Log::ERROR); - } - - return 0; - } - - public function hash($path, $type, $raw = false) { - return hash_file($type, $this->datadir . $path, $raw); - } - - public function free_space($path) { - $space = @disk_free_space($this->datadir . $path); - if ($space === false) { - return \OC\Files\SPACE_UNKNOWN; - } - return $space; - } - - public function search($query) { - return $this->searchInDir($query); - } - - public function getLocalFile($path) { - return $this->datadir . $path; - } - - public function getLocalFolder($path) { - return $this->datadir . $path; - } - - protected function searchInDir($query, $dir = '') { - $files = array(); - foreach (scandir($this->datadir . $dir) as $item) { - if ($item == '.' || $item == '..') continue; - if (strstr(strtolower($item), strtolower($query)) !== false) { - $files[] = $dir . '/' . $item; - } - if (is_dir($this->datadir . $dir . '/' . $item)) { - $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); - } - } - return $files; - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - return $this->filemtime($path) > $time; - } - } -} diff --git a/lib/files/storage/mappedlocal.php b/lib/files/storage/mappedlocal.php deleted file mode 100644 index ba5ac4191c5..00000000000 --- a/lib/files/storage/mappedlocal.php +++ /dev/null @@ -1,365 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ -namespace OC\Files\Storage; - -/** - * for local filestore, we only have to map the paths - */ -class MappedLocal extends \OC\Files\Storage\Common{ - protected $datadir; - private $mapper; - - public function __construct($arguments) { - $this->datadir=$arguments['datadir']; - if(substr($this->datadir, -1)!=='/') { - $this->datadir.='/'; - } - - $this->mapper= new \OC\Files\Mapper($this->datadir); - } - public function __destruct() { - if (defined('PHPUNIT_RUN')) { - $this->mapper->removePath($this->datadir, true, true); - } - } - public function getId(){ - return 'local::'.$this->datadir; - } - public function mkdir($path) { - return @mkdir($this->buildPath($path)); - } - public function rmdir($path) { - try { - $it = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator($this->buildPath($path)), - \RecursiveIteratorIterator::CHILD_FIRST - ); - foreach ($it as $file) { - /** - * @var \SplFileInfo $file - */ - if (in_array($file->getBasename(), array('.', '..'))) { - continue; - } elseif ($file->isDir()) { - rmdir($file->getPathname()); - } elseif ($file->isFile() || $file->isLink()) { - unlink($file->getPathname()); - } - } - if ($result = @rmdir($this->buildPath($path))) { - $this->cleanMapper($path); - } - return $result; - } catch (\UnexpectedValueException $e) { - return false; - } - } - public function opendir($path) { - $files = array('.', '..'); - $physicalPath= $this->buildPath($path); - - $logicalPath = $this->mapper->physicalToLogic($physicalPath); - $dh = opendir($physicalPath); - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if ($file === '.' or $file === '..') { - continue; - } - - $logicalFilePath = $this->mapper->physicalToLogic($physicalPath.'/'.$file); - - $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath); - $file = $this->stripLeading($file); - $files[]= $file; - } - } - - \OC\Files\Stream\Dir::register('local-win32'.$path, $files); - return opendir('fakedir://local-win32'.$path); - } - public function is_dir($path) { - if(substr($path, -1)=='/') { - $path=substr($path, 0, -1); - } - return is_dir($this->buildPath($path)); - } - public function is_file($path) { - return is_file($this->buildPath($path)); - } - public function stat($path) { - $fullPath = $this->buildPath($path); - $statResult = stat($fullPath); - - if ($statResult['size'] < 0) { - $size = self::getFileSizeFromOS($fullPath); - $statResult['size'] = $size; - $statResult[7] = $size; - } - return $statResult; - } - public function filetype($path) { - $filetype=filetype($this->buildPath($path)); - if($filetype=='link') { - $filetype=filetype(realpath($this->buildPath($path))); - } - return $filetype; - } - public function filesize($path) { - if($this->is_dir($path)) { - return 0; - }else{ - $fullPath = $this->buildPath($path); - $fileSize = filesize($fullPath); - if ($fileSize < 0) { - return self::getFileSizeFromOS($fullPath); - } - - return $fileSize; - } - } - public function isReadable($path) { - return is_readable($this->buildPath($path)); - } - public function isUpdatable($path) { - return is_writable($this->buildPath($path)); - } - public function file_exists($path) { - return file_exists($this->buildPath($path)); - } - public function filemtime($path) { - return filemtime($this->buildPath($path)); - } - public function touch($path, $mtime=null) { - // sets the modification time of the file to the given value. - // If mtime is nil the current time is set. - // note that the access time of the file always changes to the current time. - if(!is_null($mtime)) { - $result=touch( $this->buildPath($path), $mtime ); - }else{ - $result=touch( $this->buildPath($path)); - } - if( $result ) { - clearstatcache( true, $this->buildPath($path) ); - } - - return $result; - } - public function file_get_contents($path) { - return file_get_contents($this->buildPath($path)); - } - public function file_put_contents($path, $data) { - return file_put_contents($this->buildPath($path), $data); - } - public function unlink($path) { - return $this->delTree($path); - } - public function rename($path1, $path2) { - if (!$this->isUpdatable($path1)) { - \OC_Log::write('core', 'unable to rename, file is not writable : '.$path1, \OC_Log::ERROR); - return false; - } - if(! $this->file_exists($path1)) { - \OC_Log::write('core', 'unable to rename, file does not exists : '.$path1, \OC_Log::ERROR); - return false; - } - - $physicPath1 = $this->buildPath($path1); - $physicPath2 = $this->buildPath($path2); - if($return=rename($physicPath1, $physicPath2)) { - // mapper needs to create copies or all children - $this->copyMapping($path1, $path2); - $this->cleanMapper($physicPath1, false, true); - } - return $return; - } - public function copy($path1, $path2) { - if($this->is_dir($path2)) { - if(!$this->file_exists($path2)) { - $this->mkdir($path2); - } - $source=substr($path1, strrpos($path1, '/')+1); - $path2.=$source; - } - if($return=copy($this->buildPath($path1), $this->buildPath($path2))) { - // mapper needs to create copies or all children - $this->copyMapping($path1, $path2); - } - return $return; - } - public function fopen($path, $mode) { - if($return=fopen($this->buildPath($path), $mode)) { - switch($mode) { - case 'r': - break; - case 'r+': - case 'w+': - case 'x+': - case 'a+': - break; - case 'w': - case 'x': - case 'a': - break; - } - } - return $return; - } - - public function getMimeType($path) { - if($this->isReadable($path)) { - return \OC_Helper::getMimeType($this->buildPath($path)); - }else{ - return false; - } - } - - private function delTree($dir, $isLogicPath=true) { - $dirRelative=$dir; - if ($isLogicPath) { - $dir=$this->buildPath($dir); - } - if (!file_exists($dir)) { - return true; - } - if (!is_dir($dir) || is_link($dir)) { - if($return=unlink($dir)) { - $this->cleanMapper($dir, false); - return $return; - } - } - foreach (scandir($dir) as $item) { - if ($item == '.' || $item == '..') { - continue; - } - if(is_file($dir.'/'.$item)) { - if(unlink($dir.'/'.$item)) { - $this->cleanMapper($dir.'/'.$item, false); - } - }elseif(is_dir($dir.'/'.$item)) { - if (!$this->delTree($dir. "/" . $item, false)) { - return false; - }; - } - } - if($return=rmdir($dir)) { - $this->cleanMapper($dir, false); - } - return $return; - } - - private static function getFileSizeFromOS($fullPath) { - $name = strtolower(php_uname('s')); - // Windows OS: we use COM to access the filesystem - if (strpos($name, 'win') !== false) { - if (class_exists('COM')) { - $fsobj = new \COM("Scripting.FileSystemObject"); - $f = $fsobj->GetFile($fullPath); - return $f->Size; - } - } else if (strpos($name, 'bsd') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); - } - } else if (strpos($name, 'linux') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); - } - } else { - \OC_Log::write('core', - 'Unable to determine file size of "'.$fullPath.'". Unknown OS: '.$name, - \OC_Log::ERROR); - } - - return 0; - } - - public function hash($path, $type, $raw=false) { - return hash_file($type, $this->buildPath($path), $raw); - } - - public function free_space($path) { - return @disk_free_space($this->buildPath($path)); - } - - public function search($query) { - return $this->searchInDir($query); - } - public function getLocalFile($path) { - return $this->buildPath($path); - } - public function getLocalFolder($path) { - return $this->buildPath($path); - } - - protected function searchInDir($query, $dir='') { - $files=array(); - $physicalDir = $this->buildPath($dir); - foreach (scandir($physicalDir) as $item) { - if ($item == '.' || $item == '..') - continue; - $physicalItem = $this->mapper->physicalToLogic($physicalDir.'/'.$item); - $item = substr($physicalItem, strlen($physicalDir)+1); - - if(strstr(strtolower($item), strtolower($query)) !== false) { - $files[]=$dir.'/'.$item; - } - if(is_dir($physicalItem)) { - $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item)); - } - } - return $files; - } - - /** - * check if a file or folder has been updated since $time - * @param string $path - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - return $this->filemtime($path)>$time; - } - - private function buildPath($path, $create=true) { - $path = $this->stripLeading($path); - $fullPath = $this->datadir.$path; - return $this->mapper->logicToPhysical($fullPath, $create); - } - - private function cleanMapper($path, $isLogicPath=true, $recursive=true) { - $fullPath = $path; - if ($isLogicPath) { - $fullPath = $this->datadir.$path; - } - $this->mapper->removePath($fullPath, $isLogicPath, $recursive); - } - - private function copyMapping($path1, $path2) { - $path1 = $this->stripLeading($path1); - $path2 = $this->stripLeading($path2); - - $fullPath1 = $this->datadir.$path1; - $fullPath2 = $this->datadir.$path2; - - $this->mapper->copy($fullPath1, $fullPath2); - } - - private function stripLeading($path) { - if(strpos($path, '/') === 0) { - $path = substr($path, 1); - } - if(strpos($path, '\\') === 0) { - $path = substr($path, 1); - } - if ($path === false) { - return ''; - } - - return $path; - } -} diff --git a/lib/files/storage/storage.php b/lib/files/storage/storage.php deleted file mode 100644 index b673bb9a32d..00000000000 --- a/lib/files/storage/storage.php +++ /dev/null @@ -1,343 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Storage; - -/** - * Provide a common interface to all different storage options - * - * All paths passed to the storage are relative to the storage and should NOT have a leading slash. - */ -interface Storage extends \OCP\Files\Storage { - /** - * $parameters is a free form array with the configuration options needed to construct the storage - * - * @param array $parameters - */ - public function __construct($parameters); - - /** - * Get the identifier for the storage, - * the returned id should be the same for every storage object that is created with the same parameters - * and two storage objects with the same id should refer to two storages that display the same files. - * - * @return string - */ - public function getId(); - - /** - * see http://php.net/manual/en/function.mkdir.php - * - * @param string $path - * @return bool - */ - public function mkdir($path); - - /** - * see http://php.net/manual/en/function.rmdir.php - * - * @param string $path - * @return bool - */ - public function rmdir($path); - - /** - * see http://php.net/manual/en/function.opendir.php - * - * @param string $path - * @return resource - */ - public function opendir($path); - - /** - * see http://php.net/manual/en/function.is_dir.php - * - * @param string $path - * @return bool - */ - public function is_dir($path); - - /** - * see http://php.net/manual/en/function.is_file.php - * - * @param string $path - * @return bool - */ - public function is_file($path); - - /** - * see http://php.net/manual/en/function.stat.php - * only the following keys are required in the result: size and mtime - * - * @param string $path - * @return array - */ - public function stat($path); - - /** - * see http://php.net/manual/en/function.filetype.php - * - * @param string $path - * @return bool - */ - public function filetype($path); - - /** - * see http://php.net/manual/en/function.filesize.php - * The result for filesize when called on a folder is required to be 0 - * - * @param string $path - * @return int - */ - public function filesize($path); - - /** - * check if a file can be created in $path - * - * @param string $path - * @return bool - */ - public function isCreatable($path); - - /** - * check if a file can be read - * - * @param string $path - * @return bool - */ - public function isReadable($path); - - /** - * check if a file can be written to - * - * @param string $path - * @return bool - */ - public function isUpdatable($path); - - /** - * check if a file can be deleted - * - * @param string $path - * @return bool - */ - public function isDeletable($path); - - /** - * check if a file can be shared - * - * @param string $path - * @return bool - */ - public function isSharable($path); - - /** - * get the full permissions of a path. - * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php - * - * @param string $path - * @return int - */ - public function getPermissions($path); - - /** - * see http://php.net/manual/en/function.file_exists.php - * - * @param string $path - * @return bool - */ - public function file_exists($path); - - /** - * see http://php.net/manual/en/function.filemtime.php - * - * @param string $path - * @return int - */ - public function filemtime($path); - - /** - * see http://php.net/manual/en/function.file_get_contents.php - * - * @param string $path - * @return string - */ - public function file_get_contents($path); - - /** - * see http://php.net/manual/en/function.file_put_contents.php - * - * @param string $path - * @param string $data - * @return bool - */ - public function file_put_contents($path, $data); - - /** - * see http://php.net/manual/en/function.unlink.php - * - * @param string $path - * @return bool - */ - public function unlink($path); - - /** - * see http://php.net/manual/en/function.rename.php - * - * @param string $path1 - * @param string $path2 - * @return bool - */ - public function rename($path1, $path2); - - /** - * see http://php.net/manual/en/function.copy.php - * - * @param string $path1 - * @param string $path2 - * @return bool - */ - public function copy($path1, $path2); - - /** - * see http://php.net/manual/en/function.fopen.php - * - * @param string $path - * @param string $mode - * @return resource - */ - public function fopen($path, $mode); - - /** - * get the mimetype for a file or folder - * The mimetype for a folder is required to be "httpd/unix-directory" - * - * @param string $path - * @return string - */ - public function getMimeType($path); - - /** - * see http://php.net/manual/en/function.hash.php - * - * @param string $type - * @param string $path - * @param bool $raw - * @return string - */ - public function hash($type, $path, $raw = false); - - /** - * see http://php.net/manual/en/function.free_space.php - * - * @param string $path - * @return int - */ - public function free_space($path); - - /** - * search for occurrences of $query in file names - * - * @param string $query - * @return array - */ - public function search($query); - - /** - * see http://php.net/manual/en/function.touch.php - * If the backend does not support the operation, false should be returned - * - * @param string $path - * @param int $mtime - * @return bool - */ - public function touch($path, $mtime = null); - - /** - * get the path to a local version of the file. - * The local version of the file can be temporary and doesn't have to be persistent across requests - * - * @param string $path - * @return string - */ - public function getLocalFile($path); - - /** - * get the path to a local version of the folder. - * The local version of the folder can be temporary and doesn't have to be persistent across requests - * - * @param string $path - * @return string - */ - public function getLocalFolder($path); - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - * - * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. - * returning true for other changes in the folder is optional - */ - public function hasUpdated($path, $time); - - /** - * get a cache instance for the storage - * - * @param string $path - * @return \OC\Files\Cache\Cache - */ - public function getCache($path = ''); - - /** - * get a scanner instance for the storage - * - * @param string $path - * @return \OC\Files\Cache\Scanner - */ - public function getScanner($path = ''); - - - /** - * get the user id of the owner of a file or folder - * - * @param string $path - * @return string - */ - public function getOwner($path); - - /** - * get a permissions cache instance for the cache - * - * @param string $path - * @return \OC\Files\Cache\Permissions - */ - public function getPermissionsCache($path = ''); - - /** - * get a watcher instance for the cache - * - * @param string $path - * @return \OC\Files\Cache\Watcher - */ - public function getWatcher($path = ''); - - /** - * @return \OC\Files\Cache\Storage - */ - public function getStorageCache(); - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path); -} diff --git a/lib/files/storage/temporary.php b/lib/files/storage/temporary.php deleted file mode 100644 index d84dbda2e39..00000000000 --- a/lib/files/storage/temporary.php +++ /dev/null @@ -1,27 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Storage; - -/** - * local storage backend in temporary folder for testing purpose - */ -class Temporary extends Local{ - public function __construct($arguments) { - parent::__construct(array('datadir' => \OC_Helper::tmpFolder())); - } - - public function cleanUp() { - \OC_Helper::rmdirr($this->datadir); - } - - public function __destruct() { - parent::__destruct(); - $this->cleanUp(); - } -} diff --git a/lib/files/storage/wrapper/quota.php b/lib/files/storage/wrapper/quota.php deleted file mode 100644 index e2da8cf2e05..00000000000 --- a/lib/files/storage/wrapper/quota.php +++ /dev/null @@ -1,104 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Storage\Wrapper; - -class Quota extends Wrapper { - - /** - * @var int $quota - */ - protected $quota; - - /** - * @param array $parameters - */ - public function __construct($parameters) { - $this->storage = $parameters['storage']; - $this->quota = $parameters['quota']; - } - - protected function getSize($path) { - $cache = $this->getCache(); - $data = $cache->get($path); - if (is_array($data) and isset($data['size'])) { - return $data['size']; - } else { - return \OC\Files\SPACE_NOT_COMPUTED; - } - } - - /** - * Get free space as limited by the quota - * - * @param string $path - * @return int - */ - public function free_space($path) { - if ($this->quota < 0) { - return $this->storage->free_space($path); - } else { - $used = $this->getSize(''); - if ($used < 0) { - return \OC\Files\SPACE_NOT_COMPUTED; - } else { - $free = $this->storage->free_space($path); - return min($free, (max($this->quota - $used, 0))); - } - } - } - - /** - * see http://php.net/manual/en/function.file_put_contents.php - * - * @param string $path - * @param string $data - * @return bool - */ - public function file_put_contents($path, $data) { - $free = $this->free_space(''); - if ($free < 0 or strlen($data) < $free) { - return $this->storage->file_put_contents($path, $data); - } else { - return false; - } - } - - /** - * see http://php.net/manual/en/function.copy.php - * - * @param string $source - * @param string $target - * @return bool - */ - public function copy($source, $target) { - $free = $this->free_space(''); - if ($free < 0 or $this->getSize($source) < $free) { - return $this->storage->copy($source, $target); - } else { - return false; - } - } - - /** - * see http://php.net/manual/en/function.fopen.php - * - * @param string $path - * @param string $mode - * @return resource - */ - public function fopen($path, $mode) { - $source = $this->storage->fopen($path, $mode); - $free = $this->free_space(''); - if ($free >= 0) { - return \OC\Files\Stream\Quota::wrap($source, $free); - } else { - return $source; - } - } -} diff --git a/lib/files/storage/wrapper/wrapper.php b/lib/files/storage/wrapper/wrapper.php deleted file mode 100644 index 0336c27efa1..00000000000 --- a/lib/files/storage/wrapper/wrapper.php +++ /dev/null @@ -1,427 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Storage\Wrapper; - -class Wrapper implements \OC\Files\Storage\Storage { - /** - * @var \OC\Files\Storage\Storage $storage - */ - protected $storage; - - /** - * @param array $parameters - */ - public function __construct($parameters) { - $this->storage = $parameters['storage']; - } - - /** - * @return \OC\Files\Storage\Storage - */ - public function getWrapperStorage() { - return $this->storage; - } - - /** - * Get the identifier for the storage, - * the returned id should be the same for every storage object that is created with the same parameters - * and two storage objects with the same id should refer to two storages that display the same files. - * - * @return string - */ - public function getId() { - return $this->storage->getId(); - } - - /** - * see http://php.net/manual/en/function.mkdir.php - * - * @param string $path - * @return bool - */ - public function mkdir($path) { - return $this->storage->mkdir($path); - } - - /** - * see http://php.net/manual/en/function.rmdir.php - * - * @param string $path - * @return bool - */ - public function rmdir($path) { - return $this->storage->rmdir($path); - } - - /** - * see http://php.net/manual/en/function.opendir.php - * - * @param string $path - * @return resource - */ - public function opendir($path) { - return $this->storage->opendir($path); - } - - /** - * see http://php.net/manual/en/function.is_dir.php - * - * @param string $path - * @return bool - */ - public function is_dir($path) { - return $this->storage->is_dir($path); - } - - /** - * see http://php.net/manual/en/function.is_file.php - * - * @param string $path - * @return bool - */ - public function is_file($path) { - return $this->storage->is_file($path); - } - - /** - * see http://php.net/manual/en/function.stat.php - * only the following keys are required in the result: size and mtime - * - * @param string $path - * @return array - */ - public function stat($path) { - return $this->storage->stat($path); - } - - /** - * see http://php.net/manual/en/function.filetype.php - * - * @param string $path - * @return bool - */ - public function filetype($path) { - return $this->storage->filetype($path); - } - - /** - * see http://php.net/manual/en/function.filesize.php - * The result for filesize when called on a folder is required to be 0 - * - * @param string $path - * @return int - */ - public function filesize($path) { - return $this->storage->filesize($path); - } - - /** - * check if a file can be created in $path - * - * @param string $path - * @return bool - */ - public function isCreatable($path) { - return $this->storage->isCreatable($path); - } - - /** - * check if a file can be read - * - * @param string $path - * @return bool - */ - public function isReadable($path) { - return $this->storage->isReadable($path); - } - - /** - * check if a file can be written to - * - * @param string $path - * @return bool - */ - public function isUpdatable($path) { - return $this->storage->isUpdatable($path); - } - - /** - * check if a file can be deleted - * - * @param string $path - * @return bool - */ - public function isDeletable($path) { - return $this->storage->isDeletable($path); - } - - /** - * check if a file can be shared - * - * @param string $path - * @return bool - */ - public function isSharable($path) { - return $this->storage->isSharable($path); - } - - /** - * get the full permissions of a path. - * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php - * - * @param string $path - * @return int - */ - public function getPermissions($path) { - return $this->storage->getPermissions($path); - } - - /** - * see http://php.net/manual/en/function.file_exists.php - * - * @param string $path - * @return bool - */ - public function file_exists($path) { - return $this->storage->file_exists($path); - } - - /** - * see http://php.net/manual/en/function.filemtime.php - * - * @param string $path - * @return int - */ - public function filemtime($path) { - return $this->storage->filemtime($path); - } - - /** - * see http://php.net/manual/en/function.file_get_contents.php - * - * @param string $path - * @return string - */ - public function file_get_contents($path) { - return $this->storage->file_get_contents($path); - } - - /** - * see http://php.net/manual/en/function.file_put_contents.php - * - * @param string $path - * @param string $data - * @return bool - */ - public function file_put_contents($path, $data) { - return $this->storage->file_put_contents($path, $data); - } - - /** - * see http://php.net/manual/en/function.unlink.php - * - * @param string $path - * @return bool - */ - public function unlink($path) { - return $this->storage->unlink($path); - } - - /** - * see http://php.net/manual/en/function.rename.php - * - * @param string $path1 - * @param string $path2 - * @return bool - */ - public function rename($path1, $path2) { - return $this->storage->rename($path1, $path2); - } - - /** - * see http://php.net/manual/en/function.copy.php - * - * @param string $path1 - * @param string $path2 - * @return bool - */ - public function copy($path1, $path2) { - return $this->storage->copy($path1, $path2); - } - - /** - * see http://php.net/manual/en/function.fopen.php - * - * @param string $path - * @param string $mode - * @return resource - */ - public function fopen($path, $mode) { - return $this->storage->fopen($path, $mode); - } - - /** - * get the mimetype for a file or folder - * The mimetype for a folder is required to be "httpd/unix-directory" - * - * @param string $path - * @return string - */ - public function getMimeType($path) { - return $this->storage->getMimeType($path); - } - - /** - * see http://php.net/manual/en/function.hash.php - * - * @param string $type - * @param string $path - * @param bool $raw - * @return string - */ - public function hash($type, $path, $raw = false) { - return $this->storage->hash($type, $path, $raw); - } - - /** - * see http://php.net/manual/en/function.free_space.php - * - * @param string $path - * @return int - */ - public function free_space($path) { - return $this->storage->free_space($path); - } - - /** - * search for occurrences of $query in file names - * - * @param string $query - * @return array - */ - public function search($query) { - return $this->storage->search($query); - } - - /** - * see http://php.net/manual/en/function.touch.php - * If the backend does not support the operation, false should be returned - * - * @param string $path - * @param int $mtime - * @return bool - */ - public function touch($path, $mtime = null) { - return $this->storage->touch($path, $mtime); - } - - /** - * get the path to a local version of the file. - * The local version of the file can be temporary and doesn't have to be persistent across requests - * - * @param string $path - * @return string - */ - public function getLocalFile($path) { - return $this->storage->getLocalFile($path); - } - - /** - * get the path to a local version of the folder. - * The local version of the folder can be temporary and doesn't have to be persistent across requests - * - * @param string $path - * @return string - */ - public function getLocalFolder($path) { - return $this->storage->getLocalFolder($path); - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - * - * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. - * returning true for other changes in the folder is optional - */ - public function hasUpdated($path, $time) { - return $this->storage->hasUpdated($path, $time); - } - - /** - * get a cache instance for the storage - * - * @param string $path - * @return \OC\Files\Cache\Cache - */ - public function getCache($path = '') { - return $this->storage->getCache($path); - } - - /** - * get a scanner instance for the storage - * - * @param string $path - * @return \OC\Files\Cache\Scanner - */ - public function getScanner($path = '') { - return $this->storage->getScanner($path); - } - - - /** - * get the user id of the owner of a file or folder - * - * @param string $path - * @return string - */ - public function getOwner($path) { - return $this->storage->getOwner($path); - } - - /** - * get a permissions cache instance for the cache - * - * @param string $path - * @return \OC\Files\Cache\Permissions - */ - public function getPermissionsCache($path = '') { - return $this->storage->getPermissionsCache($path); - } - - /** - * get a watcher instance for the cache - * - * @param string $path - * @return \OC\Files\Cache\Watcher - */ - public function getWatcher($path = '') { - return $this->storage->getWatcher($path); - } - - /** - * @return \OC\Files\Cache\Storage - */ - public function getStorageCache() { - return $this->storage->getStorageCache(); - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path) { - return $this->storage->getETag($path); - } -} diff --git a/lib/files/stream/close.php b/lib/files/stream/close.php deleted file mode 100644 index 80de3497c36..00000000000 --- a/lib/files/stream/close.php +++ /dev/null @@ -1,100 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Stream; - -/** - * stream wrapper that provides a callback on stream close - */ -class Close { - private static $callBacks = array(); - private $path = ''; - private $source; - private static $open = array(); - - public function stream_open($path, $mode, $options, &$opened_path) { - $path = substr($path, strlen('close://')); - $this->path = $path; - $this->source = fopen($path, $mode); - if (is_resource($this->source)) { - $this->meta = stream_get_meta_data($this->source); - } - self::$open[] = $path; - return is_resource($this->source); - } - - public function stream_seek($offset, $whence = SEEK_SET) { - fseek($this->source, $offset, $whence); - } - - public function stream_tell() { - return ftell($this->source); - } - - public function stream_read($count) { - return fread($this->source, $count); - } - - public function stream_write($data) { - return fwrite($this->source, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch ($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->source); - } - - public function stream_lock($mode) { - flock($this->source, $mode); - } - - public function stream_flush() { - return fflush($this->source); - } - - public function stream_eof() { - return feof($this->source); - } - - public function url_stat($path) { - $path = substr($path, strlen('close://')); - if (file_exists($path)) { - return stat($path); - } else { - return false; - } - } - - public function stream_close() { - fclose($this->source); - if (isset(self::$callBacks[$this->path])) { - call_user_func(self::$callBacks[$this->path], $this->path); - } - } - - public function unlink($path) { - $path = substr($path, strlen('close://')); - return unlink($path); - } - - public static function registerCallback($path, $callback) { - self::$callBacks[$path] = $callback; - } -} diff --git a/lib/files/stream/dir.php b/lib/files/stream/dir.php deleted file mode 100644 index 6ca884fc994..00000000000 --- a/lib/files/stream/dir.php +++ /dev/null @@ -1,47 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Stream; - -class Dir { - private static $dirs = array(); - private $name; - private $index; - - public function dir_opendir($path, $options) { - $this->name = substr($path, strlen('fakedir://')); - $this->index = 0; - if (!isset(self::$dirs[$this->name])) { - self::$dirs[$this->name] = array(); - } - return true; - } - - public function dir_readdir() { - if ($this->index >= count(self::$dirs[$this->name])) { - return false; - } - $filename = self::$dirs[$this->name][$this->index]; - $this->index++; - return $filename; - } - - public function dir_closedir() { - $this->name = ''; - return true; - } - - public function dir_rewinddir() { - $this->index = 0; - return true; - } - - public static function register($path, $content) { - self::$dirs[$path] = $content; - } -} diff --git a/lib/files/stream/oc.php b/lib/files/stream/oc.php deleted file mode 100644 index 88e7e062df9..00000000000 --- a/lib/files/stream/oc.php +++ /dev/null @@ -1,129 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Stream; - -/** - * a stream wrappers for ownCloud's virtual filesystem - */ -class OC { - /** - * @var \OC\Files\View - */ - static private $rootView; - - private $path; - private $dirSource; - private $fileSource; - private $meta; - - private function setup(){ - if (!self::$rootView) { - self::$rootView = new \OC\Files\View(''); - } - } - - public function stream_open($path, $mode, $options, &$opened_path) { - $this->setup(); - $path = substr($path, strlen('oc://')); - $this->path = $path; - $this->fileSource = self::$rootView->fopen($path, $mode); - if (is_resource($this->fileSource)) { - $this->meta = stream_get_meta_data($this->fileSource); - } - return is_resource($this->fileSource); - } - - public function stream_seek($offset, $whence = SEEK_SET) { - fseek($this->fileSource, $offset, $whence); - } - - public function stream_tell() { - return ftell($this->fileSource); - } - - public function stream_read($count) { - return fread($this->fileSource, $count); - } - - public function stream_write($data) { - return fwrite($this->fileSource, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch ($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->fileSource, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->fileSource, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->fileSource, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->fileSource); - } - - public function stream_lock($mode) { - flock($this->fileSource, $mode); - } - - public function stream_flush() { - return fflush($this->fileSource); - } - - public function stream_eof() { - return feof($this->fileSource); - } - - public function url_stat($path) { - $this->setup(); - $path = substr($path, strlen('oc://')); - if (self::$rootView->file_exists($path)) { - return self::$rootView->stat($path); - } else { - return false; - } - } - - public function stream_close() { - fclose($this->fileSource); - } - - public function unlink($path) { - $this->setup(); - $path = substr($path, strlen('oc://')); - return self::$rootView->unlink($path); - } - - public function dir_opendir($path, $options) { - $this->setup(); - $path = substr($path, strlen('oc://')); - $this->path = $path; - $this->dirSource = self::$rootView->opendir($path); - if (is_resource($this->dirSource)) { - $this->meta = stream_get_meta_data($this->dirSource); - } - return is_resource($this->dirSource); - } - - public function dir_readdir() { - return readdir($this->dirSource); - } - - public function dir_closedir() { - closedir($this->dirSource); - } - - public function dir_rewinddir() { - rewinddir($this->dirSource); - } -} diff --git a/lib/files/stream/quota.php b/lib/files/stream/quota.php deleted file mode 100644 index 53d8a03d30f..00000000000 --- a/lib/files/stream/quota.php +++ /dev/null @@ -1,128 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Stream; - -/** - * stream wrapper limits the amount of data that can be written to a stream - * - * usage: void \OC\Files\Stream\Quota::register($id, $stream, $limit) - * or: resource \OC\Files\Stream\Quota::wrap($stream, $limit) - */ -class Quota { - private static $streams = array(); - - /** - * @var resource $source - */ - private $source; - - /** - * @var int $limit - */ - private $limit; - - /** - * @param string $id - * @param resource $stream - * @param int $limit - */ - public static function register($id, $stream, $limit) { - self::$streams[$id] = array($stream, $limit); - } - - /** - * remove all registered streams - */ - public static function clear() { - self::$streams = array(); - } - - /** - * @param resource $stream - * @param int $limit - * @return resource - */ - static public function wrap($stream, $limit) { - $id = uniqid(); - self::register($id, $stream, $limit); - $meta = stream_get_meta_data($stream); - return fopen('quota://' . $id, $meta['mode']); - } - - public function stream_open($path, $mode, $options, &$opened_path) { - $id = substr($path, strlen('quota://')); - if (isset(self::$streams[$id])) { - list($this->source, $this->limit) = self::$streams[$id]; - return true; - } else { - return false; - } - } - - public function stream_seek($offset, $whence = SEEK_SET) { - if ($whence === SEEK_SET) { - $this->limit += $this->stream_tell() - $offset; - } else { - $this->limit -= $offset; - } - fseek($this->source, $offset, $whence); - } - - public function stream_tell() { - return ftell($this->source); - } - - public function stream_read($count) { - $this->limit -= $count; - return fread($this->source, $count); - } - - public function stream_write($data) { - $size = strlen($data); - if ($size > $this->limit) { - $data = substr($data, 0, $this->limit); - $size = $this->limit; - } - $this->limit -= $size; - return fwrite($this->source, $data); - } - - public function stream_set_option($option, $arg1, $arg2) { - switch ($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->source); - } - - public function stream_lock($mode) { - flock($this->source, $mode); - } - - public function stream_flush() { - return fflush($this->source); - } - - public function stream_eof() { - return feof($this->source); - } - - public function stream_close() { - fclose($this->source); - } -} diff --git a/lib/files/stream/staticstream.php b/lib/files/stream/staticstream.php deleted file mode 100644 index 45b1a7a81f8..00000000000 --- a/lib/files/stream/staticstream.php +++ /dev/null @@ -1,156 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Stream; - -class StaticStream { - const MODE_FILE = 0100000; - - public $context; - protected static $data = array(); - - protected $path = ''; - protected $pointer = 0; - protected $writable = false; - - public function stream_close() { - } - - public function stream_eof() { - return $this->pointer >= strlen(self::$data[$this->path]); - } - - public function stream_flush() { - } - - public static function clear() { - self::$data = array(); - } - - public function stream_open($path, $mode, $options, &$opened_path) { - switch ($mode[0]) { - case 'r': - if (!isset(self::$data[$path])) return false; - $this->path = $path; - $this->writable = isset($mode[1]) && $mode[1] == '+'; - break; - case 'w': - self::$data[$path] = ''; - $this->path = $path; - $this->writable = true; - break; - case 'a': - if (!isset(self::$data[$path])) self::$data[$path] = ''; - $this->path = $path; - $this->writable = true; - $this->pointer = strlen(self::$data[$path]); - break; - case 'x': - if (isset(self::$data[$path])) return false; - $this->path = $path; - $this->writable = true; - break; - case 'c': - if (!isset(self::$data[$path])) self::$data[$path] = ''; - $this->path = $path; - $this->writable = true; - break; - default: - return false; - } - $opened_path = $this->path; - return true; - } - - public function stream_read($count) { - $bytes = min(strlen(self::$data[$this->path]) - $this->pointer, $count); - $data = substr(self::$data[$this->path], $this->pointer, $bytes); - $this->pointer += $bytes; - return $data; - } - - public function stream_seek($offset, $whence = SEEK_SET) { - $len = strlen(self::$data[$this->path]); - switch ($whence) { - case SEEK_SET: - if ($offset <= $len) { - $this->pointer = $offset; - return true; - } - break; - case SEEK_CUR: - if ($this->pointer + $offset <= $len) { - $this->pointer += $offset; - return true; - } - break; - case SEEK_END: - if ($len + $offset <= $len) { - $this->pointer = $len + $offset; - return true; - } - break; - } - return false; - } - - public function stream_stat() { - return $this->url_stat($this->path); - } - - public function stream_tell() { - return $this->pointer; - } - - public function stream_write($data) { - if (!$this->writable) return 0; - $size = strlen($data); - if ($this->stream_eof()) { - self::$data[$this->path] .= $data; - } else { - self::$data[$this->path] = substr_replace( - self::$data[$this->path], - $data, - $this->pointer - ); - } - $this->pointer += $size; - return $size; - } - - public function unlink($path) { - if (isset(self::$data[$path])) { - unset(self::$data[$path]); - } - return true; - } - - public function url_stat($path) { - if (isset(self::$data[$path])) { - $size = strlen(self::$data[$path]); - $time = time(); - $data = array( - 'dev' => 0, - 'ino' => 0, - 'mode' => self::MODE_FILE | 0777, - 'nlink' => 1, - 'uid' => 0, - 'gid' => 0, - 'rdev' => '', - 'size' => $size, - 'atime' => $time, - 'mtime' => $time, - 'ctime' => $time, - 'blksize' => -1, - 'blocks' => -1, - ); - return array_values($data) + $data; - } - return false; - } -} diff --git a/lib/files/type/detection.php b/lib/files/type/detection.php deleted file mode 100644 index 242a81cb5a4..00000000000 --- a/lib/files/type/detection.php +++ /dev/null @@ -1,121 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Type; - -/** - * Class Detection - * - * Mimetype detection - * - * @package OC\Files\Type - */ -class Detection { - protected $mimetypes = array(); - - /** - * add an extension -> mimetype mapping - * - * @param string $extension - * @param string $mimetype - */ - public function registerType($extension, $mimetype) { - $this->mimetypes[$extension] = $mimetype; - } - - /** - * add an array of extension -> mimetype mappings - * - * @param array $types - */ - public function registerTypeArray($types) { - $this->mimetypes = array_merge($this->mimetypes, $types); - } - - /** - * detect mimetype only based on filename, content of file is not used - * - * @param string $path - * @return string - */ - public function detectPath($path) { - if (strpos($path, '.')) { - //try to guess the type by the file extension - $extension = strtolower(strrchr(basename($path), ".")); - $extension = substr($extension, 1); //remove leading . - return (isset($this->mimetypes[$extension])) ? $this->mimetypes[$extension] : 'application/octet-stream'; - } else { - return 'application/octet-stream'; - } - } - - /** - * detect mimetype based on both filename and content - * - * @param string $path - * @return string - */ - public function detect($path) { - $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://'); - - if (@is_dir($path)) { - // directories are easy - return "httpd/unix-directory"; - } - - $mimeType = $this->detectPath($path); - - if ($mimeType === 'application/octet-stream' and function_exists('finfo_open') - and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME) - ) { - $info = @strtolower(finfo_file($finfo, $path)); - if ($info) { - $mimeType = substr($info, 0, strpos($info, ';')); - } - finfo_close($finfo); - } - if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) { - // use mime magic extension if available - $mimeType = mime_content_type($path); - } - if (!$isWrapped and $mimeType === 'application/octet-stream' && \OC_Helper::canExecute("file")) { - // it looks like we have a 'file' command, - // lets see if it does have mime support - $path = escapeshellarg($path); - $fp = popen("file -b --mime-type $path 2>/dev/null", "r"); - $reply = fgets($fp); - pclose($fp); - - //trim the newline - $mimeType = trim($reply); - - } - return $mimeType; - } - - /** - * detect mimetype based on the content of a string - * - * @param string $data - * @return string - */ - public function detectString($data) { - if (function_exists('finfo_open') and function_exists('finfo_file')) { - $finfo = finfo_open(FILEINFO_MIME); - return finfo_buffer($finfo, $data); - } else { - $tmpFile = \OC_Helper::tmpFile(); - $fh = fopen($tmpFile, 'wb'); - fwrite($fh, $data, 8024); - fclose($fh); - $mime = $this->detect($tmpFile); - unset($tmpFile); - return $mime; - } - } -} diff --git a/lib/files/type/templatemanager.php b/lib/files/type/templatemanager.php deleted file mode 100644 index cd1536d2732..00000000000 --- a/lib/files/type/templatemanager.php +++ /dev/null @@ -1,46 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Type; - -class TemplateManager { - protected $templates = array(); - - public function registerTemplate($mimetype, $path) { - $this->templates[$mimetype] = $path; - } - - /** - * get the path of the template for a mimetype - * - * @param string $mimetype - * @return string | null - */ - public function getTemplatePath($mimetype) { - if (isset($this->templates[$mimetype])) { - return $this->templates[$mimetype]; - } else { - return null; - } - } - - /** - * get the template content for a mimetype - * - * @param string $mimetype - * @return string - */ - public function getTemplate($mimetype) { - $path = $this->getTemplatePath($mimetype); - if ($path) { - return file_get_contents($path); - } else { - return ''; - } - } -} diff --git a/lib/files/utils/scanner.php b/lib/files/utils/scanner.php deleted file mode 100644 index 2cad7dd77bd..00000000000 --- a/lib/files/utils/scanner.php +++ /dev/null @@ -1,96 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Utils; - -use OC\Files\Filesystem; -use OC\Hooks\PublicEmitter; - -/** - * Class Scanner - * - * Hooks available in scope \OC\Utils\Scanner - * - scanFile(string $absolutePath) - * - scanFolder(string $absolutePath) - * - * @package OC\Files\Utils - */ -class Scanner extends PublicEmitter { - /** - * @var string $user - */ - private $user; - - /** - * @param string $user - */ - public function __construct($user) { - $this->user = $user; - } - - /** - * get all storages for $dir - * - * @param string $dir - * @return \OC\Files\Mount\Mount[] - */ - protected function getMounts($dir) { - //TODO: move to the node based fileapi once that's done - \OC_Util::tearDownFS(); - \OC_Util::setupFS($this->user); - $absolutePath = Filesystem::getView()->getAbsolutePath($dir); - - $mountManager = Filesystem::getMountManager(); - $mounts = $mountManager->findIn($absolutePath); - $mounts[] = $mountManager->find($absolutePath); - $mounts = array_reverse($mounts); //start with the mount of $dir - - return $mounts; - } - - /** - * attach listeners to the scanner - * - * @param \OC\Files\Mount\Mount $mount - */ - protected function attachListener($mount) { - $scanner = $mount->getStorage()->getScanner(); - $emitter = $this; - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function ($path) use ($mount, $emitter) { - $emitter->emit('\OC\Files\Utils\Scanner', 'scanFile', array($mount->getMountPoint() . $path)); - }); - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFolder', function ($path) use ($mount, $emitter) { - $emitter->emit('\OC\Files\Utils\Scanner', 'scanFolder', array($mount->getMountPoint() . $path)); - }); - } - - public function backgroundScan($dir) { - $mounts = $this->getMounts($dir); - foreach ($mounts as $mount) { - if (is_null($mount->getStorage())) { - continue; - } - $scanner = $mount->getStorage()->getScanner(); - $this->attachListener($mount); - $scanner->backgroundScan(); - } - } - - public function scan($dir) { - $mounts = $this->getMounts($dir); - foreach ($mounts as $mount) { - if (is_null($mount->getStorage())) { - continue; - } - $scanner = $mount->getStorage()->getScanner(); - $this->attachListener($mount); - $scanner->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG); - } - } -} - diff --git a/lib/files/view.php b/lib/files/view.php deleted file mode 100644 index aa08a5f7cc9..00000000000 --- a/lib/files/view.php +++ /dev/null @@ -1,1078 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * Class to provide access to ownCloud filesystem via a "view", and methods for - * working with files within that view (e.g. read, write, delete, etc.). Each - * view is restricted to a set of directories via a virtual root. The default view - * uses the currently logged in user's data directory as root (parts of - * OC_Filesystem are merely a wrapper for OC_FilesystemView). - * - * Apps that need to access files outside of the user data folders (to modify files - * belonging to a user other than the one currently logged in, for example) should - * use this class directly rather than using OC_Filesystem, or making use of PHP's - * built-in file manipulation functions. This will ensure all hooks and proxies - * are triggered correctly. - * - * Filesystem functions are not called directly; they are passed to the correct - * \OC\Files\Storage\Storage object - */ - -namespace OC\Files; - -class View { - private $fakeRoot = ''; - private $internal_path_cache = array(); - private $storage_cache = array(); - - public function __construct($root = '') { - $this->fakeRoot = $root; - } - - public function getAbsolutePath($path = '/') { - if (!$path) { - $path = '/'; - } - if ($path[0] !== '/') { - $path = '/' . $path; - } - return $this->fakeRoot . $path; - } - - /** - * change the root to a fake root - * - * @param string $fakeRoot - * @return bool - */ - public function chroot($fakeRoot) { - if (!$fakeRoot == '') { - if ($fakeRoot[0] !== '/') { - $fakeRoot = '/' . $fakeRoot; - } - } - $this->fakeRoot = $fakeRoot; - } - - /** - * get the fake root - * - * @return string - */ - public function getRoot() { - return $this->fakeRoot; - } - - /** - * get path relative to the root of the view - * - * @param string $path - * @return string - */ - public function getRelativePath($path) { - if ($this->fakeRoot == '') { - return $path; - } - if (strpos($path, $this->fakeRoot) !== 0) { - return null; - } else { - $path = substr($path, strlen($this->fakeRoot)); - if (strlen($path) === 0) { - return '/'; - } else { - return $path; - } - } - } - - /** - * get the mountpoint of the storage object for a path - * ( note: because a storage is not always mounted inside the fakeroot, the - * returned mountpoint is relative to the absolute root of the filesystem - * and doesn't take the chroot into account ) - * - * @param string $path - * @return string - */ - public function getMountPoint($path) { - return Filesystem::getMountPoint($this->getAbsolutePath($path)); - } - - /** - * resolve a path to a storage and internal path - * - * @param string $path - * @return array consisting of the storage and the internal path - */ - public function resolvePath($path) { - return Filesystem::resolvePath($this->getAbsolutePath($path)); - } - - /** - * return the path to a local version of the file - * we need this because we can't know if a file is stored local or not from - * outside the filestorage and for some purposes a local file is needed - * - * @param string $path - * @return string - */ - public function getLocalFile($path) { - $parent = substr($path, 0, strrpos($path, '/')); - $path = $this->getAbsolutePath($path); - list($storage, $internalPath) = Filesystem::resolvePath($path); - if (Filesystem::isValidPath($parent) and $storage) { - return $storage->getLocalFile($internalPath); - } else { - return null; - } - } - - /** - * @param string $path - * @return string - */ - public function getLocalFolder($path) { - $parent = substr($path, 0, strrpos($path, '/')); - $path = $this->getAbsolutePath($path); - list($storage, $internalPath) = Filesystem::resolvePath($path); - if (Filesystem::isValidPath($parent) and $storage) { - return $storage->getLocalFolder($internalPath); - } else { - return null; - } - } - - /** - * the following functions operate with arguments and return values identical - * to those of their PHP built-in equivalents. Mostly they are merely wrappers - * for \OC\Files\Storage\Storage via basicOperation(). - */ - public function mkdir($path) { - return $this->basicOperation('mkdir', $path, array('create', 'write')); - } - - public function rmdir($path) { - return $this->basicOperation('rmdir', $path, array('delete')); - } - - public function opendir($path) { - return $this->basicOperation('opendir', $path, array('read')); - } - - public function readdir($handle) { - $fsLocal = new Storage\Local(array('datadir' => '/')); - return $fsLocal->readdir($handle); - } - - public function is_dir($path) { - if ($path == '/') { - return true; - } - return $this->basicOperation('is_dir', $path); - } - - public function is_file($path) { - if ($path == '/') { - return false; - } - return $this->basicOperation('is_file', $path); - } - - public function stat($path) { - return $this->basicOperation('stat', $path); - } - - public function filetype($path) { - return $this->basicOperation('filetype', $path); - } - - public function filesize($path) { - return $this->basicOperation('filesize', $path); - } - - public function readfile($path) { - @ob_end_clean(); - $handle = $this->fopen($path, 'rb'); - if ($handle) { - $chunkSize = 8192; // 8 kB chunks - while (!feof($handle)) { - echo fread($handle, $chunkSize); - flush(); - } - $size = $this->filesize($path); - return $size; - } - return false; - } - - public function isCreatable($path) { - return $this->basicOperation('isCreatable', $path); - } - - public function isReadable($path) { - return $this->basicOperation('isReadable', $path); - } - - public function isUpdatable($path) { - return $this->basicOperation('isUpdatable', $path); - } - - public function isDeletable($path) { - return $this->basicOperation('isDeletable', $path); - } - - public function isSharable($path) { - return $this->basicOperation('isSharable', $path); - } - - public function file_exists($path) { - if ($path == '/') { - return true; - } - return $this->basicOperation('file_exists', $path); - } - - public function filemtime($path) { - return $this->basicOperation('filemtime', $path); - } - - public function touch($path, $mtime = null) { - if (!is_null($mtime) and !is_numeric($mtime)) { - $mtime = strtotime($mtime); - } - - $hooks = array('touch'); - - if (!$this->file_exists($path)) { - $hooks[] = 'create'; - $hooks[] = 'write'; - } - $result = $this->basicOperation('touch', $path, $hooks, $mtime); - if (!$result) { //if native touch fails, we emulate it by changing the mtime in the cache - $this->putFileInfo($path, array('mtime' => $mtime)); - } - return true; - } - - public function file_get_contents($path) { - return $this->basicOperation('file_get_contents', $path, array('read')); - } - - public function file_put_contents($path, $data) { - if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier - $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (\OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) - and Filesystem::isValidPath($path) - and !Filesystem::isFileBlacklisted($path) - ) { - $path = $this->getRelativePath($absolutePath); - $exists = $this->file_exists($path); - $run = true; - if ($this->shouldEmitHooks($path)) { - if (!$exists) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_create, - array( - Filesystem::signal_param_path => $this->getHookPath($path), - Filesystem::signal_param_run => &$run - ) - ); - } - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_write, - array( - Filesystem::signal_param_path => $this->getHookPath($path), - Filesystem::signal_param_run => &$run - ) - ); - } - if (!$run) { - return false; - } - $target = $this->fopen($path, 'w'); - if ($target) { - list ($count, $result) = \OC_Helper::streamCopy($data, $target); - fclose($target); - fclose($data); - if ($this->shouldEmitHooks($path) && $result !== false) { - if (!$exists) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_create, - array(Filesystem::signal_param_path => $this->getHookPath($path)) - ); - } - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_write, - array(Filesystem::signal_param_path => $this->getHookPath($path)) - ); - } - \OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); - return $result; - } else { - return false; - } - } else { - return false; - } - } else { - return $this->basicOperation('file_put_contents', $path, array('create', 'write'), $data); - } - } - - public function unlink($path) { - return $this->basicOperation('unlink', $path, array('delete')); - } - - public function deleteAll($directory, $empty = false) { - return $this->rmdir($directory); - } - - public function rename($path1, $path2) { - $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; - $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; - $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); - $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); - if ( - \OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2) - and Filesystem::isValidPath($path2) - and Filesystem::isValidPath($path1) - and !Filesystem::isFileBlacklisted($path2) - ) { - $path1 = $this->getRelativePath($absolutePath1); - $path2 = $this->getRelativePath($absolutePath2); - - if ($path1 == null or $path2 == null) { - return false; - } - $run = true; - if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) { - // if it was a rename from a part file to a regular file it was a write and not a rename operation - \OC_Hook::emit( - Filesystem::CLASSNAME, Filesystem::signal_write, - array( - Filesystem::signal_param_path => $this->getHookPath($path2), - Filesystem::signal_param_run => &$run - ) - ); - } elseif ($this->shouldEmitHooks()) { - \OC_Hook::emit( - Filesystem::CLASSNAME, Filesystem::signal_rename, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2), - Filesystem::signal_param_run => &$run - ) - ); - } - if ($run) { - $mp1 = $this->getMountPoint($path1 . $postFix1); - $mp2 = $this->getMountPoint($path2 . $postFix2); - if ($mp1 == $mp2) { - list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); - list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); - if ($storage) { - $result = $storage->rename($internalPath1, $internalPath2); - \OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2); - } else { - $result = false; - } - } else { - if ($this->is_dir($path1)) { - $result = $this->copy($path1, $path2); - if ($result === true) { - list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); - $result = $storage1->deleteAll($internalPath1); - } - } else { - $source = $this->fopen($path1 . $postFix1, 'r'); - $target = $this->fopen($path2 . $postFix2, 'w'); - list($count, $result) = \OC_Helper::streamCopy($source, $target); - - // close open handle - especially $source is necessary because unlink below will - // throw an exception on windows because the file is locked - fclose($source); - fclose($target); - - if ($result !== false) { - list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); - $storage1->unlink($internalPath1); - } - } - } - if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { - // if it was a rename from a part file to a regular file it was a write and not a rename operation - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_write, - array( - Filesystem::signal_param_path => $this->getHookPath($path2), - ) - ); - } elseif ($this->shouldEmitHooks() && $result !== false) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_rename, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2) - ) - ); - } - return $result; - } else { - return false; - } - } else { - return false; - } - } - - public function copy($path1, $path2) { - $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; - $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; - $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); - $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); - if ( - \OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) - and Filesystem::isValidPath($path2) - and Filesystem::isValidPath($path1) - and !Filesystem::isFileBlacklisted($path2) - ) { - $path1 = $this->getRelativePath($absolutePath1); - $path2 = $this->getRelativePath($absolutePath2); - - if ($path1 == null or $path2 == null) { - return false; - } - $run = true; - $exists = $this->file_exists($path2); - if ($this->shouldEmitHooks()) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_copy, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2), - Filesystem::signal_param_run => &$run - ) - ); - if ($run and !$exists) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_create, - array( - Filesystem::signal_param_path => $this->getHookPath($path2), - Filesystem::signal_param_run => &$run - ) - ); - } - if ($run) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_write, - array( - Filesystem::signal_param_path => $this->getHookPath($path2), - Filesystem::signal_param_run => &$run - ) - ); - } - } - if ($run) { - $mp1 = $this->getMountPoint($path1 . $postFix1); - $mp2 = $this->getMountPoint($path2 . $postFix2); - if ($mp1 == $mp2) { - list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); - list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); - if ($storage) { - $result = $storage->copy($internalPath1, $internalPath2); - } else { - $result = false; - } - } else { - if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) { - $result = $this->mkdir($path2); - if (is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if (!Filesystem::isIgnoredDir($file)) { - $result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file); - } - } - } - } else { - $source = $this->fopen($path1 . $postFix1, 'r'); - $target = $this->fopen($path2 . $postFix2, 'w'); - list($count, $result) = \OC_Helper::streamCopy($source, $target); - } - } - if ($this->shouldEmitHooks() && $result !== false) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_copy, - array( - Filesystem::signal_param_oldpath => $this->getHookPath($path1), - Filesystem::signal_param_newpath => $this->getHookPath($path2) - ) - ); - if (!$exists) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_create, - array(Filesystem::signal_param_path => $this->getHookPath($path2)) - ); - } - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_post_write, - array(Filesystem::signal_param_path => $this->getHookPath($path2)) - ); - } - return $result; - } else { - return false; - } - } else { - return false; - } - } - - public function fopen($path, $mode) { - $hooks = array(); - switch ($mode) { - case 'r': - case 'rb': - $hooks[] = 'read'; - break; - case 'r+': - case 'rb+': - case 'w+': - case 'wb+': - case 'x+': - case 'xb+': - case 'a+': - case 'ab+': - $hooks[] = 'read'; - $hooks[] = 'write'; - break; - case 'w': - case 'wb': - case 'x': - case 'xb': - case 'a': - case 'ab': - $hooks[] = 'write'; - break; - default: - \OC_Log::write('core', 'invalid mode (' . $mode . ') for ' . $path, \OC_Log::ERROR); - } - - return $this->basicOperation('fopen', $path, $hooks, $mode); - } - - public function toTmpFile($path) { - if (Filesystem::isValidPath($path)) { - $source = $this->fopen($path, 'r'); - if ($source) { - $extension = pathinfo($path, PATHINFO_EXTENSION); - $tmpFile = \OC_Helper::tmpFile($extension); - file_put_contents($tmpFile, $source); - return $tmpFile; - } else { - return false; - } - } else { - return false; - } - } - - public function fromTmpFile($tmpFile, $path) { - if (Filesystem::isValidPath($path)) { - if (!$tmpFile) { - debug_print_backtrace(); - } - $source = fopen($tmpFile, 'r'); - if ($source) { - $this->file_put_contents($path, $source); - unlink($tmpFile); - return true; - } else { - return false; - } - } else { - return false; - } - } - - public function getMimeType($path) { - return $this->basicOperation('getMimeType', $path); - } - - public function hash($type, $path, $raw = false) { - $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; - $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (\OC_FileProxy::runPreProxies('hash', $absolutePath) && Filesystem::isValidPath($path)) { - $path = $this->getRelativePath($absolutePath); - if ($path == null) { - return false; - } - if ($this->shouldEmitHooks($path)) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - Filesystem::signal_read, - array(Filesystem::signal_param_path => $this->getHookPath($path)) - ); - } - list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); - if ($storage) { - $result = $storage->hash($type, $internalPath, $raw); - $result = \OC_FileProxy::runPostProxies('hash', $absolutePath, $result); - return $result; - } - } - return null; - } - - public function free_space($path = '/') { - return $this->basicOperation('free_space', $path); - } - - /** - * @brief abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage - * @param string $operation - * @param string $path - * @param array $hooks (optional) - * @param mixed $extraParam (optional) - * @return mixed - * - * This method takes requests for basic filesystem functions (e.g. reading & writing - * files), processes hooks and proxies, sanitises paths, and finally passes them on to - * \OC\Files\Storage\Storage for delegation to a storage backend for execution - */ - private function basicOperation($operation, $path, $hooks = array(), $extraParam = null) { - $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; - $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) - and Filesystem::isValidPath($path) - and !Filesystem::isFileBlacklisted($path) - ) { - $path = $this->getRelativePath($absolutePath); - if ($path == null) { - return false; - } - - $run = $this->runHooks($hooks, $path); - list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); - if ($run and $storage) { - if (!is_null($extraParam)) { - $result = $storage->$operation($internalPath, $extraParam); - } else { - $result = $storage->$operation($internalPath); - } - $result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result); - if ($this->shouldEmitHooks($path) && $result !== false) { - if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open - $this->runHooks($hooks, $path, true); - } - } - return $result; - } - } - return null; - } - - /** - * get the path relative to the default root for hook usage - * - * @param string $path - * @return string - */ - private function getHookPath($path) { - if (!Filesystem::getView()) { - return $path; - } - return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path)); - } - - private function shouldEmitHooks($path = '') { - if ($path && Cache\Scanner::isPartialFile($path)) { - return false; - } - if (!Filesystem::$loaded) { - return false; - } - $defaultRoot = Filesystem::getRoot(); - return (strlen($this->fakeRoot) >= strlen($defaultRoot)) && (substr($this->fakeRoot, 0, strlen($defaultRoot)) === $defaultRoot); - } - - private function runHooks($hooks, $path, $post = false) { - $path = $this->getHookPath($path); - $prefix = ($post) ? 'post_' : ''; - $run = true; - if ($this->shouldEmitHooks($path)) { - foreach ($hooks as $hook) { - if ($hook != 'read') { - \OC_Hook::emit( - Filesystem::CLASSNAME, - $prefix . $hook, - array( - Filesystem::signal_param_run => &$run, - Filesystem::signal_param_path => $path - ) - ); - } elseif (!$post) { - \OC_Hook::emit( - Filesystem::CLASSNAME, - $prefix . $hook, - array( - Filesystem::signal_param_path => $path - ) - ); - } - } - } - return $run; - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @return bool - */ - public function hasUpdated($path, $time) { - return $this->basicOperation('hasUpdated', $path, array(), $time); - } - - /** - * get the filesystem info - * - * @param string $path - * @return array - * - * returns an associative array with the following keys: - * - size - * - mtime - * - mimetype - * - encrypted - * - versioned - */ - public function getFileInfo($path) { - $data = array(); - if (!Filesystem::isValidPath($path)) { - return $data; - } - $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = Filesystem::resolvePath($path); - if ($storage) { - $cache = $storage->getCache($internalPath); - $permissionsCache = $storage->getPermissionsCache($internalPath); - $user = \OC_User::getUser(); - - if (!$cache->inCache($internalPath)) { - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); - } else { - $watcher = $storage->getWatcher($internalPath); - $watcher->checkUpdate($internalPath); - } - - $data = $cache->get($internalPath); - - if ($data and $data['fileid']) { - if ($data['mimetype'] === 'httpd/unix-directory') { - //add the sizes of other mountpoints to the folder - $mountPoints = Filesystem::getMountPoints($path); - foreach ($mountPoints as $mountPoint) { - $subStorage = Filesystem::getStorage($mountPoint); - if ($subStorage) { - $subCache = $subStorage->getCache(''); - $rootEntry = $subCache->get(''); - $data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0; - } - } - } - - $permissions = $permissionsCache->get($data['fileid'], $user); - if ($permissions === -1) { - $permissions = $storage->getPermissions($internalPath); - $permissionsCache->set($data['fileid'], $user, $permissions); - } - $data['permissions'] = $permissions; - } - } - - $data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data); - - return $data; - } - - /** - * get the content of a directory - * - * @param string $directory path under datadirectory - * @param string $mimetype_filter limit returned content to this mimetype or mimepart - * @return array - */ - public function getDirectoryContent($directory, $mimetype_filter = '') { - $result = array(); - if (!Filesystem::isValidPath($directory)) { - return $result; - } - $path = Filesystem::normalizePath($this->fakeRoot . '/' . $directory); - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = Filesystem::resolvePath($path); - if ($storage) { - $cache = $storage->getCache($internalPath); - $permissionsCache = $storage->getPermissionsCache($internalPath); - $user = \OC_User::getUser(); - - if ($cache->getStatus($internalPath) < Cache\Cache::COMPLETE) { - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); - } else { - $watcher = $storage->getWatcher($internalPath); - $watcher->checkUpdate($internalPath); - } - - $files = $cache->getFolderContents($internalPath); //TODO: mimetype_filter - $permissions = $permissionsCache->getDirectoryPermissions($cache->getId($internalPath), $user); - - $ids = array(); - foreach ($files as $i => $file) { - $files[$i]['type'] = $file['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; - $ids[] = $file['fileid']; - - if (!isset($permissions[$file['fileid']])) { - $permissions[$file['fileid']] = $storage->getPermissions($file['path']); - $permissionsCache->set($file['fileid'], $user, $permissions[$file['fileid']]); - } - $files[$i]['permissions'] = $permissions[$file['fileid']]; - } - - //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders - $mountPoints = Filesystem::getMountPoints($path); - $dirLength = strlen($path); - foreach ($mountPoints as $mountPoint) { - $subStorage = Filesystem::getStorage($mountPoint); - if ($subStorage) { - $subCache = $subStorage->getCache(''); - - if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) { - $subScanner = $subStorage->getScanner(''); - $subScanner->scanFile(''); - } - - $rootEntry = $subCache->get(''); - if ($rootEntry) { - $relativePath = trim(substr($mountPoint, $dirLength), '/'); - if ($pos = strpos($relativePath, '/')) { - //mountpoint inside subfolder add size to the correct folder - $entryName = substr($relativePath, 0, $pos); - foreach ($files as &$entry) { - if ($entry['name'] === $entryName) { - $entry['size'] += $rootEntry['size']; - } - } - } else { //mountpoint in this folder, add an entry for it - $rootEntry['name'] = $relativePath; - $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; - $subPermissionsCache = $subStorage->getPermissionsCache(''); - $permissions = $subPermissionsCache->get($rootEntry['fileid'], $user); - if ($permissions === -1) { - $permissions = $subStorage->getPermissions($rootEntry['path']); - $subPermissionsCache->set($rootEntry['fileid'], $user, $permissions); - } - $rootEntry['permissions'] = $permissions; - - //remove any existing entry with the same name - foreach ($files as $i => $file) { - if ($file['name'] === $rootEntry['name']) { - unset($files[$i]); - break; - } - } - $files[] = $rootEntry; - } - } - } - } - - if ($mimetype_filter) { - foreach ($files as $file) { - if (strpos($mimetype_filter, '/')) { - if ($file['mimetype'] === $mimetype_filter) { - $result[] = $file; - } - } else { - if ($file['mimepart'] === $mimetype_filter) { - $result[] = $file; - } - } - } - } else { - $result = $files; - } - } - return $result; - } - - /** - * change file metadata - * - * @param string $path - * @param array $data - * @return int - * - * returns the fileid of the updated file - */ - public function putFileInfo($path, $data) { - $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = Filesystem::resolvePath($path); - if ($storage) { - $cache = $storage->getCache($path); - - if (!$cache->inCache($internalPath)) { - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); - } - - return $cache->put($internalPath, $data); - } else { - return -1; - } - } - - /** - * search for files with the name matching $query - * - * @param string $query - * @return array - */ - public function search($query) { - return $this->searchCommon('%' . $query . '%', 'search'); - } - - /** - * search for files by mimetype - * - * @param string $mimetype - * @return array - */ - public function searchByMime($mimetype) { - return $this->searchCommon($mimetype, 'searchByMime'); - } - - /** - * @param string $query - * @param string $method - * @return array - */ - private function searchCommon($query, $method) { - $files = array(); - $rootLength = strlen($this->fakeRoot); - - $mountPoint = Filesystem::getMountPoint($this->fakeRoot); - $storage = Filesystem::getStorage($mountPoint); - if ($storage) { - $cache = $storage->getCache(''); - - $results = $cache->$method($query); - foreach ($results as $result) { - if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') { - $result['path'] = substr($mountPoint . $result['path'], $rootLength); - $files[] = $result; - } - } - - $mountPoints = Filesystem::getMountPoints($this->fakeRoot); - foreach ($mountPoints as $mountPoint) { - $storage = Filesystem::getStorage($mountPoint); - if ($storage) { - $cache = $storage->getCache(''); - - $relativeMountPoint = substr($mountPoint, $rootLength); - $results = $cache->$method($query); - if ($results) { - foreach ($results as $result) { - $result['path'] = $relativeMountPoint . $result['path']; - $files[] = $result; - } - } - } - } - } - return $files; - } - - /** - * Get the owner for a file or folder - * - * @param string $path - * @return string - */ - public function getOwner($path) { - return $this->basicOperation('getOwner', $path); - } - - /** - * get the ETag for a file or folder - * - * @param string $path - * @return string - */ - public function getETag($path) { - /** - * @var Storage\Storage $storage - * @var string $internalPath - */ - list($storage, $internalPath) = $this->resolvePath($path); - if ($storage) { - return $storage->getETag($internalPath); - } else { - return null; - } - } - - /** - * Get the path of a file by id, relative to the view - * - * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file - * - * @param int $id - * @return string - */ - public function getPath($id) { - list($storage, $internalPath) = Cache\Cache::getById($id); - $mounts = Filesystem::getMountByStorageId($storage); - foreach ($mounts as $mount) { - /** - * @var \OC\Files\Mount $mount - */ - $fullPath = $mount->getMountPoint() . $internalPath; - if (!is_null($path = $this->getRelativePath($fullPath))) { - return $path; - } - } - return null; - } -} diff --git a/lib/geo.php b/lib/geo.php deleted file mode 100644 index ed01ad0b616..00000000000 --- a/lib/geo.php +++ /dev/null @@ -1,31 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ -class OC_Geo{ - /* - * @brief returns the closest timezone to coordinates - * @param (string) $latitude - Latitude - * @param (string) $longitude - Longitude - * @return (string) $timezone - closest timezone - */ - public static function timezone($latitude, $longitude) { - $alltimezones = DateTimeZone::listIdentifiers(); - $variances = array(); - //calculate for all timezones the system know - foreach($alltimezones as $timezone) { - $datetimezoneobj = new DateTimeZone($timezone); - $locationinformations = $datetimezoneobj->getLocation(); - $latitudeoftimezone = $locationinformations['latitude']; - $longitudeoftimezone = $locationinformations['longitude']; - $variances[abs($latitudeoftimezone - $latitude) + abs($longitudeoftimezone - $longitude)] = $timezone; - } - //sort array and return the timezone with the smallest difference - ksort($variances); - reset($variances); - return current($variances); - } -} diff --git a/lib/group.php b/lib/group.php deleted file mode 100644 index ba93dc129a1..00000000000 --- a/lib/group.php +++ /dev/null @@ -1,301 +0,0 @@ -. - * - */ - -/** - * This class provides all methods needed for managing groups. - * - * Hooks provided: - * pre_createGroup(&run, gid) - * post_createGroup(gid) - * pre_deleteGroup(&run, gid) - * post_deleteGroup(gid) - * pre_addToGroup(&run, uid, gid) - * post_addToGroup(uid, gid) - * pre_removeFromGroup(&run, uid, gid) - * post_removeFromGroup(uid, gid) - */ -class OC_Group { - /** - * @var \OC\Group\Manager $manager - */ - private static $manager; - - /** - * @var \OC\User\Manager - */ - private static $userManager; - - /** - * @return \OC\Group\Manager - */ - public static function getManager() { - if (self::$manager) { - return self::$manager; - } - self::$userManager = \OC_User::getManager(); - self::$manager = new \OC\Group\Manager(self::$userManager); - return self::$manager; - } - - /** - * @brief set the group backend - * @param \OC_Group_Backend $backend The backend to use for user managment - * @return bool - */ - public static function useBackend($backend) { - self::getManager()->addBackend($backend); - return true; - } - - /** - * remove all used backends - */ - public static function clearBackends() { - self::getManager()->clearBackends(); - } - - /** - * @brief Try to create a new group - * @param string $gid The name of the group to create - * @return bool - * - * Tries to create a new group. If the group name already exists, false will - * be returned. Basic checking of Group name - */ - public static function createGroup($gid) { - OC_Hook::emit("OC_Group", "pre_createGroup", array("run" => true, "gid" => $gid)); - - if (self::getManager()->createGroup($gid)) { - OC_Hook::emit("OC_User", "post_createGroup", array("gid" => $gid)); - return true; - } else { - return false; - } - } - - /** - * @brief delete a group - * @param string $gid gid of the group to delete - * @return bool - * - * Deletes a group and removes it from the group_user-table - */ - public static function deleteGroup($gid) { - // Prevent users from deleting group admin - if ($gid == "admin") { - return false; - } - - OC_Hook::emit("OC_Group", "pre_deleteGroup", array("run" => true, "gid" => $gid)); - - $group = self::getManager()->get($gid); - if ($group) { - if ($group->delete()) { - OC_Hook::emit("OC_User", "post_deleteGroup", array("gid" => $gid)); - return true; - } - } - return false; - } - - /** - * @brief is user in group? - * @param string $uid uid of the user - * @param string $gid gid of the group - * @return bool - * - * Checks whether the user is member of a group or not. - */ - public static function inGroup($uid, $gid) { - $group = self::getManager()->get($gid); - $user = self::$userManager->get($uid); - if ($group and $user) { - return $group->inGroup($user); - } - return false; - } - - /** - * @brief Add a user to a group - * @param string $uid Name of the user to add to group - * @param string $gid Name of the group in which add the user - * @return bool - * - * Adds a user to a group. - */ - public static function addToGroup($uid, $gid) { - $group = self::getManager()->get($gid); - $user = self::$userManager->get($uid); - if ($group and $user) { - OC_Hook::emit("OC_Group", "pre_addToGroup", array("run" => true, "uid" => $uid, "gid" => $gid)); - $group->addUser($user); - OC_Hook::emit("OC_User", "post_addToGroup", array("uid" => $uid, "gid" => $gid)); - return true; - } else { - return false; - } - } - - /** - * @brief Removes a user from a group - * @param string $uid Name of the user to remove from group - * @param string $gid Name of the group from which remove the user - * @return bool - * - * removes the user from a group. - */ - public static function removeFromGroup($uid, $gid) { - $group = self::getManager()->get($gid); - $user = self::$userManager->get($uid); - if ($group and $user) { - OC_Hook::emit("OC_Group", "pre_removeFromGroup", array("run" => true, "uid" => $uid, "gid" => $gid)); - $group->removeUser($user); - OC_Hook::emit("OC_User", "post_removeFromGroup", array("uid" => $uid, "gid" => $gid)); - return true; - } else { - return false; - } - } - - /** - * @brief Get all groups a user belongs to - * @param string $uid Name of the user - * @return array with group names - * - * This function fetches all groups a user belongs to. It does not check - * if the user exists at all. - */ - public static function getUserGroups($uid) { - $user = self::$userManager->get($uid); - if ($user) { - $groups = self::getManager()->getUserGroups($user); - $groupIds = array(); - foreach ($groups as $group) { - $groupIds[] = $group->getGID(); - } - return $groupIds; - } else { - return array(); - } - } - - /** - * @brief get a list of all groups - * @returns array with group names - * - * Returns a list with all groups - */ - public static function getGroups($search = '', $limit = null, $offset = null) { - $groups = self::getManager()->search($search, $limit, $offset); - $groupIds = array(); - foreach ($groups as $group) { - $groupIds[] = $group->getGID(); - } - return $groupIds; - } - - /** - * check if a group exists - * - * @param string $gid - * @return bool - */ - public static function groupExists($gid) { - return self::getManager()->groupExists($gid); - } - - /** - * @brief get a list of all users in a group - * @returns array with user ids - */ - public static function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { - $group = self::getManager()->get($gid); - if ($group) { - $users = $group->searchUsers($search, $limit, $offset); - $userIds = array(); - foreach ($users as $user) { - $userIds[] = $user->getUID(); - } - return $userIds; - } else { - return array(); - } - } - - /** - * @brief get a list of all users in several groups - * @param array $gids - * @param string $search - * @param int $limit - * @param int $offset - * @return array with user ids - */ - public static function usersInGroups($gids, $search = '', $limit = -1, $offset = 0) { - $users = array(); - foreach ($gids as $gid) { - // TODO Need to apply limits to groups as total - $users = array_merge(array_diff(self::usersInGroup($gid, $search, $limit, $offset), $users), $users); - } - return $users; - } - - /** - * @brief get a list of all display names in a group - * @returns array with display names (value) and user ids(key) - */ - public static function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) { - $group = self::getManager()->get($gid); - if ($group) { - $users = $group->searchDisplayName($search . $limit, $offset); - $displayNames = array(); - foreach ($users as $user) { - $displayNames[] = $user->getDisplayName(); - } - return $displayNames; - } else { - return array(); - } - } - - /** - * @brief get a list of all display names in several groups - * @param array $gids - * @param string $search - * @param int $limit - * @param int $offset - * @return array with display names (Key) user ids (value) - */ - public static function displayNamesInGroups($gids, $search = '', $limit = -1, $offset = 0) { - $displayNames = array(); - foreach ($gids as $gid) { - // TODO Need to apply limits to groups as total - $diff = array_diff( - self::displayNamesInGroup($gid, $search, $limit, $offset), - $displayNames - ); - if ($diff) { - $displayNames = array_merge($diff, $displayNames); - } - } - return $displayNames; - } -} diff --git a/lib/group/backend.php b/lib/group/backend.php deleted file mode 100644 index 2e17b5d0b7f..00000000000 --- a/lib/group/backend.php +++ /dev/null @@ -1,157 +0,0 @@ -. -* -*/ - -/** - * error code for functions not provided by the group backend - */ -define('OC_GROUP_BACKEND_NOT_IMPLEMENTED', -501); - -/** - * actions that user backends can define - */ -define('OC_GROUP_BACKEND_CREATE_GROUP', 0x00000001); -define('OC_GROUP_BACKEND_DELETE_GROUP', 0x00000010); -define('OC_GROUP_BACKEND_ADD_TO_GROUP', 0x00000100); -define('OC_GROUP_BACKEND_REMOVE_FROM_GOUP', 0x00001000); -define('OC_GROUP_BACKEND_GET_DISPLAYNAME', 0x00010000); - -/** - * Abstract base class for user management - */ -abstract class OC_Group_Backend implements OC_Group_Interface { - protected $possibleActions = array( - OC_GROUP_BACKEND_CREATE_GROUP => 'createGroup', - OC_GROUP_BACKEND_DELETE_GROUP => 'deleteGroup', - OC_GROUP_BACKEND_ADD_TO_GROUP => 'addToGroup', - OC_GROUP_BACKEND_REMOVE_FROM_GOUP => 'removeFromGroup', - OC_GROUP_BACKEND_GET_DISPLAYNAME => 'displayNamesInGroup', - ); - - /** - * @brief Get all supported actions - * @return int bitwise-or'ed actions - * - * Returns the supported actions as int to be - * compared with OC_USER_BACKEND_CREATE_USER etc. - */ - public function getSupportedActions() { - $actions = 0; - foreach($this->possibleActions AS $action => $methodName) { - if(method_exists($this, $methodName)) { - $actions |= $action; - } - } - - return $actions; - } - - /** - * @brief Check if backend implements actions - * @param int $actions bitwise-or'ed actions - * @return boolean - * - * Returns the supported actions as int to be - * compared with OC_GROUP_BACKEND_CREATE_GROUP etc. - */ - public function implementsActions($actions) { - return (bool)($this->getSupportedActions() & $actions); - } - - /** - * @brief is user in group? - * @param string $uid uid of the user - * @param string $gid gid of the group - * @return bool - * - * Checks whether the user is member of a group or not. - */ - public function inGroup($uid, $gid) { - return in_array($gid, $this->getUserGroups($uid)); - } - - /** - * @brief Get all groups a user belongs to - * @param string $uid Name of the user - * @return array with group names - * - * This function fetches all groups a user belongs to. It does not check - * if the user exists at all. - */ - public function getUserGroups($uid) { - return array(); - } - - /** - * @brief get a list of all groups - * @param string $search - * @param int $limit - * @param int $offset - * @return array with group names - * - * Returns a list with all groups - */ - - public function getGroups($search = '', $limit = -1, $offset = 0) { - return array(); - } - - /** - * check if a group exists - * @param string $gid - * @return bool - */ - public function groupExists($gid) { - return in_array($gid, $this->getGroups($gid, 1)); - } - - /** - * @brief get a list of all users in a group - * @param string $gid - * @param string $search - * @param int $limit - * @param int $offset - * @return array with user ids - */ - public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { - return array(); - } - - /** - * @brief get a list of all display names in a group - * @param string $gid - * @param string $search - * @param int $limit - * @param int $offset - * @return array with display names (value) and user ids (key) - */ - public function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) { - $displayNames = array(); - $users = $this->usersInGroup($gid, $search, $limit, $offset); - foreach ($users as $user) { - $displayNames[$user] = $user; - } - - return $displayNames; - } - -} diff --git a/lib/group/database.php b/lib/group/database.php deleted file mode 100644 index d0974685ff6..00000000000 --- a/lib/group/database.php +++ /dev/null @@ -1,239 +0,0 @@ -. - * - */ -/* - * - * The following SQL statement is just a help for developers and will not be - * executed! - * - * CREATE TABLE `groups` ( - * `gid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, - * PRIMARY KEY (`gid`) - * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - * - * CREATE TABLE `group_user` ( - * `gid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, - * `uid` varchar(64) COLLATE utf8_unicode_ci NOT NULL - * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - * - */ - -/** - * Class for group management in a SQL Database (e.g. MySQL, SQLite) - */ -class OC_Group_Database extends OC_Group_Backend { - - /** - * @brief Try to create a new group - * @param string $gid The name of the group to create - * @return bool - * - * Tries to create a new group. If the group name already exists, false will - * be returned. - */ - public function createGroup( $gid ) { - // Check for existence - $stmt = OC_DB::prepare( "SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` = ?" ); - $result = $stmt->execute( array( $gid )); - - if( $result->fetchRow() ) { - // Can not add an existing group - return false; - } - else{ - // Add group and exit - $stmt = OC_DB::prepare( "INSERT INTO `*PREFIX*groups` ( `gid` ) VALUES( ? )" ); - $result = $stmt->execute( array( $gid )); - - return $result ? true : false; - } - } - - /** - * @brief delete a group - * @param string $gid gid of the group to delete - * @return bool - * - * Deletes a group and removes it from the group_user-table - */ - public function deleteGroup( $gid ) { - // Delete the group - $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*groups` WHERE `gid` = ?" ); - $stmt->execute( array( $gid )); - - // Delete the group-user relation - $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*group_user` WHERE `gid` = ?" ); - $stmt->execute( array( $gid )); - - return true; - } - - /** - * @brief is user in group? - * @param string $uid uid of the user - * @param string $gid gid of the group - * @return bool - * - * Checks whether the user is member of a group or not. - */ - public function inGroup( $uid, $gid ) { - // check - $stmt = OC_DB::prepare( "SELECT `uid` FROM `*PREFIX*group_user` WHERE `gid` = ? AND `uid` = ?" ); - $result = $stmt->execute( array( $gid, $uid )); - - return $result->fetchRow() ? true : false; - } - - /** - * @brief Add a user to a group - * @param string $uid Name of the user to add to group - * @param string $gid Name of the group in which add the user - * @return bool - * - * Adds a user to a group. - */ - public function addToGroup( $uid, $gid ) { - // No duplicate entries! - if( !$this->inGroup( $uid, $gid )) { - $stmt = OC_DB::prepare( "INSERT INTO `*PREFIX*group_user` ( `uid`, `gid` ) VALUES( ?, ? )" ); - $stmt->execute( array( $uid, $gid )); - return true; - }else{ - return false; - } - } - - /** - * @brief Removes a user from a group - * @param string $uid Name of the user to remove from group - * @param string $gid Name of the group from which remove the user - * @return bool - * - * removes the user from a group. - */ - public function removeFromGroup( $uid, $gid ) { - $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*group_user` WHERE `uid` = ? AND `gid` = ?" ); - $stmt->execute( array( $uid, $gid )); - - return true; - } - - /** - * @brief Get all groups a user belongs to - * @param string $uid Name of the user - * @return array with group names - * - * This function fetches all groups a user belongs to. It does not check - * if the user exists at all. - */ - public function getUserGroups( $uid ) { - // No magic! - $stmt = OC_DB::prepare( "SELECT `gid` FROM `*PREFIX*group_user` WHERE `uid` = ?" ); - $result = $stmt->execute( array( $uid )); - - $groups = array(); - while( $row = $result->fetchRow()) { - $groups[] = $row["gid"]; - } - - return $groups; - } - - /** - * @brief get a list of all groups - * @param string $search - * @param int $limit - * @param int $offset - * @return array with group names - * - * Returns a list with all groups - */ - public function getGroups($search = '', $limit = null, $offset = null) { - $stmt = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` LIKE ?', $limit, $offset); - $result = $stmt->execute(array($search.'%')); - $groups = array(); - while ($row = $result->fetchRow()) { - $groups[] = $row['gid']; - } - return $groups; - } - - /** - * check if a group exists - * @param string $gid - * @return bool - */ - public function groupExists($gid) { - $query = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` = ?'); - $result = $query->execute(array($gid))->fetchOne(); - if ($result) { - return true; - } - return false; - } - - /** - * @brief get a list of all users in a group - * @param string $gid - * @param string $search - * @param int $limit - * @param int $offset - * @return array with user ids - */ - public function usersInGroup($gid, $search = '', $limit = null, $offset = null) { - $stmt = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*group_user` WHERE `gid` = ? AND `uid` LIKE ?', - $limit, - $offset); - $result = $stmt->execute(array($gid, $search.'%')); - $users = array(); - while ($row = $result->fetchRow()) { - $users[] = $row['uid']; - } - return $users; - } - - /** - * @brief get a list of all display names in a group - * @param string $gid - * @param string $search - * @param int $limit - * @param int $offset - * @return array with display names (value) and user ids (key) - */ - public function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) { - $displayNames = array(); - - $stmt = OC_DB::prepare('SELECT `*PREFIX*users`.`uid`, `*PREFIX*users`.`displayname`' - .' FROM `*PREFIX*users`' - .' INNER JOIN `*PREFIX*group_user` ON `*PREFIX*group_user`.`uid` = `*PREFIX*users`.`uid`' - .' WHERE `gid` = ? AND `*PREFIX*group_user`.`uid` LIKE ?', - $limit, - $offset); - $result = $stmt->execute(array($gid, $search.'%')); - $users = array(); - while ($row = $result->fetchRow()) { - $displayName = trim($row['displayname'], ' '); - $displayNames[$row['uid']] = empty($displayName) ? $row['uid'] : $displayName; - } - return $displayNames; - } -} diff --git a/lib/group/dummy.php b/lib/group/dummy.php deleted file mode 100644 index 9516fd52ff8..00000000000 --- a/lib/group/dummy.php +++ /dev/null @@ -1,160 +0,0 @@ -. -* -*/ - -/** - * dummy group backend, does not keep state, only for testing use - */ -class OC_Group_Dummy extends OC_Group_Backend { - private $groups=array(); - /** - * @brief Try to create a new group - * @param $gid The name of the group to create - * @returns true/false - * - * Trys to create a new group. If the group name already exists, false will - * be returned. - */ - public function createGroup($gid) { - if(!isset($this->groups[$gid])) { - $this->groups[$gid]=array(); - return true; - }else{ - return false; - } - } - - /** - * @brief delete a group - * @param $gid gid of the group to delete - * @returns true/false - * - * Deletes a group and removes it from the group_user-table - */ - public function deleteGroup($gid) { - if(isset($this->groups[$gid])) { - unset($this->groups[$gid]); - return true; - }else{ - return false; - } - } - - /** - * @brief is user in group? - * @param $uid uid of the user - * @param $gid gid of the group - * @returns true/false - * - * Checks whether the user is member of a group or not. - */ - public function inGroup($uid, $gid) { - if(isset($this->groups[$gid])) { - return (array_search($uid, $this->groups[$gid])!==false); - }else{ - return false; - } - } - - /** - * @brief Add a user to a group - * @param $uid Name of the user to add to group - * @param $gid Name of the group in which add the user - * @returns true/false - * - * Adds a user to a group. - */ - public function addToGroup($uid, $gid) { - if(isset($this->groups[$gid])) { - if(array_search($uid, $this->groups[$gid])===false) { - $this->groups[$gid][]=$uid; - return true; - }else{ - return false; - } - }else{ - return false; - } - } - - /** - * @brief Removes a user from a group - * @param $uid NameUSER of the user to remove from group - * @param $gid Name of the group from which remove the user - * @returns true/false - * - * removes the user from a group. - */ - public function removeFromGroup($uid, $gid) { - if(isset($this->groups[$gid])) { - if(($index=array_search($uid, $this->groups[$gid]))!==false) { - unset($this->groups[$gid][$index]); - }else{ - return false; - } - }else{ - return false; - } - } - - /** - * @brief Get all groups a user belongs to - * @param $uid Name of the user - * @returns array with group names - * - * This function fetches all groups a user belongs to. It does not check - * if the user exists at all. - */ - public function getUserGroups($uid) { - $groups=array(); - $allGroups=array_keys($this->groups); - foreach($allGroups as $group) { - if($this->inGroup($uid, $group)) { - $groups[]=$group; - } - } - return $groups; - } - - /** - * @brief get a list of all groups - * @returns array with group names - * - * Returns a list with all groups - */ - public function getGroups($search = '', $limit = -1, $offset = 0) { - return array_keys($this->groups); - } - - /** - * @brief get a list of all users in a group - * @returns array with user ids - */ - public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { - if(isset($this->groups[$gid])) { - return $this->groups[$gid]; - }else{ - return array(); - } - } - -} diff --git a/lib/group/example.php b/lib/group/example.php deleted file mode 100644 index 3519b9ed92f..00000000000 --- a/lib/group/example.php +++ /dev/null @@ -1,109 +0,0 @@ -. -* -*/ - -/** - * abstract reference class for group management - * this class should only be used as a reference for method signatures and their descriptions - */ -abstract class OC_Group_Example { - /** - * @brief Try to create a new group - * @param $gid The name of the group to create - * @returns true/false - * - * Trys to create a new group. If the group name already exists, false will - * be returned. - */ - abstract public static function createGroup($gid); - - /** - * @brief delete a group - * @param $gid gid of the group to delete - * @returns true/false - * - * Deletes a group and removes it from the group_user-table - */ - abstract public static function deleteGroup($gid); - - /** - * @brief is user in group? - * @param $uid uid of the user - * @param $gid gid of the group - * @returns true/false - * - * Checks whether the user is member of a group or not. - */ - abstract public static function inGroup($uid, $gid); - - /** - * @brief Add a user to a group - * @param $uid Name of the user to add to group - * @param $gid Name of the group in which add the user - * @returns true/false - * - * Adds a user to a group. - */ - abstract public static function addToGroup($uid, $gid); - - /** - * @brief Removes a user from a group - * @param $uid NameUSER of the user to remove from group - * @param $gid Name of the group from which remove the user - * @returns true/false - * - * removes the user from a group. - */ - abstract public static function removeFromGroup($uid, $gid); - - /** - * @brief Get all groups a user belongs to - * @param $uid Name of the user - * @returns array with group names - * - * This function fetches all groups a user belongs to. It does not check - * if the user exists at all. - */ - abstract public static function getUserGroups($uid); - - /** - * @brief get a list of all groups - * @returns array with group names - * - * Returns a list with all groups - */ - abstract public static function getGroups($search = '', $limit = -1, $offset = 0); - - /** - * check if a group exists - * @param string $gid - * @return bool - */ - abstract public function groupExists($gid); - - /** - * @brief get a list of all users in a group - * @returns array with user ids - */ - abstract public static function usersInGroup($gid, $search = '', $limit = -1, $offset = 0); - -} diff --git a/lib/group/group.php b/lib/group/group.php deleted file mode 100644 index bcd2419b309..00000000000 --- a/lib/group/group.php +++ /dev/null @@ -1,248 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Group; - -class Group { - /** - * @var string $id - */ - private $gid; - - /** - * @var \OC\User\User[] $users - */ - private $users; - - /** - * @var \OC_Group_Backend[] | \OC_Group_Database[] $backend - */ - private $backends; - - /** - * @var \OC\Hooks\PublicEmitter $emitter; - */ - private $emitter; - - /** - * @var \OC\User\Manager $userManager - */ - private $userManager; - - /** - * @param string $gid - * @param \OC_Group_Backend[] $backends - * @param \OC\User\Manager $userManager - * @param \OC\Hooks\PublicEmitter $emitter - */ - public function __construct($gid, $backends, $userManager, $emitter = null) { - $this->gid = $gid; - $this->backends = $backends; - $this->userManager = $userManager; - $this->emitter = $emitter; - } - - public function getGID() { - return $this->gid; - } - - /** - * get all users in the group - * - * @return \OC\User\User[] - */ - public function getUsers() { - if ($this->users) { - return $this->users; - } - - $userIds = array(); - foreach ($this->backends as $backend) { - $diff = array_diff( - $backend->usersInGroup($this->gid), - $userIds - ); - if ($diff) { - $userIds = array_merge($userIds, $diff); - } - } - - $this->users = $this->getVerifiedUsers($userIds); - return $this->users; - } - - /** - * check if a user is in the group - * - * @param \OC\User\User $user - * @return bool - */ - public function inGroup($user) { - foreach ($this->backends as $backend) { - if ($backend->inGroup($user->getUID(), $this->gid)) { - return true; - } - } - return false; - } - - /** - * add a user to the group - * - * @param \OC\User\User $user - */ - public function addUser($user) { - if ($this->inGroup($user)) { - return; - } - - if ($this->emitter) { - $this->emitter->emit('\OC\Group', 'preAddUser', array($this, $user)); - } - foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_ADD_TO_GROUP)) { - $backend->addToGroup($user->getUID(), $this->gid); - if ($this->users) { - $this->users[$user->getUID()] = $user; - } - if ($this->emitter) { - $this->emitter->emit('\OC\Group', 'postAddUser', array($this, $user)); - } - return; - } - } - } - - /** - * remove a user from the group - * - * @param \OC\User\User $user - */ - public function removeUser($user) { - $result = false; - if ($this->emitter) { - $this->emitter->emit('\OC\Group', 'preRemoveUser', array($this, $user)); - } - foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_REMOVE_FROM_GOUP) and $backend->inGroup($user->getUID(), $this->gid)) { - $backend->removeFromGroup($user->getUID(), $this->gid); - $result = true; - } - } - if ($result) { - if ($this->emitter) { - $this->emitter->emit('\OC\Group', 'postRemoveUser', array($this, $user)); - } - if ($this->users) { - foreach ($this->users as $index => $groupUser) { - if ($groupUser->getUID() === $user->getUID()) { - unset($this->users[$index]); - return; - } - } - } - } - } - - /** - * search for users in the group by userid - * - * @param string $search - * @param int $limit - * @param int $offset - * @return \OC\User\User[] - */ - public function searchUsers($search, $limit = null, $offset = null) { - $users = array(); - foreach ($this->backends as $backend) { - $userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset); - if (!is_null($limit)) { - $limit -= count($userIds); - } - if (!is_null($offset)) { - $offset -= count($userIds); - } - $users += $this->getVerifiedUsers($userIds); - if (!is_null($limit) and $limit <= 0) { - return array_values($users); - } - } - return array_values($users); - } - - /** - * search for users in the group by displayname - * - * @param string $search - * @param int $limit - * @param int $offset - * @return \OC\User\User[] - */ - public function searchDisplayName($search, $limit = null, $offset = null) { - foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_GET_DISPLAYNAME)) { - $userIds = array_keys($backend->displayNamesInGroup($this->gid, $search, $limit, $offset)); - } else { - $userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset); - } - if (!is_null($limit)) { - $limit -= count($userIds); - } - if (!is_null($offset)) { - $offset -= count($userIds); - } - $users = $this->getVerifiedUsers($userIds); - if (!is_null($limit) and $limit <= 0) { - return array_values($users); - } - } - return array_values($users); - } - - /** - * delete the group - * - * @return bool - */ - public function delete() { - $result = false; - if ($this->emitter) { - $this->emitter->emit('\OC\Group', 'preDelete', array($this)); - } - foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_DELETE_GROUP)) { - $result = true; - $backend->deleteGroup($this->gid); - } - } - if ($result and $this->emitter) { - $this->emitter->emit('\OC\Group', 'postDelete', array($this)); - } - return $result; - } - - /** - * @brief returns all the Users from an array that really exists - * @param $userIds an array containing user IDs - * @return an Array with the userId as Key and \OC\User\User as value - */ - private function getVerifiedUsers($userIds) { - if(!is_array($userIds)) { - return array(); - } - $users = array(); - foreach ($userIds as $userId) { - $user = $this->userManager->get($userId); - if(!is_null($user)) { - $users[$userId] = $user; - } - } - return $users; - } -} diff --git a/lib/group/interface.php b/lib/group/interface.php deleted file mode 100644 index 4ef3663837f..00000000000 --- a/lib/group/interface.php +++ /dev/null @@ -1,83 +0,0 @@ -. - * - */ - -interface OC_Group_Interface { - /** - * @brief Check if backend implements actions - * @param int $actions bitwise-or'ed actions - * @return boolean - * - * Returns the supported actions as int to be - * compared with OC_GROUP_BACKEND_CREATE_GROUP etc. - */ - public function implementsActions($actions); - - /** - * @brief is user in group? - * @param string $uid uid of the user - * @param string $gid gid of the group - * @return bool - * - * Checks whether the user is member of a group or not. - */ - public function inGroup($uid, $gid); - - /** - * @brief Get all groups a user belongs to - * @param string $uid Name of the user - * @return array with group names - * - * This function fetches all groups a user belongs to. It does not check - * if the user exists at all. - */ - public function getUserGroups($uid); - - /** - * @brief get a list of all groups - * @param string $search - * @param int $limit - * @param int $offset - * @return array with group names - * - * Returns a list with all groups - */ - public function getGroups($search = '', $limit = -1, $offset = 0); - - /** - * check if a group exists - * @param string $gid - * @return bool - */ - public function groupExists($gid); - - /** - * @brief get a list of all users in a group - * @param string $gid - * @param string $search - * @param int $limit - * @param int $offset - * @return array with user ids - */ - public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0); - -} diff --git a/lib/group/manager.php b/lib/group/manager.php deleted file mode 100644 index bf469d51d12..00000000000 --- a/lib/group/manager.php +++ /dev/null @@ -1,169 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Group; - -use OC\Hooks\PublicEmitter; - -/** - * Class Manager - * - * Hooks available in scope \OC\Group: - * - preAddUser(\OC\Group\Group $group, \OC\User\User $user) - * - postAddUser(\OC\Group\Group $group, \OC\User\User $user) - * - preRemoveUser(\OC\Group\Group $group, \OC\User\User $user) - * - postRemoveUser(\OC\Group\Group $group, \OC\User\User $user) - * - preDelete(\OC\Group\Group $group) - * - postDelete(\OC\Group\Group $group) - * - preCreate(string $groupId) - * - postCreate(\OC\Group\Group $group) - * - * @package OC\Group - */ -class Manager extends PublicEmitter { - /** - * @var \OC_Group_Backend[] | \OC_Group_Database[] $backends - */ - private $backends = array(); - - /** - * @var \OC\User\Manager $userManager - */ - private $userManager; - - /** - * @var \OC\Group\Group[] - */ - private $cachedGroups; - - /** - * @param \OC\User\Manager $userManager - */ - public function __construct($userManager) { - $this->userManager = $userManager; - $cache = & $this->cachedGroups; - $this->listen('\OC\Group', 'postDelete', function ($group) use (&$cache) { - /** - * @var \OC\Group\Group $group - */ - unset($cache[$group->getGID()]); - }); - } - - /** - * @param \OC_Group_Backend $backend - */ - public function addBackend($backend) { - $this->backends[] = $backend; - } - - public function clearBackends() { - $this->backends = array(); - $this->cachedGroups = array(); - } - - /** - * @param string $gid - * @return \OC\Group\Group - */ - public function get($gid) { - if (isset($this->cachedGroups[$gid])) { - return $this->cachedGroups[$gid]; - } - foreach ($this->backends as $backend) { - if ($backend->groupExists($gid)) { - return $this->getGroupObject($gid); - } - } - return null; - } - - protected function getGroupObject($gid) { - $backends = array(); - foreach ($this->backends as $backend) { - if ($backend->groupExists($gid)) { - $backends[] = $backend; - } - } - $this->cachedGroups[$gid] = new Group($gid, $backends, $this->userManager, $this); - return $this->cachedGroups[$gid]; - } - - /** - * @param string $gid - * @return bool - */ - public function groupExists($gid) { - return !is_null($this->get($gid)); - } - - /** - * @param string $gid - * @return \OC\Group\Group - */ - public function createGroup($gid) { - if (!$gid) { - return false; - } else if ($this->groupExists($gid)) { - return $this->get($gid); - } else { - $this->emit('\OC\Group', 'preCreate', array($gid)); - foreach ($this->backends as $backend) { - if ($backend->implementsActions(OC_GROUP_BACKEND_CREATE_GROUP)) { - $backend->createGroup($gid); - $group = $this->getGroupObject($gid); - $this->emit('\OC\Group', 'postCreate', array($group)); - return $group; - } - } - return null; - } - } - - /** - * @param string $search - * @param int $limit - * @param int $offset - * @return \OC\Group\Group[] - */ - public function search($search, $limit = null, $offset = null) { - $groups = array(); - foreach ($this->backends as $backend) { - $groupIds = $backend->getGroups($search, $limit, $offset); - if (!is_null($limit)) { - $limit -= count($groupIds); - } - if (!is_null($offset)) { - $offset -= count($groupIds); - } - foreach ($groupIds as $groupId) { - $groups[$groupId] = $this->getGroupObject($groupId); - } - if (!is_null($limit) and $limit <= 0) { - return array_values($groups); - } - } - return array_values($groups); - } - - /** - * @param \OC\User\User $user - * @return \OC\Group\Group[] - */ - public function getUserGroups($user) { - $groups = array(); - foreach ($this->backends as $backend) { - $groupIds = $backend->getUserGroups($user->getUID()); - foreach ($groupIds as $groupId) { - $groups[$groupId] = $this->getGroupObject($groupId); - } - } - return array_values($groups); - } -} diff --git a/lib/helper.php b/lib/helper.php deleted file mode 100644 index 66e7acb407a..00000000000 --- a/lib/helper.php +++ /dev/null @@ -1,934 +0,0 @@ -. - * - */ - -/** - * Collection of useful functions - */ -class OC_Helper { - private static $tmpFiles = array(); - private static $mimetypeIcons = array(); - private static $mimetypeDetector; - private static $templateManager; - - /** - * @brief Creates an url using a defined route - * @param $route - * @param array $parameters - * @return - * @internal param array $args with param=>value, will be appended to the returned url - * @returns the url - * - * Returns a url to the given app and file. - */ - public static function linkToRoute($route, $parameters = array()) { - $urlLinkTo = OC::getRouter()->generate($route, $parameters); - return $urlLinkTo; - } - - /** - * @brief Creates an url - * @param string $app app - * @param string $file file - * @param array $args array with param=>value, will be appended to the returned url - * The value of $args will be urlencoded - * @return string the url - * - * Returns a url to the given app and file. - */ - public static function linkTo( $app, $file, $args = array() ) { - if( $app != '' ) { - $app_path = OC_App::getAppPath($app); - // Check if the app is in the app folder - if ($app_path && file_exists($app_path . '/' . $file)) { - if (substr($file, -3) == 'php' || substr($file, -3) == 'css') { - $urlLinkTo = OC::$WEBROOT . '/index.php/apps/' . $app; - $urlLinkTo .= ($file != 'index.php') ? '/' . $file : ''; - } else { - $urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file; - } - } else { - $urlLinkTo = OC::$WEBROOT . '/' . $app . '/' . $file; - } - } else { - if (file_exists(OC::$SERVERROOT . '/core/' . $file)) { - $urlLinkTo = OC::$WEBROOT . '/core/' . $file; - } else { - $urlLinkTo = OC::$WEBROOT . '/' . $file; - } - } - - if ($args && $query = http_build_query($args, '', '&')) { - $urlLinkTo .= '?' . $query; - } - - return $urlLinkTo; - } - - /** - * @brief Creates an absolute url - * @param string $app app - * @param string $file file - * @param array $args array with param=>value, will be appended to the returned url - * The value of $args will be urlencoded - * @return string the url - * - * Returns a absolute url to the given app and file. - */ - public static function linkToAbsolute($app, $file, $args = array()) { - $urlLinkTo = self::linkTo($app, $file, $args); - return self::makeURLAbsolute($urlLinkTo); - } - - /** - * @brief Makes an $url absolute - * @param string $url the url - * @return string the absolute url - * - * Returns a absolute url to the given app and file. - */ - public static function makeURLAbsolute($url) { - return OC_Request::serverProtocol() . '://' . OC_Request::serverHost() . $url; - } - - /** - * @brief Creates an url for remote use - * @param string $service id - * @return string the url - * - * Returns a url to the given service. - */ - public static function linkToRemoteBase($service) { - return self::linkTo('', 'remote.php') . '/' . $service; - } - - /** - * @brief Creates an absolute url for remote use - * @param string $service id - * @param bool $add_slash - * @return string the url - * - * Returns a absolute url to the given service. - */ - public static function linkToRemote($service, $add_slash = true) { - return self::makeURLAbsolute(self::linkToRemoteBase($service)) - . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); - } - - /** - * @brief Creates an absolute url for public use - * @param string $service id - * @param bool $add_slash - * @return string the url - * - * Returns a absolute url to the given service. - */ - public static function linkToPublic($service, $add_slash = false) { - return self::linkToAbsolute('', 'public.php') . '?service=' . $service - . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); - } - - /** - * @brief Creates path to an image - * @param string $app app - * @param string $image image name - * @return string the url - * - * Returns the path to the image. - */ - public static function imagePath($app, $image) { - // Read the selected theme from the config file - $theme = OC_Util::getTheme(); - - // Check if the app is in the app folder - if (file_exists(OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$image")) { - return OC::$WEBROOT . "/themes/$theme/apps/$app/img/$image"; - } elseif (file_exists(OC_App::getAppPath($app) . "/img/$image")) { - return OC_App::getAppWebPath($app) . "/img/$image"; - } elseif (!empty($app) and file_exists(OC::$SERVERROOT . "/themes/$theme/$app/img/$image")) { - return OC::$WEBROOT . "/themes/$theme/$app/img/$image"; - } elseif (!empty($app) and file_exists(OC::$SERVERROOT . "/$app/img/$image")) { - return OC::$WEBROOT . "/$app/img/$image"; - } elseif (file_exists(OC::$SERVERROOT . "/themes/$theme/core/img/$image")) { - return OC::$WEBROOT . "/themes/$theme/core/img/$image"; - } elseif (file_exists(OC::$SERVERROOT . "/core/img/$image")) { - return OC::$WEBROOT . "/core/img/$image"; - } else { - throw new RuntimeException('image not found: image:' . $image . ' webroot:' . OC::$WEBROOT . ' serverroot:' . OC::$SERVERROOT); - } - } - - /** - * @brief get path to icon of file type - * @param string $mimetype mimetype - * @return string the url - * - * Returns the path to the image of this file type. - */ - public static function mimetypeIcon($mimetype) { - $alias = array( - 'application/xml' => 'code/xml', - 'application/msword' => 'x-office/document', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'x-office/document', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'x-office/document', - 'application/vnd.ms-word.document.macroEnabled.12' => 'x-office/document', - 'application/vnd.ms-word.template.macroEnabled.12' => 'x-office/document', - 'application/vnd.oasis.opendocument.text' => 'x-office/document', - 'application/vnd.oasis.opendocument.text-template' => 'x-office/document', - 'application/vnd.oasis.opendocument.text-web' => 'x-office/document', - 'application/vnd.oasis.opendocument.text-master' => 'x-office/document', - 'application/vnd.ms-powerpoint' => 'x-office/presentation', - 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation', - 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'x-office/presentation', - 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'x-office/presentation', - 'application/vnd.ms-powerpoint.addin.macroEnabled.12' => 'x-office/presentation', - 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' => 'x-office/presentation', - 'application/vnd.ms-powerpoint.template.macroEnabled.12' => 'x-office/presentation', - 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation', - 'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation', - 'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation', - 'application/vnd.ms-excel' => 'x-office/spreadsheet', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'x-office/spreadsheet', - 'application/vnd.ms-excel.sheet.macroEnabled.12' => 'x-office/spreadsheet', - 'application/vnd.ms-excel.template.macroEnabled.12' => 'x-office/spreadsheet', - 'application/vnd.ms-excel.addin.macroEnabled.12' => 'x-office/spreadsheet', - 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet', - 'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet', - 'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet', - ); - - if (isset($alias[$mimetype])) { - $mimetype = $alias[$mimetype]; - } - if (isset(self::$mimetypeIcons[$mimetype])) { - return self::$mimetypeIcons[$mimetype]; - } - // Replace slash and backslash with a minus - $icon = str_replace('/', '-', $mimetype); - $icon = str_replace('\\', '-', $icon); - - // Is it a dir? - if ($mimetype === 'dir') { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder.png'; - return OC::$WEBROOT . '/core/img/filetypes/folder.png'; - } - if ($mimetype === 'dir-shared') { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-shared.png'; - return OC::$WEBROOT . '/core/img/filetypes/folder-shared.png'; - } - if ($mimetype === 'dir-external') { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-external.png'; - return OC::$WEBROOT . '/core/img/filetypes/folder-external.png'; - } - - // Icon exists? - if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $icon . '.png')) { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png'; - return OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png'; - } - - // Try only the first part of the filetype - $mimePart = substr($icon, 0, strpos($icon, '-')); - if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $mimePart . '.png')) { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png'; - return OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png'; - } else { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/file.png'; - return OC::$WEBROOT . '/core/img/filetypes/file.png'; - } - } - - /** - * @brief get path to preview of file - * @param string $path path - * @return string the url - * - * Returns the path to the preview of the file. - */ - public static function previewIcon($path) { - return self::linkToRoute( 'core_ajax_preview', array('x' => 36, 'y' => 36, 'file' => urlencode($path) )); - } - - public static function publicPreviewIcon( $path, $token ) { - return self::linkToRoute( 'core_ajax_public_preview', array('x' => 36, 'y' => 36, 'file' => urlencode($path), 't' => $token)); - } - - /** - * @brief Make a human file size - * @param int $bytes file size in bytes - * @return string a human readable file size - * - * Makes 2048 to 2 kB. - */ - public static function humanFileSize($bytes) { - if ($bytes < 0) { - return "?"; - } - if ($bytes < 1024) { - return "$bytes B"; - } - $bytes = round($bytes / 1024, 1); - if ($bytes < 1024) { - return "$bytes kB"; - } - $bytes = round($bytes / 1024, 1); - if ($bytes < 1024) { - return "$bytes MB"; - } - $bytes = round($bytes / 1024, 1); - if ($bytes < 1024) { - return "$bytes GB"; - } - $bytes = round($bytes / 1024, 1); - if ($bytes < 1024) { - return "$bytes TB"; - } - - $bytes = round($bytes / 1024, 1); - return "$bytes PB"; - } - - /** - * @brief Make a computer file size - * @param string $str file size in a fancy format - * @return int a file size in bytes - * - * Makes 2kB to 2048. - * - * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418 - */ - public static function computerFileSize($str) { - $str = strtolower($str); - - $bytes_array = array( - 'b' => 1, - 'k' => 1024, - 'kb' => 1024, - 'mb' => 1024 * 1024, - 'm' => 1024 * 1024, - 'gb' => 1024 * 1024 * 1024, - 'g' => 1024 * 1024 * 1024, - 'tb' => 1024 * 1024 * 1024 * 1024, - 't' => 1024 * 1024 * 1024 * 1024, - 'pb' => 1024 * 1024 * 1024 * 1024 * 1024, - 'p' => 1024 * 1024 * 1024 * 1024 * 1024, - ); - - $bytes = floatval($str); - - if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) { - $bytes *= $bytes_array[$matches[1]]; - } - - $bytes = round($bytes, 2); - - return $bytes; - } - - /** - * @brief Recursive editing of file permissions - * @param string $path path to file or folder - * @param int $filemode unix style file permissions - * @return bool - */ - static function chmodr($path, $filemode) { - if (!is_dir($path)) - return chmod($path, $filemode); - $dh = opendir($path); - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if ($file != '.' && $file != '..') { - $fullpath = $path . '/' . $file; - if (is_link($fullpath)) - return false; - elseif (!is_dir($fullpath) && !@chmod($fullpath, $filemode)) - return false; elseif (!self::chmodr($fullpath, $filemode)) - return false; - } - } - closedir($dh); - } - if (@chmod($path, $filemode)) - return true; - else - return false; - } - - /** - * @brief Recursive copying of folders - * @param string $src source folder - * @param string $dest target folder - * - */ - static function copyr($src, $dest) { - if (is_dir($src)) { - if (!is_dir($dest)) { - mkdir($dest); - } - $files = scandir($src); - foreach ($files as $file) { - if ($file != "." && $file != "..") { - self::copyr("$src/$file", "$dest/$file"); - } - } - } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) { - copy($src, $dest); - } - } - - /** - * @brief Recursive deletion of folders - * @param string $dir path to the folder - * @return bool - */ - static function rmdirr($dir) { - if (is_dir($dir)) { - $files = scandir($dir); - foreach ($files as $file) { - if ($file != "." && $file != "..") { - self::rmdirr("$dir/$file"); - } - } - rmdir($dir); - } elseif (file_exists($dir)) { - unlink($dir); - } - if (file_exists($dir)) { - return false; - } else { - return true; - } - } - - /** - * @return \OC\Files\Type\Detection - */ - static public function getMimetypeDetector() { - if (!self::$mimetypeDetector) { - self::$mimetypeDetector = new \OC\Files\Type\Detection(); - self::$mimetypeDetector->registerTypeArray(include 'mimetypes.list.php'); - } - return self::$mimetypeDetector; - } - - /** - * @return \OC\Files\Type\TemplateManager - */ - static public function getFileTemplateManager() { - if (!self::$templateManager) { - self::$templateManager = new \OC\Files\Type\TemplateManager(); - } - return self::$templateManager; - } - - /** - * Try to guess the mimetype based on filename - * - * @param string $path - * @return string - */ - static public function getFileNameMimeType($path) { - return self::getMimetypeDetector()->detectPath($path); - } - - /** - * get the mimetype form a local file - * - * @param string $path - * @return string - * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead - */ - static function getMimeType($path) { - return self::getMimetypeDetector()->detect($path); - } - - /** - * get the mimetype form a data string - * - * @param string $data - * @return string - */ - static function getStringMimeType($data) { - return self::getMimetypeDetector()->detectString($data); - } - - /** - * @brief Checks $_REQUEST contains a var for the $s key. If so, returns the html-escaped value of this var; otherwise returns the default value provided by $d. - * @param string $s name of the var to escape, if set. - * @param string $d default value. - * @return string the print-safe value. - * - */ - - //FIXME: should also check for value validation (i.e. the email is an email). - public static function init_var($s, $d = "") { - $r = $d; - if (isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) { - $r = OC_Util::sanitizeHTML($_REQUEST[$s]); - } - - return $r; - } - - /** - * returns "checked"-attribute if request contains selected radio element - * OR if radio element is the default one -- maybe? - * - * @param string $s Name of radio-button element name - * @param string $v Value of current radio-button element - * @param string $d Value of default radio-button element - */ - public static function init_radio($s, $v, $d) { - if ((isset($_REQUEST[$s]) && $_REQUEST[$s] == $v) || (!isset($_REQUEST[$s]) && $v == $d)) - print "checked=\"checked\" "; - } - - /** - * detect if a given program is found in the search PATH - * - * @param $name - * @param bool $path - * @internal param string $program name - * @internal param string $optional search path, defaults to $PATH - * @return bool true if executable program found in path - */ - public static function canExecute($name, $path = false) { - // path defaults to PATH from environment if not set - if ($path === false) { - $path = getenv("PATH"); - } - // check method depends on operating system - if (!strncmp(PHP_OS, "WIN", 3)) { - // on Windows an appropriate COM or EXE file needs to exist - $exts = array(".exe", ".com"); - $check_fn = "file_exists"; - } else { - // anywhere else we look for an executable file of that name - $exts = array(""); - $check_fn = "is_executable"; - } - // Default check will be done with $path directories : - $dirs = explode(PATH_SEPARATOR, $path); - // WARNING : We have to check if open_basedir is enabled : - $obd = ini_get('open_basedir'); - if ($obd != "none") { - $obd_values = explode(PATH_SEPARATOR, $obd); - if (count($obd_values) > 0 and $obd_values[0]) { - // open_basedir is in effect ! - // We need to check if the program is in one of these dirs : - $dirs = $obd_values; - } - } - foreach ($dirs as $dir) { - foreach ($exts as $ext) { - if ($check_fn("$dir/$name" . $ext)) - return true; - } - } - return false; - } - - /** - * copy the contents of one stream to another - * - * @param resource $source - * @param resource $target - * @return int the number of bytes copied - */ - public static function streamCopy($source, $target) { - if (!$source or !$target) { - return false; - } - $result = true; - $count = 0; - while (!feof($source)) { - if (($c = fwrite($target, fread($source, 8192))) === false) { - $result = false; - } else { - $count += $c; - } - } - return array($count, $result); - } - - /** - * create a temporary file with an unique filename - * - * @param string $postfix - * @return string - * - * temporary files are automatically cleaned up after the script is finished - */ - public static function tmpFile($postfix = '') { - $file = get_temp_dir() . '/' . md5(time() . rand()) . $postfix; - $fh = fopen($file, 'w'); - fclose($fh); - self::$tmpFiles[] = $file; - return $file; - } - - /** - * move a file to oc-noclean temp dir - * - * @param string $filename - * @return mixed - * - */ - public static function moveToNoClean($filename = '') { - if ($filename == '') { - return false; - } - $tmpDirNoClean = get_temp_dir() . '/oc-noclean/'; - if (!file_exists($tmpDirNoClean) || !is_dir($tmpDirNoClean)) { - if (file_exists($tmpDirNoClean)) { - unlink($tmpDirNoClean); - } - mkdir($tmpDirNoClean); - } - $newname = $tmpDirNoClean . basename($filename); - if (rename($filename, $newname)) { - return $newname; - } else { - return false; - } - } - - /** - * create a temporary folder with an unique filename - * - * @return string - * - * temporary files are automatically cleaned up after the script is finished - */ - public static function tmpFolder() { - $path = get_temp_dir() . '/' . md5(time() . rand()); - mkdir($path); - self::$tmpFiles[] = $path; - return $path . '/'; - } - - /** - * remove all files created by self::tmpFile - */ - public static function cleanTmp() { - $leftoversFile = get_temp_dir() . '/oc-not-deleted'; - if (file_exists($leftoversFile)) { - $leftovers = file($leftoversFile); - foreach ($leftovers as $file) { - self::rmdirr($file); - } - unlink($leftoversFile); - } - - foreach (self::$tmpFiles as $file) { - if (file_exists($file)) { - if (!self::rmdirr($file)) { - file_put_contents($leftoversFile, $file . "\n", FILE_APPEND); - } - } - } - } - - /** - * remove all files in PHP /oc-noclean temp dir - */ - public static function cleanTmpNoClean() { - $tmpDirNoCleanName=get_temp_dir() . '/oc-noclean/'; - if(file_exists($tmpDirNoCleanName) && is_dir($tmpDirNoCleanName)) { - $files=scandir($tmpDirNoCleanName); - foreach($files as $file) { - $fileName = $tmpDirNoCleanName . $file; - if (!\OC\Files\Filesystem::isIgnoredDir($file) && filemtime($fileName) + 600 < time()) { - unlink($fileName); - } - } - // if oc-noclean is empty delete it - $isTmpDirNoCleanEmpty = true; - $tmpDirNoClean = opendir($tmpDirNoCleanName); - if(is_resource($tmpDirNoClean)) { - while (false !== ($file = readdir($tmpDirNoClean))) { - if (!\OC\Files\Filesystem::isIgnoredDir($file)) { - $isTmpDirNoCleanEmpty = false; - } - } - } - if ($isTmpDirNoCleanEmpty) { - rmdir($tmpDirNoCleanName); - } - } - } - - /** - * Adds a suffix to the name in case the file exists - * - * @param $path - * @param $filename - * @return string - */ - public static function buildNotExistingFileName($path, $filename) { - $view = \OC\Files\Filesystem::getView(); - return self::buildNotExistingFileNameForView($path, $filename, $view); - } - - /** - * Adds a suffix to the name in case the file exists - * - * @param $path - * @param $filename - * @return string - */ - public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) { - if ($path === '/') { - $path = ''; - } - if ($pos = strrpos($filename, '.')) { - $name = substr($filename, 0, $pos); - $ext = substr($filename, $pos); - } else { - $name = $filename; - $ext = ''; - } - - $newpath = $path . '/' . $filename; - if ($view->file_exists($newpath)) { - if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) { - //Replace the last "(number)" with "(number+1)" - $last_match = count($matches[0]) - 1; - $counter = $matches[1][$last_match][0] + 1; - $offset = $matches[0][$last_match][1]; - $match_length = strlen($matches[0][$last_match][0]); - } else { - $counter = 2; - $offset = false; - } - do { - if ($offset) { - //Replace the last "(number)" with "(number+1)" - $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length); - } else { - $newname = $name . ' (' . $counter . ')'; - } - $newpath = $path . '/' . $newname . $ext; - $counter++; - } while ($view->file_exists($newpath)); - } - - return $newpath; - } - - /** - * @brief Checks if $sub is a subdirectory of $parent - * - * @param string $sub - * @param string $parent - * @return bool - */ - public static function issubdirectory($sub, $parent) { - if (strpos(realpath($sub), realpath($parent)) === 0) { - return true; - } - return false; - } - - /** - * @brief Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. - * - * @param array $input The array to work on - * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 - * @return array - * - * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. - * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715 - * - */ - public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') { - $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER; - $ret = array(); - foreach ($input as $k => $v) { - $ret[mb_convert_case($k, $case, $encoding)] = $v; - } - return $ret; - } - - /** - * @brief replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement. - * - * @param $string - * @param string $replacement The replacement string. - * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string. - * @param int $length Length of the part to be replaced - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 - * @internal param string $input The input string. .Opposite to the PHP build-in function does not accept an array. - * @return string - */ - public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') { - $start = intval($start); - $length = intval($length); - $string = mb_substr($string, 0, $start, $encoding) . - $replacement . - mb_substr($string, $start + $length, mb_strlen($string, 'UTF-8') - $start, $encoding); - - return $string; - } - - /** - * @brief Replace all occurrences of the search string with the replacement string - * - * @param string $search The value being searched for, otherwise known as the needle. - * @param string $replace The replacement - * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack. - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 - * @param int $count If passed, this will be set to the number of replacements performed. - * @return string - * - */ - public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) { - $offset = -1; - $length = mb_strlen($search, $encoding); - while (($i = mb_strrpos($subject, $search, $offset, $encoding)) !== false) { - $subject = OC_Helper::mb_substr_replace($subject, $replace, $i, $length); - $offset = $i - mb_strlen($subject, $encoding); - $count++; - } - return $subject; - } - - /** - * @brief performs a search in a nested array - * @param array $haystack the array to be searched - * @param string $needle the search string - * @param string $index optional, only search this key name - * @return mixed the key of the matching field, otherwise false - * - * performs a search in a nested array - * - * taken from http://www.php.net/manual/en/function.array-search.php#97645 - */ - public static function recursiveArraySearch($haystack, $needle, $index = null) { - $aIt = new RecursiveArrayIterator($haystack); - $it = new RecursiveIteratorIterator($aIt); - - while ($it->valid()) { - if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) { - return $aIt->key(); - } - - $it->next(); - } - - return false; - } - - /** - * Shortens str to maxlen by replacing characters in the middle with '...', eg. - * ellipsis('a very long string with lots of useless info to make a better example', 14) becomes 'a very ...example' - * - * @param string $str the string - * @param string $maxlen the maximum length of the result - * @return string with at most maxlen characters - */ - public static function ellipsis($str, $maxlen) { - if (strlen($str) > $maxlen) { - $characters = floor($maxlen / 2); - return substr($str, 0, $characters) . '...' . substr($str, -1 * $characters); - } - return $str; - } - - /** - * @brief calculates the maximum upload size respecting system settings, free space and user quota - * - * @param $dir the current folder where the user currently operates - * @return number of bytes representing - */ - public static function maxUploadFilesize($dir) { - $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); - $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); - $freeSpace = \OC\Files\Filesystem::free_space($dir); - if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { - $maxUploadFilesize = \OC\Files\SPACE_UNLIMITED; - } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { - $maxUploadFilesize = max($upload_max_filesize, $post_max_size); //only the non 0 value counts - } else { - $maxUploadFilesize = min($upload_max_filesize, $post_max_size); - } - - if ($freeSpace !== \OC\Files\SPACE_UNKNOWN) { - $freeSpace = max($freeSpace, 0); - - return min($maxUploadFilesize, $freeSpace); - } else { - return $maxUploadFilesize; - } - } - - /** - * Checks if a function is available - * - * @param string $function_name - * @return bool - */ - public static function is_function_enabled($function_name) { - if (!function_exists($function_name)) { - return false; - } - $disabled = explode(', ', ini_get('disable_functions')); - if (in_array($function_name, $disabled)) { - return false; - } - $disabled = explode(', ', ini_get('suhosin.executor.func.blacklist')); - if (in_array($function_name, $disabled)) { - return false; - } - return true; - } - - /** - * Calculate the disc space for the given path - * - * @param string $path - * @return array - */ - public static function getStorageInfo($path) { - $rootInfo = \OC\Files\Filesystem::getFileInfo($path); - $used = $rootInfo['size']; - if ($used < 0) { - $used = 0; - } - $free = \OC\Files\Filesystem::free_space($path); - if ($free >= 0) { - $total = $free + $used; - } else { - $total = $free; //either unknown or unlimited - } - if ($total > 0) { - // prevent division by zero or error codes (negative values) - $relative = round(($used / $total) * 10000) / 100; - } else { - $relative = 0; - } - - return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); - } -} diff --git a/lib/hintexception.php b/lib/hintexception.php deleted file mode 100644 index 3934ae2a4c2..00000000000 --- a/lib/hintexception.php +++ /dev/null @@ -1,27 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC; - -class HintException extends \Exception { - - private $hint; - - public function __construct($message, $hint = '', $code = 0, Exception $previous = null) { - $this->hint = $hint; - parent::__construct($message, $code, $previous); - } - - public function __toString() { - return __CLASS__ . ": [{$this->code}]: {$this->message} ({$this->hint})\n"; - } - - public function getHint() { - return $this->hint; - } -} diff --git a/lib/hook.php b/lib/hook.php deleted file mode 100644 index 8516cf0dcff..00000000000 --- a/lib/hook.php +++ /dev/null @@ -1,100 +0,0 @@ - $slotclass, - "name" => $slotname - ); - - // No chance for failure ;-) - return true; - } - - /** - * @brief emits a signal - * @param string $signalclass class name of emitter - * @param string $signalname name of signal - * @param array $params defautl: array() array with additional data - * @return bool, true if slots exists or false if not - * - * Emits a signal. To get data from the slot use references! - * - * TODO: write example - */ - static public function emit( $signalclass, $signalname, $params = array()) { - - // Return false if no hook handlers are listening to this - // emitting class - if( !array_key_exists( $signalclass, self::$registered )) { - return false; - } - - // Return false if no hook handlers are listening to this - // emitting method - if( !array_key_exists( $signalname, self::$registered[$signalclass] )) { - return false; - } - - // Call all slots - foreach( self::$registered[$signalclass][$signalname] as $i ) { - try { - call_user_func( array( $i["class"], $i["name"] ), $params ); - } catch (Exception $e){ - OC_Log::write('hook', - 'error while running hook (' . $i["class"] . '::' . $i["name"] . '): '.$e->getMessage(), - OC_Log::ERROR); - } - } - - // return true - return true; - } - - /** - * clear hooks - * @param string $signalclass - * @param string $signalname - */ - static public function clear($signalclass='', $signalname='') { - if($signalclass) { - if($signalname) { - self::$registered[$signalclass][$signalname]=array(); - }else{ - self::$registered[$signalclass]=array(); - } - }else{ - self::$registered=array(); - } - } -} diff --git a/lib/hooks/basicemitter.php b/lib/hooks/basicemitter.php deleted file mode 100644 index 9ffe1af2314..00000000000 --- a/lib/hooks/basicemitter.php +++ /dev/null @@ -1,89 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Hooks; - -abstract class BasicEmitter implements Emitter { - - /** - * @var (callable[])[] $listeners - */ - protected $listeners = array(); - - /** - * @param string $scope - * @param string $method - * @param callable $callback - */ - public function listen($scope, $method, $callback) { - $eventName = $scope . '::' . $method; - if (!isset($this->listeners[$eventName])) { - $this->listeners[$eventName] = array(); - } - if (array_search($callback, $this->listeners[$eventName]) === false) { - $this->listeners[$eventName][] = $callback; - } - } - - /** - * @param string $scope optional - * @param string $method optional - * @param callable $callback optional - */ - public function removeListener($scope = null, $method = null, $callback = null) { - $names = array(); - $allNames = array_keys($this->listeners); - if ($scope and $method) { - $name = $scope . '::' . $method; - if (isset($this->listeners[$name])) { - $names[] = $name; - } - } elseif ($scope) { - foreach ($allNames as $name) { - $parts = explode('::', $name, 2); - if ($parts[0] == $scope) { - $names[] = $name; - } - } - } elseif ($method) { - foreach ($allNames as $name) { - $parts = explode('::', $name, 2); - if ($parts[1] == $method) { - $names[] = $name; - } - } - } else { - $names = $allNames; - } - - foreach ($names as $name) { - if ($callback) { - $index = array_search($callback, $this->listeners[$name]); - if ($index !== false) { - unset($this->listeners[$name][$index]); - } - } else { - $this->listeners[$name] = array(); - } - } - } - - /** - * @param string $scope - * @param string $method - * @param array $arguments optional - */ - protected function emit($scope, $method, $arguments = array()) { - $eventName = $scope . '::' . $method; - if (isset($this->listeners[$eventName])) { - foreach ($this->listeners[$eventName] as $callback) { - call_user_func_array($callback, $arguments); - } - } - } -} diff --git a/lib/hooks/emitter.php b/lib/hooks/emitter.php deleted file mode 100644 index 8e9074bad67..00000000000 --- a/lib/hooks/emitter.php +++ /dev/null @@ -1,32 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Hooks; - -/** - * Class Emitter - * - * interface for all classes that are able to emit events - * - * @package OC\Hooks - */ -interface Emitter { - /** - * @param string $scope - * @param string $method - * @param callable $callback - */ - public function listen($scope, $method, $callback); - - /** - * @param string $scope optional - * @param string $method optional - * @param callable $callback optional - */ - public function removeListener($scope = null, $method = null, $callback = null); -} diff --git a/lib/hooks/forwardingemitter.php b/lib/hooks/forwardingemitter.php deleted file mode 100644 index 1aacc4012e0..00000000000 --- a/lib/hooks/forwardingemitter.php +++ /dev/null @@ -1,50 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Hooks; - -/** - * Class ForwardingEmitter - * - * allows forwarding all listen calls to other emitters - * - * @package OC\Hooks - */ -abstract class ForwardingEmitter extends BasicEmitter { - /** - * @var \OC\Hooks\Emitter[] array - */ - private $forwardEmitters = array(); - - /** - * @param string $scope - * @param string $method - * @param callable $callback - */ - public function listen($scope, $method, $callback) { - parent::listen($scope, $method, $callback); - foreach ($this->forwardEmitters as $emitter) { - $emitter->listen($scope, $method, $callback); - } - } - - /** - * @param \OC\Hooks\Emitter $emitter - */ - protected function forward($emitter) { - $this->forwardEmitters[] = $emitter; - - //forward all previously connected hooks - foreach ($this->listeners as $key => $listeners) { - list($scope, $method) = explode('::', $key, 2); - foreach ($listeners as $listener) { - $emitter->listen($scope, $method, $listener); - } - } - } -} diff --git a/lib/hooks/legacyemitter.php b/lib/hooks/legacyemitter.php deleted file mode 100644 index a2d16ace9a7..00000000000 --- a/lib/hooks/legacyemitter.php +++ /dev/null @@ -1,16 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Hooks; - -abstract class LegacyEmitter extends BasicEmitter { - protected function emit($scope, $method, $arguments = array()) { - \OC_Hook::emit($scope, $method, $arguments); - parent::emit($scope, $method, $arguments); - } -} diff --git a/lib/hooks/publicemitter.php b/lib/hooks/publicemitter.php deleted file mode 100644 index e2371713ac3..00000000000 --- a/lib/hooks/publicemitter.php +++ /dev/null @@ -1,20 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Hooks; - -class PublicEmitter extends BasicEmitter { - /** - * @param string $scope - * @param string $method - * @param array $arguments optional - */ - public function emit($scope, $method, $arguments = array()) { - parent::emit($scope, $method, $arguments); - } -} diff --git a/lib/image.php b/lib/image.php deleted file mode 100644 index 7761a3c7737..00000000000 --- a/lib/image.php +++ /dev/null @@ -1,1020 +0,0 @@ - -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 library. If not, see . -* -*/ -/** - * Class for basic image manipulation - */ -class OC_Image { - protected $resource = false; // tmp resource. - protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident. - protected $mimeType = "image/png"; // Default to png - protected $bitDepth = 24; - protected $filePath = null; - - private $fileInfo; - - /** - * @brief Get mime type for an image file. - * @param $filepath The path to a local image file. - * @returns string The mime type if the it could be determined, otherwise an empty string. - */ - static public function getMimeTypeForFile($filePath) { - // exif_imagetype throws "read error!" if file is less than 12 byte - if (filesize($filePath) > 11) { - $imageType = exif_imagetype($filePath); - } - else { - $imageType = false; - } - return $imageType ? image_type_to_mime_type($imageType) : ''; - } - - /** - * @brief Constructor. - * @param $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function. - * @returns bool False on error - */ - public function __construct($imageRef = null) { - //OC_Log::write('core',__METHOD__.'(): start', OC_Log::DEBUG); - if(!extension_loaded('gd') || !function_exists('gd_info')) { - OC_Log::write('core', __METHOD__.'(): GD module not installed', OC_Log::ERROR); - return false; - } - - if (\OC_Util::fileInfoLoaded()) { - $this->fileInfo = new finfo(FILEINFO_MIME_TYPE); - } - - if(!is_null($imageRef)) { - $this->load($imageRef); - } - } - - /** - * @brief Determine whether the object contains an image resource. - * @returns bool - */ - public function valid() { // apparently you can't name a method 'empty'... - return is_resource($this->resource); - } - - /** - * @brief Returns the MIME type of the image or an empty string if no image is loaded. - * @returns int - */ - public function mimeType() { - return $this->valid() ? $this->mimeType : ''; - } - - /** - * @brief Returns the width of the image or -1 if no image is loaded. - * @returns int - */ - public function width() { - return $this->valid() ? imagesx($this->resource) : -1; - } - - /** - * @brief Returns the height of the image or -1 if no image is loaded. - * @returns int - */ - public function height() { - return $this->valid() ? imagesy($this->resource) : -1; - } - - /** - * @brief Returns the width when the image orientation is top-left. - * @returns int - */ - public function widthTopLeft() { - $o = $this->getOrientation(); - OC_Log::write('core', 'OC_Image->widthTopLeft() Orientation: '.$o, OC_Log::DEBUG); - switch($o) { - case -1: - case 1: - case 2: // Not tested - case 3: - case 4: // Not tested - return $this->width(); - break; - case 5: // Not tested - case 6: - case 7: // Not tested - case 8: - return $this->height(); - break; - } - return $this->width(); - } - - /** - * @brief Returns the height when the image orientation is top-left. - * @returns int - */ - public function heightTopLeft() { - $o = $this->getOrientation(); - OC_Log::write('core', 'OC_Image->heightTopLeft() Orientation: '.$o, OC_Log::DEBUG); - switch($o) { - case -1: - case 1: - case 2: // Not tested - case 3: - case 4: // Not tested - return $this->height(); - break; - case 5: // Not tested - case 6: - case 7: // Not tested - case 8: - return $this->width(); - break; - } - return $this->height(); - } - - /** - * @brief Outputs the image. - * @returns bool - */ - public function show() { - header('Content-Type: '.$this->mimeType()); - return $this->_output(); - } - - /** - * @brief Saves the image. - * @returns bool - */ - - public function save($filePath=null) { - if($filePath === null && $this->filePath === null) { - OC_Log::write('core', __METHOD__.'(): called with no path.', OC_Log::ERROR); - return false; - } elseif($filePath === null && $this->filePath !== null) { - $filePath = $this->filePath; - } - return $this->_output($filePath); - } - - /** - * @brief Outputs/saves the image. - */ - private function _output($filePath=null) { - if($filePath) { - if (!file_exists(dirname($filePath))) - mkdir(dirname($filePath), 0777, true); - if(!is_writable(dirname($filePath))) { - OC_Log::write('core', - __METHOD__.'(): Directory \''.dirname($filePath).'\' is not writable.', - OC_Log::ERROR); - return false; - } elseif(is_writable(dirname($filePath)) && file_exists($filePath) && !is_writable($filePath)) { - OC_Log::write('core', __METHOD__.'(): File \''.$filePath.'\' is not writable.', OC_Log::ERROR); - return false; - } - } - if (!$this->valid()) { - return false; - } - - $retVal = false; - switch($this->imageType) { - case IMAGETYPE_GIF: - $retVal = imagegif($this->resource, $filePath); - break; - case IMAGETYPE_JPEG: - $retVal = imagejpeg($this->resource, $filePath); - break; - case IMAGETYPE_PNG: - $retVal = imagepng($this->resource, $filePath); - break; - case IMAGETYPE_XBM: - $retVal = imagexbm($this->resource, $filePath); - break; - case IMAGETYPE_WBMP: - $retVal = imagewbmp($this->resource, $filePath); - break; - case IMAGETYPE_BMP: - $retVal = imagebmp($this->resource, $filePath, $this->bitDepth); - break; - default: - $retVal = imagepng($this->resource, $filePath); - } - return $retVal; - } - - /** - * @brief Prints the image when called as $image(). - */ - public function __invoke() { - return $this->show(); - } - - /** - * @returns Returns the image resource in any. - */ - public function resource() { - return $this->resource; - } - - /** - * @returns Returns the raw image data. - */ - function data() { - ob_start(); - switch ($this->mimeType) { - case "image/png": - $res = imagepng($this->resource); - break; - case "image/jpeg": - $res = imagejpeg($this->resource); - break; - case "image/gif": - $res = imagegif($this->resource); - break; - default: - $res = imagepng($this->resource); - OC_Log::write('core', 'OC_Image->data. Couldn\'t guess mimetype, defaulting to png', OC_Log::INFO); - break; - } - if (!$res) { - OC_Log::write('core', 'OC_Image->data. Error getting image data.', OC_Log::ERROR); - } - return ob_get_clean(); - } - - /** - * @returns Returns a base64 encoded string suitable for embedding in a VCard. - */ - function __toString() { - return base64_encode($this->data()); - } - - /** - * (I'm open for suggestions on better method name ;) - * @brief Get the orientation based on EXIF data. - * @returns The orientation or -1 if no EXIF data is available. - */ - public function getOrientation() { - if(!is_callable('exif_read_data')) { - OC_Log::write('core', 'OC_Image->fixOrientation() Exif module not enabled.', OC_Log::DEBUG); - return -1; - } - if(!$this->valid()) { - OC_Log::write('core', 'OC_Image->fixOrientation() No image loaded.', OC_Log::DEBUG); - return -1; - } - if(is_null($this->filePath) || !is_readable($this->filePath)) { - OC_Log::write('core', 'OC_Image->fixOrientation() No readable file path set.', OC_Log::DEBUG); - return -1; - } - $exif = @exif_read_data($this->filePath, 'IFD0'); - if(!$exif) { - return -1; - } - if(!isset($exif['Orientation'])) { - return -1; - } - return $exif['Orientation']; - } - - /** - * (I'm open for suggestions on better method name ;) - * @brief Fixes orientation based on EXIF data. - * @returns bool. - */ - public function fixOrientation() { - $o = $this->getOrientation(); - OC_Log::write('core', 'OC_Image->fixOrientation() Orientation: '.$o, OC_Log::DEBUG); - $rotate = 0; - $flip = false; - switch($o) { - case -1: - return false; //Nothing to fix - break; - case 1: - $rotate = 0; - $flip = false; - break; - case 2: // Not tested - $rotate = 0; - $flip = true; - break; - case 3: - $rotate = 180; - $flip = false; - break; - case 4: // Not tested - $rotate = 180; - $flip = true; - break; - case 5: // Not tested - $rotate = 90; - $flip = true; - break; - case 6: - //$rotate = 90; - $rotate = 270; - $flip = false; - break; - case 7: // Not tested - $rotate = 270; - $flip = true; - break; - case 8: - $rotate = 90; - $flip = false; - break; - } - if($rotate) { - $res = imagerotate($this->resource, $rotate, -1); - if($res) { - if(imagealphablending($res, true)) { - if(imagesavealpha($res, true)) { - imagedestroy($this->resource); - $this->resource = $res; - return true; - } else { - OC_Log::write('core', 'OC_Image->fixOrientation() Error during alphasaving.', OC_Log::DEBUG); - return false; - } - } else { - OC_Log::write('core', 'OC_Image->fixOrientation() Error during alphablending.', OC_Log::DEBUG); - return false; - } - } else { - OC_Log::write('core', 'OC_Image->fixOrientation() Error during oriention fixing.', OC_Log::DEBUG); - return false; - } - } - } - - /** - * @brief Loads an image from a local file, a base64 encoded string or a resource created by an imagecreate* function. - * @param $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function or a file resource (file handle ). - * @returns An image resource or false on error - */ - public function load($imageRef) { - if(is_resource($imageRef)) { - if(get_resource_type($imageRef) == 'gd') { - $this->resource = $imageRef; - return $this->resource; - } elseif(in_array(get_resource_type($imageRef), array('file', 'stream'))) { - return $this->loadFromFileHandle($imageRef); - } - } elseif($this->loadFromFile($imageRef) !== false) { - return $this->resource; - } elseif($this->loadFromBase64($imageRef) !== false) { - return $this->resource; - } elseif($this->loadFromData($imageRef) !== false) { - return $this->resource; - } else { - OC_Log::write('core', __METHOD__.'(): couldn\'t load anything. Giving up!', OC_Log::DEBUG); - return false; - } - } - - /** - * @brief Loads an image from an open file handle. - * It is the responsibility of the caller to position the pointer at the correct place and to close the handle again. - * @param $handle - * @returns An image resource or false on error - */ - public function loadFromFileHandle($handle) { - OC_Log::write('core', __METHOD__.'(): Trying', OC_Log::DEBUG); - $contents = stream_get_contents($handle); - if($this->loadFromData($contents)) { - return $this->resource; - } - } - - /** - * @brief Loads an image from a local file. - * @param $imageref The path to a local file. - * @returns An image resource or false on error - */ - public function loadFromFile($imagePath=false) { - // exif_imagetype throws "read error!" if file is less than 12 byte - if(!@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) { - // Debug output disabled because this method is tried before loadFromBase64? - OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: '.$imagePath, OC_Log::DEBUG); - return false; - } - $iType = exif_imagetype($imagePath); - switch ($iType) { - case IMAGETYPE_GIF: - if (imagetypes() & IMG_GIF) { - $this->resource = imagecreatefromgif($imagePath); - } else { - OC_Log::write('core', - 'OC_Image->loadFromFile, GIF images not supported: '.$imagePath, - OC_Log::DEBUG); - } - break; - case IMAGETYPE_JPEG: - if (imagetypes() & IMG_JPG) { - $this->resource = imagecreatefromjpeg($imagePath); - } else { - OC_Log::write('core', - 'OC_Image->loadFromFile, JPG images not supported: '.$imagePath, - OC_Log::DEBUG); - } - break; - case IMAGETYPE_PNG: - if (imagetypes() & IMG_PNG) { - $this->resource = imagecreatefrompng($imagePath); - } else { - OC_Log::write('core', - 'OC_Image->loadFromFile, PNG images not supported: '.$imagePath, - OC_Log::DEBUG); - } - break; - case IMAGETYPE_XBM: - if (imagetypes() & IMG_XPM) { - $this->resource = imagecreatefromxbm($imagePath); - } else { - OC_Log::write('core', - 'OC_Image->loadFromFile, XBM/XPM images not supported: '.$imagePath, - OC_Log::DEBUG); - } - break; - case IMAGETYPE_WBMP: - if (imagetypes() & IMG_WBMP) { - $this->resource = imagecreatefromwbmp($imagePath); - } else { - OC_Log::write('core', - 'OC_Image->loadFromFile, WBMP images not supported: '.$imagePath, - OC_Log::DEBUG); - } - break; - case IMAGETYPE_BMP: - $this->resource = $this->imagecreatefrombmp($imagePath); - break; - /* - case IMAGETYPE_TIFF_II: // (intel byte order) - break; - case IMAGETYPE_TIFF_MM: // (motorola byte order) - break; - case IMAGETYPE_JPC: - break; - case IMAGETYPE_JP2: - break; - case IMAGETYPE_JPX: - break; - case IMAGETYPE_JB2: - break; - case IMAGETYPE_SWC: - break; - case IMAGETYPE_IFF: - break; - case IMAGETYPE_ICO: - break; - case IMAGETYPE_SWF: - break; - case IMAGETYPE_PSD: - break; - */ - default: - - // this is mostly file created from encrypted file - $this->resource = imagecreatefromstring(\OC\Files\Filesystem::file_get_contents(\OC\Files\Filesystem::getLocalPath($imagePath))); - $iType = IMAGETYPE_PNG; - OC_Log::write('core', 'OC_Image->loadFromFile, Default', OC_Log::DEBUG); - break; - } - if($this->valid()) { - $this->imageType = $iType; - $this->mimeType = image_type_to_mime_type($iType); - $this->filePath = $imagePath; - } - return $this->resource; - } - - /** - * @brief Loads an image from a string of data. - * @param $str A string of image data as read from a file. - * @returns An image resource or false on error - */ - public function loadFromData($str) { - if(is_resource($str)) { - return false; - } - $this->resource = @imagecreatefromstring($str); - if ($this->fileInfo) { - $this->mimeType = $this->fileInfo->buffer($str); - } - if(is_resource($this->resource)) { - imagealphablending($this->resource, false); - imagesavealpha($this->resource, true); - } - - if(!$this->resource) { - OC_Log::write('core', 'OC_Image->loadFromData, couldn\'t load', OC_Log::DEBUG); - return false; - } - return $this->resource; - } - - /** - * @brief Loads an image from a base64 encoded string. - * @param $str A string base64 encoded string of image data. - * @returns An image resource or false on error - */ - public function loadFromBase64($str) { - if(!is_string($str)) { - return false; - } - $data = base64_decode($str); - if($data) { // try to load from string data - $this->resource = @imagecreatefromstring($data); - if ($this->fileInfo) { - $this->mimeType = $this->fileInfo->buffer($data); - } - if(!$this->resource) { - OC_Log::write('core', 'OC_Image->loadFromBase64, couldn\'t load', OC_Log::DEBUG); - return false; - } - return $this->resource; - } else { - return false; - } - } - - /** - * Create a new image from file or URL - * @link http://www.programmierer-forum.de/function-imagecreatefrombmp-laeuft-mit-allen-bitraten-t143137.htm - * @version 1.00 - * @param string $filename

- * Path to the BMP image. - *

- * @return resource an image resource identifier on success, FALSE on errors. - */ - private function imagecreatefrombmp($fileName) { - if (!($fh = fopen($fileName, 'rb'))) { - trigger_error('imagecreatefrombmp: Can not open ' . $fileName, E_USER_WARNING); - return false; - } - // read file header - $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14)); - // check for bitmap - if ($meta['type'] != 19778) { - trigger_error('imagecreatefrombmp: ' . $fileName . ' is not a bitmap!', E_USER_WARNING); - return false; - } - // read image header - $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40)); - // read additional 16bit header - if ($meta['bits'] == 16) { - $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12)); - } - // set bytes and padding - $meta['bytes'] = $meta['bits'] / 8; - $this->bitDepth = $meta['bits']; //remember the bit depth for the imagebmp call - $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4))); - if ($meta['decal'] == 4) { - $meta['decal'] = 0; - } - // obtain imagesize - if ($meta['imagesize'] < 1) { - $meta['imagesize'] = $meta['filesize'] - $meta['offset']; - // in rare cases filesize is equal to offset so we need to read physical size - if ($meta['imagesize'] < 1) { - $meta['imagesize'] = @filesize($filename) - $meta['offset']; - if ($meta['imagesize'] < 1) { - trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING); - return false; - } - } - } - // calculate colors - $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors']; - // read color palette - $palette = array(); - if ($meta['bits'] < 16) { - $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4)); - // in rare cases the color value is signed - if ($palette[1] < 0) { - foreach ($palette as $i => $color) { - $palette[$i] = $color + 16777216; - } - } - } - // create gd image - $im = imagecreatetruecolor($meta['width'], $meta['height']); - $data = fread($fh, $meta['imagesize']); - $p = 0; - $vide = chr(0); - $y = $meta['height'] - 1; - $error = 'imagecreatefrombmp: ' . $fileName . ' has not enough data!'; - // loop through the image data beginning with the lower left corner - while ($y >= 0) { - $x = 0; - while ($x < $meta['width']) { - switch ($meta['bits']) { - case 32: - case 24: - if (!($part = substr($data, $p, 3))) { - trigger_error($error, E_USER_WARNING); - return $im; - } - $color = unpack('V', $part . $vide); - break; - case 16: - if (!($part = substr($data, $p, 2))) { - trigger_error($error, E_USER_WARNING); - return $im; - } - $color = unpack('v', $part); - $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3); - break; - case 8: - $color = unpack('n', $vide . substr($data, $p, 1)); - $color[1] = $palette[ $color[1] + 1 ]; - break; - case 4: - $color = unpack('n', $vide . substr($data, floor($p), 1)); - $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F; - $color[1] = $palette[ $color[1] + 1 ]; - break; - case 1: - $color = unpack('n', $vide . substr($data, floor($p), 1)); - switch (($p * 8) % 8) { - case 0: - $color[1] = $color[1] >> 7; - break; - case 1: - $color[1] = ($color[1] & 0x40) >> 6; - break; - case 2: - $color[1] = ($color[1] & 0x20) >> 5; - break; - case 3: - $color[1] = ($color[1] & 0x10) >> 4; - break; - case 4: - $color[1] = ($color[1] & 0x8) >> 3; - break; - case 5: - $color[1] = ($color[1] & 0x4) >> 2; - break; - case 6: - $color[1] = ($color[1] & 0x2) >> 1; - break; - case 7: - $color[1] = ($color[1] & 0x1); - break; - } - $color[1] = $palette[ $color[1] + 1 ]; - break; - default: - trigger_error('imagecreatefrombmp: ' - . $fileName . ' has ' . $meta['bits'] . ' bits and this is not supported!', - E_USER_WARNING); - return false; - } - imagesetpixel($im, $x, $y, $color[1]); - $x++; - $p += $meta['bytes']; - } - $y--; - $p += $meta['decal']; - } - fclose($fh); - return $im; - } - - /** - * @brief Resizes the image preserving ratio. - * @param $maxsize The maximum size of either the width or height. - * @returns bool - */ - public function resize($maxSize) { - if(!$this->valid()) { - OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); - return false; - } - $widthOrig=imageSX($this->resource); - $heightOrig=imageSY($this->resource); - $ratioOrig = $widthOrig/$heightOrig; - - if ($ratioOrig > 1) { - $newHeight = round($maxSize/$ratioOrig); - $newWidth = $maxSize; - } else { - $newWidth = round($maxSize*$ratioOrig); - $newHeight = $maxSize; - } - - $this->preciseResize(round($newWidth), round($newHeight)); - return true; - } - - public function preciseResize($width, $height) { - if (!$this->valid()) { - OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); - return false; - } - $widthOrig=imageSX($this->resource); - $heightOrig=imageSY($this->resource); - $process = imagecreatetruecolor($width, $height); - - if ($process == false) { - OC_Log::write('core', __METHOD__.'(): Error creating true color image', OC_Log::ERROR); - imagedestroy($process); - return false; - } - - // preserve transparency - if($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) { - imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127)); - imagealphablending($process, false); - imagesavealpha($process, true); - } - - imagecopyresampled($process, $this->resource, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig); - if ($process == false) { - OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$width.'x'.$height, OC_Log::ERROR); - imagedestroy($process); - return false; - } - imagedestroy($this->resource); - $this->resource = $process; - return true; - } - - /** - * @brief Crops the image to the middle square. If the image is already square it just returns. - * @param int maximum size for the result (optional) - * @returns bool for success or failure - */ - public function centerCrop($size=0) { - if(!$this->valid()) { - OC_Log::write('core', 'OC_Image->centerCrop, No image loaded', OC_Log::ERROR); - return false; - } - $widthOrig=imageSX($this->resource); - $heightOrig=imageSY($this->resource); - if($widthOrig === $heightOrig and $size==0) { - return true; - } - $ratioOrig = $widthOrig/$heightOrig; - $width = $height = min($widthOrig, $heightOrig); - - if ($ratioOrig > 1) { - $x = ($widthOrig/2) - ($width/2); - $y = 0; - } else { - $y = ($heightOrig/2) - ($height/2); - $x = 0; - } - if($size>0) { - $targetWidth=$size; - $targetHeight=$size; - }else{ - $targetWidth=$width; - $targetHeight=$height; - } - $process = imagecreatetruecolor($targetWidth, $targetHeight); - if ($process == false) { - OC_Log::write('core', 'OC_Image->centerCrop. Error creating true color image', OC_Log::ERROR); - imagedestroy($process); - return false; - } - - // preserve transparency - if($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) { - imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127)); - imagealphablending($process, false); - imagesavealpha($process, true); - } - - imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height); - if ($process == false) { - OC_Log::write('core', - 'OC_Image->centerCrop. Error resampling process image '.$width.'x'.$height, - OC_Log::ERROR); - imagedestroy($process); - return false; - } - imagedestroy($this->resource); - $this->resource = $process; - return true; - } - - /** - * @brief Crops the image from point $x$y with dimension $wx$h. - * @param $x Horizontal position - * @param $y Vertical position - * @param $w Width - * @param $h Height - * @returns bool for success or failure - */ - public function crop($x, $y, $w, $h) { - if(!$this->valid()) { - OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); - return false; - } - $process = imagecreatetruecolor($w, $h); - if ($process == false) { - OC_Log::write('core', __METHOD__.'(): Error creating true color image', OC_Log::ERROR); - imagedestroy($process); - return false; - } - imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h); - if ($process == false) { - OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$w.'x'.$h, OC_Log::ERROR); - imagedestroy($process); - return false; - } - imagedestroy($this->resource); - $this->resource = $process; - return true; - } - - /** - * @brief Resizes the image to fit within a boundry while preserving ratio. - * @param $maxWidth - * @param $maxHeight - * @returns bool - */ - public function fitIn($maxWidth, $maxHeight) { - if(!$this->valid()) { - OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); - return false; - } - $widthOrig=imageSX($this->resource); - $heightOrig=imageSY($this->resource); - $ratio = $widthOrig/$heightOrig; - - $newWidth = min($maxWidth, $ratio*$maxHeight); - $newHeight = min($maxHeight, $maxWidth/$ratio); - - $this->preciseResize(round($newWidth), round($newHeight)); - return true; - } - - public function destroy() { - if($this->valid()) { - imagedestroy($this->resource); - } - $this->resource=null; - } - - public function __destruct() { - $this->destroy(); - } -} -if ( ! function_exists( 'imagebmp') ) { - /** - * Output a BMP image to either the browser or a file - * @link http://www.ugia.cn/wp-data/imagebmp.php - * @author legend - * @link http://www.programmierer-forum.de/imagebmp-gute-funktion-gefunden-t143716.htm - * @author mgutt - * @version 1.00 - * @param resource $image - * @param string $filename [optional]

The path to save the file to.

- * @param int $bit [optional]

Bit depth, (default is 24).

- * @param int $compression [optional] - * @return bool TRUE on success or FALSE on failure. - */ - function imagebmp($im, $fileName='', $bit=24, $compression=0) { - if (!in_array($bit, array(1, 4, 8, 16, 24, 32))) { - $bit = 24; - } - else if ($bit == 32) { - $bit = 24; - } - $bits = pow(2, $bit); - imagetruecolortopalette($im, true, $bits); - $width = imagesx($im); - $height = imagesy($im); - $colorsNum = imagecolorstotal($im); - $rgbQuad = ''; - if ($bit <= 8) { - for ($i = 0; $i < $colorsNum; $i++) { - $colors = imagecolorsforindex($im, $i); - $rgbQuad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0"; - } - $bmpData = ''; - if ($compression == 0 || $bit < 8) { - $compression = 0; - $extra = ''; - $padding = 4 - ceil($width / (8 / $bit)) % 4; - if ($padding % 4 != 0) { - $extra = str_repeat("\0", $padding); - } - for ($j = $height - 1; $j >= 0; $j --) { - $i = 0; - while ($i < $width) { - $bin = 0; - $limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0; - for ($k = 8 - $bit; $k >= $limit; $k -= $bit) { - $index = imagecolorat($im, $i, $j); - $bin |= $index << $k; - $i++; - } - $bmpData .= chr($bin); - } - $bmpData .= $extra; - } - } - // RLE8 - else if ($compression == 1 && $bit == 8) { - for ($j = $height - 1; $j >= 0; $j--) { - $lastIndex = "\0"; - $sameNum = 0; - for ($i = 0; $i <= $width; $i++) { - $index = imagecolorat($im, $i, $j); - if ($index !== $lastIndex || $sameNum > 255) { - if ($sameNum != 0) { - $bmpData .= chr($same_num) . chr($lastIndex); - } - $lastIndex = $index; - $sameNum = 1; - } - else { - $sameNum++; - } - } - $bmpData .= "\0\0"; - } - $bmpData .= "\0\1"; - } - $sizeQuad = strlen($rgbQuad); - $sizeData = strlen($bmpData); - } - else { - $extra = ''; - $padding = 4 - ($width * ($bit / 8)) % 4; - if ($padding % 4 != 0) { - $extra = str_repeat("\0", $padding); - } - $bmpData = ''; - for ($j = $height - 1; $j >= 0; $j--) { - for ($i = 0; $i < $width; $i++) { - $index = imagecolorat($im, $i, $j); - $colors = imagecolorsforindex($im, $index); - if ($bit == 16) { - $bin = 0 << $bit; - $bin |= ($colors['red'] >> 3) << 10; - $bin |= ($colors['green'] >> 3) << 5; - $bin |= $colors['blue'] >> 3; - $bmpData .= pack("v", $bin); - } - else { - $bmpData .= pack("c*", $colors['blue'], $colors['green'], $colors['red']); - } - } - $bmpData .= $extra; - } - $sizeQuad = 0; - $sizeData = strlen($bmpData); - $colorsNum = 0; - } - $fileHeader = 'BM' . pack('V3', 54 + $sizeQuad + $sizeData, 0, 54 + $sizeQuad); - $infoHeader = pack('V3v2V*', 0x28, $width, $height, 1, $bit, $compression, $sizeData, 0, 0, $colorsNum, 0); - if ($fileName != '') { - $fp = fopen($fileName, 'wb'); - fwrite($fp, $fileHeader . $infoHeader . $rgbQuad . $bmpData); - fclose($fp); - return true; - } - echo $fileHeader . $infoHeader. $rgbQuad . $bmpData; - return true; - } -} - -if ( ! function_exists( 'exif_imagetype' ) ) { - /** - * Workaround if exif_imagetype does not exist - * @link http://www.php.net/manual/en/function.exif-imagetype.php#80383 - * @param string $filename - * @return string|boolean - */ - function exif_imagetype ( $fileName ) { - if ( ( $info = getimagesize( $fileName ) ) !== false ) { - return $info[2]; - } - return false; - } -} diff --git a/lib/installer.php b/lib/installer.php deleted file mode 100644 index e082c7eeee9..00000000000 --- a/lib/installer.php +++ /dev/null @@ -1,481 +0,0 @@ -. - * - */ - -/** - * This class provides the functionality needed to install, update and remove plugins/apps - */ -class OC_Installer{ - /** - * @brief Installs an app - * @param $data array with all information - * @throws \Exception - * @returns integer - * - * This function installs an app. All information needed are passed in the - * associative array $data. - * The following keys are required: - * - source: string, can be "path" or "http" - * - * One of the following keys is required: - * - path: path to the file containing the app - * - href: link to the downloadable file containing the app - * - * The following keys are optional: - * - pretend: boolean, if set true the system won't do anything - * - noinstall: boolean, if true appinfo/install.php won't be loaded - * - inactive: boolean, if set true the appconfig/app.sample.php won't be - * renamed - * - * This function works as follows - * -# fetching the file - * -# unzipping it - * -# check the code - * -# installing the database at appinfo/database.xml - * -# including appinfo/install.php - * -# setting the installed version - * - * It is the task of oc_app_install to create the tables and do whatever is - * needed to get the app working. - */ - public static function installApp( $data = array()) { - $l = \OC_L10N::get('lib'); - - if(!isset($data['source'])) { - throw new \Exception($l->t("No source specified when installing app")); - } - - //download the file if necesary - if($data['source']=='http') { - $path=OC_Helper::tmpFile(); - if(!isset($data['href'])) { - throw new \Exception($l->t("No href specified when installing app from http")); - } - copy($data['href'], $path); - }else{ - if(!isset($data['path'])) { - throw new \Exception($l->t("No path specified when installing app from local file")); - } - $path=$data['path']; - } - - //detect the archive type - $mime=OC_Helper::getMimeType($path); - if($mime=='application/zip') { - rename($path, $path.'.zip'); - $path.='.zip'; - }elseif($mime=='application/x-gzip') { - rename($path, $path.'.tgz'); - $path.='.tgz'; - }else{ - throw new \Exception($l->t("Archives of type %s are not supported", array($mime))); - } - - //extract the archive in a temporary folder - $extractDir=OC_Helper::tmpFolder(); - OC_Helper::rmdirr($extractDir); - mkdir($extractDir); - if($archive=OC_Archive::open($path)) { - $archive->extract($extractDir); - } else { - OC_Helper::rmdirr($extractDir); - if($data['source']=='http') { - unlink($path); - } - throw new \Exception($l->t("Failed to open archive when installing app")); - } - - //load the info.xml file of the app - if(!is_file($extractDir.'/appinfo/info.xml')) { - //try to find it in a subdir - $dh=opendir($extractDir); - if(is_resource($dh)) { - while (($folder = readdir($dh)) !== false) { - if($folder[0]!='.' and is_dir($extractDir.'/'.$folder)) { - if(is_file($extractDir.'/'.$folder.'/appinfo/info.xml')) { - $extractDir.='/'.$folder; - } - } - } - } - } - if(!is_file($extractDir.'/appinfo/info.xml')) { - OC_Helper::rmdirr($extractDir); - if($data['source']=='http') { - unlink($path); - } - throw new \Exception($l->t("App does not provide an info.xml file")); - } - $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml', true); - // check the code for not allowed calls - if(!OC_Installer::checkCode($info['id'], $extractDir)) { - OC_Helper::rmdirr($extractDir); - throw new \Exception($l->t("App can't be installed because of not allowed code in the App")); - } - - // check if the app is compatible with this version of ownCloud - if( - !isset($info['require']) - or !OC_App::isAppVersionCompatible(OC_Util::getVersion(), $info['require']) - ) { - OC_Helper::rmdirr($extractDir); - throw new \Exception($l->t("App can't be installed because it is not compatible with this version of ownCloud")); - } - - // check if shipped tag is set which is only allowed for apps that are shipped with ownCloud - if(isset($info['shipped']) and ($info['shipped']=='true')) { - OC_Helper::rmdirr($extractDir); - throw new \Exception($l->t("App can't be installed because it contains the true tag which is not allowed for non shipped apps")); - } - - // check if the ocs version is the same as the version in info.xml/version - if(!isset($info['version']) or ($info['version']<>$data['appdata']['version'])) { - OC_Helper::rmdirr($extractDir); - throw new \Exception($l->t("App can't be installed because the version in info.xml/version is not the same as the version reported from the app store")); - } - - $basedir=OC_App::getInstallPath().'/'.$info['id']; - //check if the destination directory already exists - if(is_dir($basedir)) { - OC_Helper::rmdirr($extractDir); - if($data['source']=='http') { - unlink($path); - } - throw new \Exception($l->t("App directory already exists")); - } - - if(isset($data['pretent']) and $data['pretent']==true) { - return false; - } - - //copy the app to the correct place - if(@!mkdir($basedir)) { - OC_Helper::rmdirr($extractDir); - if($data['source']=='http') { - unlink($path); - } - throw new \Exception($l->t("Can't create app folder. Please fix permissions. %s", array($basedir))); - } - OC_Helper::copyr($extractDir, $basedir); - - //remove temporary files - OC_Helper::rmdirr($extractDir); - - //install the database - if(is_file($basedir.'/appinfo/database.xml')) { - OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml'); - } - - //run appinfo/install.php - if((!isset($data['noinstall']) or $data['noinstall']==false) and file_exists($basedir.'/appinfo/install.php')) { - include $basedir.'/appinfo/install.php'; - } - - //set the installed version - OC_Appconfig::setValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'])); - OC_Appconfig::setValue($info['id'], 'enabled', 'no'); - - //set remote/public handelers - foreach($info['remote'] as $name=>$path) { - OCP\CONFIG::setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); - } - foreach($info['public'] as $name=>$path) { - OCP\CONFIG::setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); - } - - OC_App::setAppTypes($info['id']); - - return $info['id']; - } - - /** - * @brief checks whether or not an app is installed - * @param $app app - * @returns true/false - * - * Checks whether or not an app is installed, i.e. registered in apps table. - */ - public static function isInstalled( $app ) { - - if( null == OC_Appconfig::getValue( $app, "installed_version" )) { - return false; - } - - return true; - } - - /** - * @brief Update an application - * @param $data array with all information - * - * This function installs an app. All information needed are passed in the - * associative array $data. - * The following keys are required: - * - source: string, can be "path" or "http" - * - * One of the following keys is required: - * - path: path to the file containing the app - * - href: link to the downloadable file containing the app - * - * The following keys are optional: - * - pretend: boolean, if set true the system won't do anything - * - noupgrade: boolean, if true appinfo/upgrade.php won't be loaded - * - * This function works as follows - * -# fetching the file - * -# removing the old files - * -# unzipping new file - * -# including appinfo/upgrade.php - * -# setting the installed version - * - * upgrade.php can determine the current installed version of the app using - * "OC_Appconfig::getValue($appid, 'installed_version')" - */ - public static function updateApp( $app ) { - $ocsid=OC_Appconfig::getValue( $app, 'ocsid'); - OC_App::disable($app); - OC_App::enable($ocsid); - return(true); - } - - /** - * @brief Check if an update for the app is available - * @param $name name of the application - * @returns empty string is no update available or the version number of the update - * - * The function will check if an update for a version is available - */ - public static function isUpdateAvailable( $app ) { - $ocsid=OC_Appconfig::getValue( $app, 'ocsid', ''); - - if($ocsid<>'') { - - $ocsdata=OC_OCSClient::getApplication($ocsid); - $ocsversion= (string) $ocsdata['version']; - $currentversion=OC_App::getAppVersion($app); - if($ocsversion<>$currentversion) { - return($ocsversion); - - }else{ - return(''); - } - - }else{ - return(''); - } - - } - - /** - * @brief Check if app is already downloaded - * @param $name name of the application to remove - * @returns true/false - * - * The function will check if the app is already downloaded in the apps repository - */ - public static function isDownloaded( $name ) { - - $downloaded=false; - foreach(OC::$APPSROOTS as $dir) { - if(is_dir($dir['path'].'/'.$name)) $downloaded=true; - } - return($downloaded); - } - - /** - * @brief Removes an app - * @param $name name of the application to remove - * @param $options array with options - * @returns true/false - * - * This function removes an app. $options is an associative array. The - * following keys are optional:ja - * - keeppreferences: boolean, if true the user preferences won't be deleted - * - keepappconfig: boolean, if true the config will be kept - * - keeptables: boolean, if true the database will be kept - * - keepfiles: boolean, if true the user files will be kept - * - * This function works as follows - * -# including appinfo/remove.php - * -# removing the files - * - * The function will not delete preferences, tables and the configuration, - * this has to be done by the function oc_app_uninstall(). - */ - public static function removeApp( $name, $options = array()) { - - if(isset($options['keeppreferences']) and $options['keeppreferences']==false ) { - // todo - // remove preferences - } - - if(isset($options['keepappconfig']) and $options['keepappconfig']==false ) { - // todo - // remove app config - } - - if(isset($options['keeptables']) and $options['keeptables']==false ) { - // todo - // remove app database tables - } - - if(isset($options['keepfiles']) and $options['keepfiles']==false ) { - // todo - // remove user files - } - - if(OC_Installer::isDownloaded( $name )) { - $appdir=OC_App::getInstallPath().'/'.$name; - OC_Helper::rmdirr($appdir); - - }else{ - OC_Log::write('core', 'can\'t remove app '.$name.'. It is not installed.', OC_Log::ERROR); - - } - - } - - /** - * @brief Installs shipped apps - * - * This function installs all apps found in the 'apps' directory that should be enabled by default; - */ - public static function installShippedApps() { - foreach(OC::$APPSROOTS as $app_dir) { - if($dir = opendir( $app_dir['path'] )) { - while( false !== ( $filename = readdir( $dir ))) { - if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) { - if( file_exists( $app_dir['path']."/$filename/appinfo/app.php" )) { - if(!OC_Installer::isInstalled($filename)) { - $info=OC_App::getAppInfo($filename); - $enabled = isset($info['default_enable']); - if( $enabled ) { - OC_Installer::installShippedApp($filename); - OC_Appconfig::setValue($filename, 'enabled', 'yes'); - } - } - } - } - } - closedir( $dir ); - } - } - } - - /** - * install an app already placed in the app folder - * @param string $app id of the app to install - * @returns array see OC_App::getAppInfo - */ - public static function installShippedApp($app) { - //install the database - if(is_file(OC_App::getAppPath($app)."/appinfo/database.xml")) { - OC_DB::createDbFromStructure(OC_App::getAppPath($app)."/appinfo/database.xml"); - } - - //run appinfo/install.php - if(is_file(OC_App::getAppPath($app)."/appinfo/install.php")) { - include OC_App::getAppPath($app)."/appinfo/install.php"; - } - $info=OC_App::getAppInfo($app); - OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app)); - - //set remote/public handelers - foreach($info['remote'] as $name=>$path) { - OCP\CONFIG::setAppValue('core', 'remote_'.$name, $app.'/'.$path); - } - foreach($info['public'] as $name=>$path) { - OCP\CONFIG::setAppValue('core', 'public_'.$name, $app.'/'.$path); - } - - OC_App::setAppTypes($info['id']); - - return $info['id']; - } - - - /** - * check the code of an app with some static code checks - * @param string $folder the folder of the app to check - * @returns true for app is o.k. and false for app is not o.k. - */ - public static function checkCode($appname, $folder) { - - $blacklist=array( - 'exec(', - 'eval(', - // more evil pattern will go here later - - // classes replaced by the public api - 'OC_API::', - 'OC_App::', - 'OC_AppConfig::', - 'OC_Avatar', - 'OC_BackgroundJob::', - 'OC_Config::', - 'OC_DB::', - 'OC_Files::', - 'OC_Helper::', - 'OC_Hook::', - 'OC_Image::', - 'OC_JSON::', - 'OC_L10N::', - 'OC_Log::', - 'OC_Mail::', - 'OC_Preferences::', - 'OC_Request::', - 'OC_Response::', - 'OC_Template::', - 'OC_User::', - 'OC_Util::', - ); - - // is the code checker enabled? - if(OC_Config::getValue('appcodechecker', false)) { - - // check if grep is installed - $grep = exec('which grep'); - if($grep=='') { - OC_Log::write('core', - 'grep not installed. So checking the code of the app "'.$appname.'" was not possible', - OC_Log::ERROR); - return true; - } - - // iterate the bad patterns - foreach($blacklist as $bl) { - $cmd = 'grep -ri '.escapeshellarg($bl).' '.$folder.''; - $result = exec($cmd); - // bad pattern found - if($result<>'') { - OC_Log::write('core', - 'App "'.$appname.'" is using a not allowed call "'.$bl.'". Installation refused.', - OC_Log::ERROR); - return false; - } - } - return true; - - }else{ - return true; - } - } -} diff --git a/lib/json.php b/lib/json.php deleted file mode 100644 index 6ba0b13806b..00000000000 --- a/lib/json.php +++ /dev/null @@ -1,115 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_JSON{ - static protected $send_content_type_header = false; - /** - * set Content-Type header to jsonrequest - */ - public static function setContentTypeHeader($type='application/json') { - if (!self::$send_content_type_header) { - // We send json data - header( 'Content-Type: '.$type . '; charset=utf-8'); - self::$send_content_type_header = true; - } - } - - /** - * Check if the app is enabled, send json error msg if not - */ - public static function checkAppEnabled($app) { - if( !OC_App::isEnabled($app)) { - $l = OC_L10N::get('lib'); - self::error(array( 'data' => array( 'message' => $l->t('Application is not enabled') ))); - exit(); - } - } - - /** - * Check if the user is logged in, send json error msg if not - */ - public static function checkLoggedIn() { - if( !OC_User::isLoggedIn()) { - $l = OC_L10N::get('lib'); - self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); - exit(); - } - } - - /** - * @brief Check an ajax get/post call if the request token is valid. - * @return json Error msg if not valid. - */ - public static function callCheck() { - if( !OC_Util::isCallRegistered()) { - $l = OC_L10N::get('lib'); - self::error(array( 'data' => array( 'message' => $l->t('Token expired. Please reload page.') ))); - exit(); - } - } - - /** - * Check if the user is a admin, send json error msg if not - */ - public static function checkAdminUser() { - if( !OC_User::isAdminUser(OC_User::getUser())) { - $l = OC_L10N::get('lib'); - self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); - exit(); - } - } - - /** - * Check if the user is a subadmin, send json error msg if not - */ - public static function checkSubAdminUser() { - if(!OC_SubAdmin::isSubAdmin(OC_User::getUser())) { - $l = OC_L10N::get('lib'); - self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); - exit(); - } - } - - /** - * Send json error msg - */ - public static function error($data = array()) { - $data['status'] = 'error'; - self::encodedPrint($data); - } - - /** - * Send json success msg - */ - public static function success($data = array()) { - $data['status'] = 'success'; - self::encodedPrint($data); - } - - /** - * Convert OC_L10N_String to string, for use in json encodings - */ - protected static function to_string(&$value) { - if ($value instanceof OC_L10N_String) { - $value = (string)$value; - } - } - - /** - * Encode and print $data in json format - */ - public static function encodedPrint($data, $setContentType=true) { - // Disable mimesniffing, don't move this to setContentTypeHeader! - header( 'X-Content-Type-Options: nosniff' ); - if($setContentType) { - self::setContentTypeHeader(); - } - array_walk_recursive($data, array('OC_JSON', 'to_string')); - echo json_encode($data); - } -} diff --git a/lib/l10n.php b/lib/l10n.php deleted file mode 100644 index f93443b886a..00000000000 --- a/lib/l10n.php +++ /dev/null @@ -1,546 +0,0 @@ -. - * - */ - -/** - * This class is for i18n and l10n - */ -class OC_L10N { - /** - * cached instances - */ - protected static $instances=array(); - - /** - * cache - */ - protected static $cache = array(); - - /** - * The best language - */ - protected static $language = ''; - - /** - * App of this object - */ - protected $app; - - /** - * Language of this object - */ - protected $lang; - - /** - * Translations - */ - private $translations = array(); - - /** - * Plural forms (string) - */ - private $plural_form_string = 'nplurals=2; plural=(n != 1);'; - - /** - * Plural forms (function) - */ - private $plural_form_function = null; - - /** - * Localization - */ - private $localizations = array( - 'jsdate' => 'dd.mm.yy', - 'date' => '%d.%m.%Y', - 'datetime' => '%d.%m.%Y %H:%M:%S', - 'time' => '%H:%M:%S', - 'firstday' => 0); - - /** - * get an L10N instance - * @param $app string - * @param $lang string|null - * @return OC_L10N - */ - public static function get($app, $lang=null) { - if(is_null($lang)) { - if(!isset(self::$instances[$app])) { - self::$instances[$app]=new OC_L10N($app); - } - return self::$instances[$app]; - }else{ - return new OC_L10N($app, $lang); - } - } - - /** - * @brief The constructor - * @param $app string app requesting l10n - * @param $lang string default: null Language - * @returns OC_L10N-Object - * - * If language is not set, the constructor tries to find the right - * language. - */ - public function __construct($app, $lang = null) { - $this->app = $app; - $this->lang = $lang; - } - - public function load($transFile) { - $this->app = true; - include $transFile; - if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)) { - $this->translations = $TRANSLATIONS; - } - if(isset($PLURAL_FORMS)) { - $this->plural_form_string = $PLURAL_FORMS; - } - } - - protected function init() { - if ($this->app === true) { - return; - } - $app = OC_App::cleanAppId($this->app); - $lang = $this->lang; - $this->app = true; - // Find the right language - if(is_null($lang) || $lang == '') { - $lang = self::findLanguage($app); - } - - // Use cache if possible - if(array_key_exists($app.'::'.$lang, self::$cache)) { - - $this->translations = self::$cache[$app.'::'.$lang]['t']; - $this->localizations = self::$cache[$app.'::'.$lang]['l']; - } - else{ - $i18ndir = self::findI18nDir($app); - // Localization is in /l10n, Texts are in $i18ndir - // (Just no need to define date/time format etc. twice) - if((OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC_App::getAppPath($app).'/l10n/') - || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/core/l10n/') - || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/lib/l10n/') - || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/settings') - ) - && file_exists($i18ndir.$lang.'.php')) { - // Include the file, save the data from $CONFIG - $transFile = strip_tags($i18ndir).strip_tags($lang).'.php'; - include $transFile; - if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)) { - $this->translations = $TRANSLATIONS; - //merge with translations from theme - $theme = OC_Config::getValue( "theme" ); - if (!is_null($theme)) { - $transFile = OC::$SERVERROOT.'/themes/'.$theme.substr($transFile, strlen(OC::$SERVERROOT)); - if (file_exists($transFile)) { - include $transFile; - if (isset($TRANSLATIONS) && is_array($TRANSLATIONS)) { - $this->translations = array_merge($this->translations, $TRANSLATIONS); - } - } - } - } - if(isset($PLURAL_FORMS)) { - $this->plural_form_string = $PLURAL_FORMS; - } - } - - if(file_exists(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php')) { - // Include the file, save the data from $CONFIG - include OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php'; - if(isset($LOCALIZATIONS) && is_array($LOCALIZATIONS)) { - $this->localizations = array_merge($this->localizations, $LOCALIZATIONS); - } - } - - self::$cache[$app.'::'.$lang]['t'] = $this->translations; - self::$cache[$app.'::'.$lang]['l'] = $this->localizations; - } - } - - /** - * @brief Creates a function that The constructor - * - * If language is not set, the constructor tries to find the right - * language. - * - * Parts of the code is copied from Habari: - * https://github.com/habari/system/blob/master/classes/locale.php - * @param $string string - * @return string - */ - protected function createPluralFormFunction($string){ - if(preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) { - // sanitize - $nplurals = preg_replace( '/[^0-9]/', '', $matches[1] ); - $plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] ); - - $body = str_replace( - array( 'plural', 'n', '$n$plurals', ), - array( '$plural', '$n', '$nplurals', ), - 'nplurals='. $nplurals . '; plural=' . $plural - ); - - // add parents - // important since PHP's ternary evaluates from left to right - $body .= ';'; - $res = ''; - $p = 0; - for($i = 0; $i < strlen($body); $i++) { - $ch = $body[$i]; - switch ( $ch ) { - case '?': - $res .= ' ? ('; - $p++; - break; - case ':': - $res .= ') : ('; - break; - case ';': - $res .= str_repeat( ')', $p ) . ';'; - $p = 0; - break; - default: - $res .= $ch; - } - } - - $body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);'; - return create_function('$n', $body); - } - else { - // default: one plural form for all cases but n==1 (english) - return create_function( - '$n', - '$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);' - ); - } - } - - /** - * @brief Translating - * @param $text String The text we need a translation for - * @param array $parameters default:array() Parameters for sprintf - * @return \OC_L10N_String Translation or the same text - * - * Returns the translation. If no translation is found, $text will be - * returned. - */ - public function t($text, $parameters = array()) { - return new OC_L10N_String($this, $text, $parameters); - } - - /** - * @brief Translating - * @param $text_singular String the string to translate for exactly one object - * @param $text_plural String the string to translate for n objects - * @param $count Integer Number of objects - * @param array $parameters default:array() Parameters for sprintf - * @return \OC_L10N_String Translation or the same text - * - * Returns the translation. If no translation is found, $text will be - * returned. %n will be replaced with the number of objects. - * - * The correct plural is determined by the plural_forms-function - * provided by the po file. - * - */ - public function n($text_singular, $text_plural, $count, $parameters = array()) { - $this->init(); - $identifier = "_${text_singular}__${text_plural}_"; - if( array_key_exists($identifier, $this->translations)) { - return new OC_L10N_String( $this, $identifier, $parameters, $count ); - } - else{ - if($count === 1) { - return new OC_L10N_String($this, $text_singular, $parameters, $count); - } - else{ - return new OC_L10N_String($this, $text_plural, $parameters, $count); - } - } - } - - /** - * @brief Translating - * @param $textArray The text array we need a translation for - * @returns Translation or the same text - * - * Returns the translation. If no translation is found, $textArray will be - * returned. - * - * - * @deprecated deprecated since ownCloud version 5.0 - * This method will probably be removed with ownCloud 6.0 - * - * - */ - public function tA($textArray) { - OC_Log::write('core', 'DEPRECATED: the method tA is deprecated and will be removed soon.', OC_Log::WARN); - $result = array(); - foreach($textArray as $key => $text) { - $result[$key] = (string)$this->t($text); - } - return $result; - } - - /** - * @brief getTranslations - * @returns Fetch all translations - * - * Returns an associative array with all translations - */ - public function getTranslations() { - $this->init(); - return $this->translations; - } - - /** - * @brief getPluralFormString - * @returns string containing the gettext "Plural-Forms"-string - * - * Returns a string like "nplurals=2; plural=(n != 1);" - */ - public function getPluralFormString() { - $this->init(); - return $this->plural_form_string; - } - - /** - * @brief getPluralFormFunction - * @returns string the plural form function - * - * returned function accepts the argument $n - */ - public function getPluralFormFunction() { - $this->init(); - if(is_null($this->plural_form_function)) { - $this->plural_form_function = $this->createPluralFormFunction($this->plural_form_string); - } - return $this->plural_form_function; - } - - /** - * @brief get localizations - * @returns Fetch all localizations - * - * Returns an associative array with all localizations - */ - public function getLocalizations() { - $this->init(); - return $this->localizations; - } - - /** - * @brief Localization - * @param $type Type of localization - * @param $params parameters for this localization - * @returns String or false - * - * Returns the localized data. - * - * Implemented types: - * - date - * - Creates a date - * - l10n-field: date - * - params: timestamp (int/string) - * - datetime - * - Creates date and time - * - l10n-field: datetime - * - params: timestamp (int/string) - * - time - * - Creates a time - * - l10n-field: time - * - params: timestamp (int/string) - */ - public function l($type, $data) { - $this->init(); - switch($type) { - // If you add something don't forget to add it to $localizations - // at the top of the page - case 'date': - case 'datetime': - case 'time': - if($data instanceof DateTime) { - return $data->format($this->localizations[$type]); - } elseif(is_string($data) && !is_numeric($data)) { - $data = strtotime($data); - } - $locales = array(self::findLanguage()); - if (strlen($locales[0]) == 2) { - $locales[] = $locales[0].'_'.strtoupper($locales[0]); - } - setlocale(LC_TIME, $locales); - $format = $this->localizations[$type]; - // Check for Windows to find and replace the %e modifier correctly - if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { - $format = preg_replace('#(?localizations[$type]; - default: - return false; - } - } - - /** - * @brief Choose a language - * @param $texts Associative Array with possible strings - * @returns String - * - * $text is an array 'de' => 'hallo welt', 'en' => 'hello world', ... - * - * This function is useful to avoid loading thousands of files if only one - * simple string is needed, for example in appinfo.php - */ - public static function selectLanguage($text) { - $lang = self::findLanguage(array_keys($text)); - return $text[$lang]; - } - - /** - * @brief find the best language - * @param $app Array or string, details below - * @returns language - * - * If $app is an array, ownCloud assumes that these are the available - * languages. Otherwise ownCloud tries to find the files in the l10n - * folder. - * - * If nothing works it returns 'en' - */ - public static function findLanguage($app = null) { - if(!is_array($app) && self::$language != '') { - return self::$language; - } - - if(OC_User::getUser() && OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang')) { - $lang = OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang'); - self::$language = $lang; - if(is_array($app)) { - $available = $app; - $lang_exists = array_search($lang, $available) !== false; - } - else { - $lang_exists = self::languageExists($app, $lang); - } - if($lang_exists) { - return $lang; - } - } - - $default_language = OC_Config::getValue('default_language', false); - - if($default_language !== false) { - return $default_language; - } - - if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - $accepted_languages = preg_split('/,\s*/', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); - if(is_array($app)) { - $available = $app; - } - else{ - $available = self::findAvailableLanguages($app); - } - foreach($accepted_languages as $i) { - $temp = explode(';', $i); - $temp[0] = str_replace('-', '_', $temp[0]); - if( ($key = array_search($temp[0], $available)) !== false) { - if (is_null($app)) { - self::$language = $available[$key]; - } - return $available[$key]; - } - foreach($available as $l) { - if ( $temp[0] == substr($l, 0, 2) ) { - if (is_null($app)) { - self::$language = $l; - } - return $l; - } - } - } - } - - // Last try: English - return 'en'; - } - - /** - * @brief find the l10n directory - * @param $app App that needs to be translated - * @returns directory - */ - protected static function findI18nDir($app) { - // find the i18n dir - $i18ndir = OC::$SERVERROOT.'/core/l10n/'; - if($app != '') { - // Check if the app is in the app folder - if(file_exists(OC_App::getAppPath($app).'/l10n/')) { - $i18ndir = OC_App::getAppPath($app).'/l10n/'; - } - else{ - $i18ndir = OC::$SERVERROOT.'/'.$app.'/l10n/'; - } - } - return $i18ndir; - } - - /** - * @brief find all available languages for an app - * @param $app App that needs to be translated - * @returns array an array of available languages - */ - public static function findAvailableLanguages($app=null) { - $available=array('en');//english is always available - $dir = self::findI18nDir($app); - if(is_dir($dir)) { - $files=scandir($dir); - foreach($files as $file) { - if(substr($file, -4, 4) === '.php' && substr($file, 0, 4) !== 'l10n') { - $i = substr($file, 0, -4); - $available[] = $i; - } - } - } - return $available; - } - - public static function languageExists($app, $lang) { - if ($lang == 'en') {//english is always available - return true; - } - $dir = self::findI18nDir($app); - if(is_dir($dir)) { - return file_exists($dir.'/'.$lang.'.php'); - } - return false; - } -} diff --git a/lib/l10n/ach.php b/lib/l10n/ach.php deleted file mode 100644 index 406ff5f5a26..00000000000 --- a/lib/l10n/ach.php +++ /dev/null @@ -1,8 +0,0 @@ - array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/l10n/af_ZA.php b/lib/l10n/af_ZA.php deleted file mode 100644 index d6bf5771e8d..00000000000 --- a/lib/l10n/af_ZA.php +++ /dev/null @@ -1,14 +0,0 @@ - "Hulp", -"Personal" => "Persoonlik", -"Settings" => "Instellings", -"Users" => "Gebruikers", -"Admin" => "Admin", -"web services under your control" => "webdienste onder jou beheer", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ar.php b/lib/l10n/ar.php deleted file mode 100644 index f626dcdfda6..00000000000 --- a/lib/l10n/ar.php +++ /dev/null @@ -1,50 +0,0 @@ - "المساعدة", -"Personal" => "شخصي", -"Settings" => "إعدادات", -"Users" => "المستخدمين", -"Admin" => "المدير", -"web services under your control" => "خدمات الشبكة تحت سيطرتك", -"ZIP download is turned off." => "تحميل ملفات ZIP متوقف", -"Files need to be downloaded one by one." => "الملفات بحاجة الى ان يتم تحميلها واحد تلو الاخر", -"Back to Files" => "العودة الى الملفات", -"Selected files too large to generate zip file." => "الملفات المحددة كبيرة جدا ليتم ضغطها في ملف zip", -"Application is not enabled" => "التطبيق غير مفعّل", -"Authentication error" => "لم يتم التأكد من الشخصية بنجاح", -"Token expired. Please reload page." => "انتهت صلاحية الكلمة , يرجى اعادة تحميل الصفحة", -"Files" => "الملفات", -"Text" => "معلومات إضافية", -"Images" => "صور", -"%s enter the database username." => "%s ادخل اسم المستخدم الخاص بقاعدة البيانات.", -"%s enter the database name." => "%s ادخل اسم فاعدة البيانات", -"%s you may not use dots in the database name" => "%s لا يسمح لك باستخدام نقطه (.) في اسم قاعدة البيانات", -"MS SQL username and/or password not valid: %s" => "اسم المستخدم و/أو كلمة المرور لنظام MS SQL غير صحيح : %s", -"You need to enter either an existing account or the administrator." => "انت بحاجة لكتابة اسم مستخدم موجود أو حساب المدير.", -"MySQL username and/or password not valid" => "اسم المستخدم و/أو كلمة المرور لنظام MySQL غير صحيح", -"DB Error: \"%s\"" => "خطأ في قواعد البيانات : \"%s\"", -"Offending command was: \"%s\"" => "الأمر المخالف كان : \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "أسم المستخدم '%s'@'localhost' الخاص بـ MySQL موجود مسبقا", -"Drop this user from MySQL" => "احذف اسم المستخدم هذا من الـ MySQL", -"MySQL user '%s'@'%%' already exists" => "أسم المستخدم '%s'@'%%' الخاص بـ MySQL موجود مسبقا", -"Drop this user from MySQL." => "احذف اسم المستخدم هذا من الـ MySQL.", -"Oracle username and/or password not valid" => "اسم المستخدم و/أو كلمة المرور لنظام Oracle غير صحيح", -"Offending command was: \"%s\", name: %s, password: %s" => "الأمر المخالف كان : \"%s\", اسم المستخدم : %s, كلمة المرور: %s", -"PostgreSQL username and/or password not valid" => "اسم المستخدم / أو كلمة المرور الخاصة بـPostgreSQL غير صحيحة", -"Set an admin username." => "اعداد اسم مستخدم للمدير", -"Set an admin password." => "اعداد كلمة مرور للمدير", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "اعدادات خادمك غير صحيحة بشكل تسمح لك بمزامنة ملفاتك وذلك بسبب أن واجهة WebDAV تبدو معطلة", -"Please double check the installation guides." => "الرجاء التحقق من دليل التنصيب.", -"seconds ago" => "منذ ثواني", -"_%n minute ago_::_%n minutes ago_" => array("","","","","",""), -"_%n hour ago_::_%n hours ago_" => array("","","","","",""), -"today" => "اليوم", -"yesterday" => "يوم أمس", -"_%n day go_::_%n days ago_" => array("","","","","",""), -"last month" => "الشهر الماضي", -"_%n month ago_::_%n months ago_" => array("","","","","",""), -"last year" => "السنةالماضية", -"years ago" => "سنة مضت", -"Could not find category \"%s\"" => "تعذر العثور على المجلد \"%s\"" -); -$PLURAL_FORMS = "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"; diff --git a/lib/l10n/be.php b/lib/l10n/be.php deleted file mode 100644 index 1570411eb86..00000000000 --- a/lib/l10n/be.php +++ /dev/null @@ -1,8 +0,0 @@ - array("","","",""), -"_%n hour ago_::_%n hours ago_" => array("","","",""), -"_%n day go_::_%n days ago_" => array("","","",""), -"_%n month ago_::_%n months ago_" => array("","","","") -); -$PLURAL_FORMS = "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/bg_BG.php b/lib/l10n/bg_BG.php deleted file mode 100644 index b6cc949eb8a..00000000000 --- a/lib/l10n/bg_BG.php +++ /dev/null @@ -1,51 +0,0 @@ - "Помощ", -"Personal" => "Лични", -"Settings" => "Настройки", -"Users" => "Потребители", -"Admin" => "Админ", -"web services under your control" => "уеб услуги под Ваш контрол", -"ZIP download is turned off." => "Изтеглянето като ZIP е изключено.", -"Files need to be downloaded one by one." => "Файловете трябва да се изтеглят един по един.", -"Back to Files" => "Назад към файловете", -"Selected files too large to generate zip file." => "Избраните файлове са прекалено големи за генерирането на ZIP архив.", -"Application is not enabled" => "Приложението не е включено.", -"Authentication error" => "Възникна проблем с идентификацията", -"Token expired. Please reload page." => "Ключът е изтекъл, моля презаредете страницата", -"Files" => "Файлове", -"Text" => "Текст", -"Images" => "Снимки", -"%s enter the database username." => "%s въведете потребителско име за базата с данни.", -"%s enter the database name." => "%s въведете име на базата с данни.", -"%s you may not use dots in the database name" => "%s, не можете да ползвате точки в името на базата от данни", -"MS SQL username and/or password not valid: %s" => "Невалидно MS SQL потребителско име и/или парола: %s", -"You need to enter either an existing account or the administrator." => "Необходимо е да влезете в всъществуващ акаунт или като администратора", -"MySQL username and/or password not valid" => "Невалидно MySQL потребителско име и/или парола", -"DB Error: \"%s\"" => "Грешка в базата от данни: \"%s\"", -"Offending command was: \"%s\"" => "Проблемната команда беше: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL потребителят '%s'@'localhost' вече съществува", -"Drop this user from MySQL" => "Изтриване на потребителя от MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL потребителят '%s'@'%%' вече съществува.", -"Drop this user from MySQL." => "Изтриване на потребителя от MySQL.", -"Oracle connection could not be established" => "Oracle връзка не можа да се осъществи", -"Oracle username and/or password not valid" => "Невалидно Oracle потребителско име и/или парола", -"Offending command was: \"%s\", name: %s, password: %s" => "Проблемната команда беше: \"%s\", име: %s, парола: %s", -"PostgreSQL username and/or password not valid" => "Невалидно PostgreSQL потребителско име и/или парола", -"Set an admin username." => "Въведете потребителско име за администратор.", -"Set an admin password." => "Въведете парола за администратор.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Вашият web сървър все още не е удачно настроен да позволява синхронизация на файлове, защото WebDAV интерфейсът изглежда не работи.", -"Please double check the installation guides." => "Моля направете повторна справка с ръководството за инсталиране.", -"seconds ago" => "преди секунди", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "днес", -"yesterday" => "вчера", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "последният месец", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "последната година", -"years ago" => "последните години", -"Could not find category \"%s\"" => "Невъзможно откриване на категорията \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/bn_BD.php b/lib/l10n/bn_BD.php deleted file mode 100644 index a42435a2a47..00000000000 --- a/lib/l10n/bn_BD.php +++ /dev/null @@ -1,29 +0,0 @@ - "সহায়িকা", -"Personal" => "ব্যক্তিগত", -"Settings" => "নিয়ামকসমূহ", -"Users" => "ব্যবহারকারী", -"Admin" => "প্রশাসন", -"web services under your control" => "ওয়েব সার্ভিস আপনার হাতের মুঠোয়", -"ZIP download is turned off." => "ZIP ডাউনলোড বন্ধ করা আছে।", -"Files need to be downloaded one by one." => "ফাইলগুলো একে একে ডাউনলোড করা আবশ্যক।", -"Back to Files" => "ফাইলে ফিরে চল", -"Selected files too large to generate zip file." => "নির্বাচিত ফাইলগুলো এতই বৃহৎ যে জিপ ফাইল তৈরী করা সম্ভব নয়।", -"Application is not enabled" => "অ্যাপ্লিকেসনটি সক্রিয় নয়", -"Authentication error" => "অনুমোদন ঘটিত সমস্যা", -"Token expired. Please reload page." => "টোকেন মেয়াদোত্তীর্ণ। দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।", -"Files" => "ফাইল", -"Text" => "টেক্সট", -"seconds ago" => "সেকেন্ড পূর্বে", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "আজ", -"yesterday" => "গতকাল", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "গত মাস", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "গত বছর", -"years ago" => "বছর পূর্বে" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/bs.php b/lib/l10n/bs.php deleted file mode 100644 index 3cb98906e62..00000000000 --- a/lib/l10n/bs.php +++ /dev/null @@ -1,8 +0,0 @@ - array("","",""), -"_%n hour ago_::_%n hours ago_" => array("","",""), -"_%n day go_::_%n days ago_" => array("","",""), -"_%n month ago_::_%n months ago_" => array("","","") -); -$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/ca.php b/lib/l10n/ca.php deleted file mode 100644 index a8769224705..00000000000 --- a/lib/l10n/ca.php +++ /dev/null @@ -1,72 +0,0 @@ - "L'aplicació \"%s\" no es pot instal·lar perquè no és compatible amb aquesta versió d'ownCloud.", -"No app name specified" => "No heu especificat cap nom d'aplicació", -"Help" => "Ajuda", -"Personal" => "Personal", -"Settings" => "Configuració", -"Users" => "Usuaris", -"Admin" => "Administració", -"Failed to upgrade \"%s\"." => "Ha fallat l'actualització \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Les imatges de perfil personals encara no funcionen amb encriptació", -"Unknown filetype" => "Tipus de fitxer desconegut", -"Invalid image" => "Imatge no vàlida", -"web services under your control" => "controleu els vostres serveis web", -"cannot open \"%s\"" => "no es pot obrir \"%s\"", -"ZIP download is turned off." => "La baixada en ZIP està desactivada.", -"Files need to be downloaded one by one." => "Els fitxers s'han de baixar d'un en un.", -"Back to Files" => "Torna a Fitxers", -"Selected files too large to generate zip file." => "Els fitxers seleccionats son massa grans per generar un fitxer zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Baixeu els fitxers en trossos petits, de forma separada, o pregunteu a l'administrador.", -"No source specified when installing app" => "No heu especificat la font en instal·lar l'aplicació", -"No href specified when installing app from http" => "No heu especificat href en instal·lar l'aplicació des de http", -"No path specified when installing app from local file" => "No heu seleccionat el camí en instal·lar una aplicació des d'un fitxer local", -"Archives of type %s are not supported" => "Els fitxers del tipus %s no són compatibles", -"Failed to open archive when installing app" => "Ha fallat l'obertura del fitxer en instal·lar l'aplicació", -"App does not provide an info.xml file" => "L'aplicació no proporciona un fitxer info.xml", -"App can't be installed because of not allowed code in the App" => "L'aplicació no es pot instal·lar perquè hi ha codi no autoritzat en l'aplicació", -"App can't be installed because it is not compatible with this version of ownCloud" => "L'aplicació no es pot instal·lar perquè no és compatible amb aquesta versió d'ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "L'aplicació no es pot instal·lar perquè conté l'etiqueta vertader que no es permet per aplicacions no enviades", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "L'aplicació no es pot instal·lar perquè la versió a info.xml/version no és la mateixa que la versió indicada des de la botiga d'aplicacions", -"App directory already exists" => "La carpeta de l'aplicació ja existeix", -"Can't create app folder. Please fix permissions. %s" => "No es pot crear la carpeta de l'aplicació. Arregleu els permisos. %s", -"Application is not enabled" => "L'aplicació no està habilitada", -"Authentication error" => "Error d'autenticació", -"Token expired. Please reload page." => "El testimoni ha expirat. Torneu a carregar la pàgina.", -"Files" => "Fitxers", -"Text" => "Text", -"Images" => "Imatges", -"%s enter the database username." => "%s escriviu el nom d'usuari de la base de dades.", -"%s enter the database name." => "%s escriviu el nom de la base de dades.", -"%s you may not use dots in the database name" => "%s no podeu usar punts en el nom de la base de dades", -"MS SQL username and/or password not valid: %s" => "Nom d'usuari i/o contrasenya MS SQL no vàlids: %s", -"You need to enter either an existing account or the administrator." => "Heu d'escriure un compte existent o el d'administrador.", -"MySQL username and/or password not valid" => "Nom d'usuari i/o contrasenya MySQL no vàlids", -"DB Error: \"%s\"" => "Error DB: \"%s\"", -"Offending command was: \"%s\"" => "L'ordre en conflicte és: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "L'usuari MySQL '%s'@'localhost' ja existeix.", -"Drop this user from MySQL" => "Elimina aquest usuari de MySQL", -"MySQL user '%s'@'%%' already exists" => "L'usuari MySQL '%s'@'%%' ja existeix", -"Drop this user from MySQL." => "Elimina aquest usuari de MySQL.", -"Oracle connection could not be established" => "No s'ha pogut establir la connexió Oracle", -"Oracle username and/or password not valid" => "Nom d'usuari i/o contrasenya Oracle no vàlids", -"Offending command was: \"%s\", name: %s, password: %s" => "L'ordre en conflicte és: \"%s\", nom: %s, contrasenya: %s", -"PostgreSQL username and/or password not valid" => "Nom d'usuari i/o contrasenya PostgreSQL no vàlids", -"Set an admin username." => "Establiu un nom d'usuari per l'administrador.", -"Set an admin password." => "Establiu una contrasenya per l'administrador.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "El servidor web no està configurat correctament per permetre la sincronització de fitxers perquè la interfície WebDAV sembla no funcionar correctament.", -"Please double check the installation guides." => "Comproveu les guies d'instal·lació.", -"seconds ago" => "segons enrere", -"_%n minute ago_::_%n minutes ago_" => array("fa %n minut","fa %n minuts"), -"_%n hour ago_::_%n hours ago_" => array("fa %n hora","fa %n hores"), -"today" => "avui", -"yesterday" => "ahir", -"_%n day go_::_%n days ago_" => array("fa %n dia","fa %n dies"), -"last month" => "el mes passat", -"_%n month ago_::_%n months ago_" => array("fa %n mes","fa %n mesos"), -"last year" => "l'any passat", -"years ago" => "anys enrere", -"Caused by:" => "Provocat per:", -"Could not find category \"%s\"" => "No s'ha trobat la categoria \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/cs_CZ.php b/lib/l10n/cs_CZ.php deleted file mode 100644 index ed31ae79529..00000000000 --- a/lib/l10n/cs_CZ.php +++ /dev/null @@ -1,72 +0,0 @@ - "Aplikace \"%s\" nemůže být nainstalována, protože není kompatibilní s touto verzí ownCloud.", -"No app name specified" => "Nebyl zadan název aplikace", -"Help" => "Nápověda", -"Personal" => "Osobní", -"Settings" => "Nastavení", -"Users" => "Uživatelé", -"Admin" => "Administrace", -"Failed to upgrade \"%s\"." => "Selhala aktualizace verze \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Vlastní profilové obrázky zatím nefungují v kombinaci se šifrováním", -"Unknown filetype" => "Neznámý typ souboru", -"Invalid image" => "Chybný obrázek", -"web services under your control" => "webové služby pod Vaší kontrolou", -"cannot open \"%s\"" => "nelze otevřít \"%s\"", -"ZIP download is turned off." => "Stahování v ZIPu je vypnuto.", -"Files need to be downloaded one by one." => "Soubory musí být stahovány jednotlivě.", -"Back to Files" => "Zpět k souborům", -"Selected files too large to generate zip file." => "Vybrané soubory jsou příliš velké pro vytvoření ZIP souboru.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Stáhněte soubory po menších částech, samostatně, nebo se obraťte na správce.", -"No source specified when installing app" => "Nebyl zadán zdroj při instalaci aplikace", -"No href specified when installing app from http" => "Nebyl zadán odkaz pro instalaci aplikace z HTTP", -"No path specified when installing app from local file" => "Nebyla zadána cesta pro instalaci aplikace z místního souboru", -"Archives of type %s are not supported" => "Archivy typu %s nejsou podporovány", -"Failed to open archive when installing app" => "Chyba při otevírání archivu během instalace aplikace", -"App does not provide an info.xml file" => "Aplikace neposkytuje soubor info.xml", -"App can't be installed because of not allowed code in the App" => "Aplikace nemůže být nainstalována, protože obsahuje nepovolený kód", -"App can't be installed because it is not compatible with this version of ownCloud" => "Aplikace nemůže být nainstalována, protože není kompatibilní s touto verzí ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Aplikace nemůže být nainstalována, protože obsahuje značku\n\n\ntrue\n\n\ncož není povoleno pro nedodávané aplikace", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Aplikace nemůže být nainstalována, protože verze uvedená v info.xml/version nesouhlasí s verzí oznámenou z úložiště aplikací.", -"App directory already exists" => "Adresář aplikace již existuje", -"Can't create app folder. Please fix permissions. %s" => "Nelze vytvořit složku aplikace. Opravte práva souborů. %s", -"Application is not enabled" => "Aplikace není povolena", -"Authentication error" => "Chyba ověření", -"Token expired. Please reload page." => "Token vypršel. Obnovte prosím stránku.", -"Files" => "Soubory", -"Text" => "Text", -"Images" => "Obrázky", -"%s enter the database username." => "Zadejte uživatelské jméno %s databáze.", -"%s enter the database name." => "Zadejte název databáze pro %s databáze.", -"%s you may not use dots in the database name" => "V názvu databáze %s nesmíte používat tečky.", -"MS SQL username and/or password not valid: %s" => "Uživatelské jméno či heslo MSSQL není platné: %s", -"You need to enter either an existing account or the administrator." => "Musíte zadat existující účet či správce.", -"MySQL username and/or password not valid" => "Uživatelské jméno či heslo MySQL není platné", -"DB Error: \"%s\"" => "Chyba databáze: \"%s\"", -"Offending command was: \"%s\"" => "Příslušný příkaz byl: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Uživatel '%s'@'localhost' již v MySQL existuje.", -"Drop this user from MySQL" => "Zrušte tohoto uživatele z MySQL", -"MySQL user '%s'@'%%' already exists" => "Uživatel '%s'@'%%' již v MySQL existuje", -"Drop this user from MySQL." => "Zrušte tohoto uživatele z MySQL", -"Oracle connection could not be established" => "Spojení s Oracle nemohlo být navázáno", -"Oracle username and/or password not valid" => "Uživatelské jméno či heslo Oracle není platné", -"Offending command was: \"%s\", name: %s, password: %s" => "Příslušný příkaz byl: \"%s\", jméno: %s, heslo: %s", -"PostgreSQL username and/or password not valid" => "Uživatelské jméno či heslo PostgreSQL není platné", -"Set an admin username." => "Zadejte uživatelské jméno správce.", -"Set an admin password." => "Zadejte heslo správce.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Váš webový server není správně nastaven pro umožnění synchronizace, rozhraní WebDAV se zdá být rozbité.", -"Please double check the installation guides." => "Zkonzultujte, prosím, průvodce instalací.", -"seconds ago" => "před pár sekundami", -"_%n minute ago_::_%n minutes ago_" => array("před %n minutou","před %n minutami","před %n minutami"), -"_%n hour ago_::_%n hours ago_" => array("před %n hodinou","před %n hodinami","před %n hodinami"), -"today" => "dnes", -"yesterday" => "včera", -"_%n day go_::_%n days ago_" => array("před %n dnem","před %n dny","před %n dny"), -"last month" => "minulý měsíc", -"_%n month ago_::_%n months ago_" => array("před %n měsícem","před %n měsíci","před %n měsíci"), -"last year" => "minulý rok", -"years ago" => "před lety", -"Caused by:" => "Příčina:", -"Could not find category \"%s\"" => "Nelze nalézt kategorii \"%s\"" -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/lib/l10n/cy_GB.php b/lib/l10n/cy_GB.php deleted file mode 100644 index 6973b51878f..00000000000 --- a/lib/l10n/cy_GB.php +++ /dev/null @@ -1,50 +0,0 @@ - "Cymorth", -"Personal" => "Personol", -"Settings" => "Gosodiadau", -"Users" => "Defnyddwyr", -"Admin" => "Gweinyddu", -"web services under your control" => "gwasanaethau gwe a reolir gennych", -"ZIP download is turned off." => "Mae llwytho ZIP wedi ei ddiffodd.", -"Files need to be downloaded one by one." => "Mae angen llwytho ffeiliau i lawr fesul un.", -"Back to Files" => "Nôl i Ffeiliau", -"Selected files too large to generate zip file." => "Mae'r ffeiliau ddewiswyd yn rhy fawr i gynhyrchu ffeil zip.", -"Application is not enabled" => "Nid yw'r pecyn wedi'i alluogi", -"Authentication error" => "Gwall dilysu", -"Token expired. Please reload page." => "Tocyn wedi dod i ben. Ail-lwythwch y dudalen.", -"Files" => "Ffeiliau", -"Text" => "Testun", -"Images" => "Delweddau", -"%s enter the database username." => "%s rhowch enw defnyddiwr y gronfa ddata.", -"%s enter the database name." => "%s rhowch enw'r gronfa ddata.", -"%s you may not use dots in the database name" => "%s does dim hawl defnyddio dot yn enw'r gronfa ddata", -"MS SQL username and/or password not valid: %s" => "Enw a/neu gyfrinair MS SQL annilys: %s", -"You need to enter either an existing account or the administrator." => "Rhaid i chi naill ai gyflwyno cyfrif presennol neu'r gweinyddwr.", -"MySQL username and/or password not valid" => "Enw a/neu gyfrinair MySQL annilys", -"DB Error: \"%s\"" => "Gwall DB: \"%s\"", -"Offending command was: \"%s\"" => "Y gorchymyn wnaeth beri tramgwydd oedd: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Defnyddiwr MySQL '%s'@'localhost' yn bodoli eisoes.", -"Drop this user from MySQL" => "Gollwng y defnyddiwr hwn o MySQL", -"MySQL user '%s'@'%%' already exists" => "Defnyddiwr MySQL '%s'@'%%' eisoes yn bodoli", -"Drop this user from MySQL." => "Gollwng y defnyddiwr hwn o MySQL.", -"Oracle username and/or password not valid" => "Enw a/neu gyfrinair Oracle annilys", -"Offending command was: \"%s\", name: %s, password: %s" => "Y gorchymyn wnaeth beri tramgwydd oedd: \"%s\", enw: %s, cyfrinair: %s", -"PostgreSQL username and/or password not valid" => "Enw a/neu gyfrinair PostgreSQL annilys", -"Set an admin username." => "Creu enw defnyddiwr i'r gweinyddwr.", -"Set an admin password." => "Gosod cyfrinair y gweinyddwr.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Nid yw eich gweinydd wedi'i gyflunio eto i ganiatáu cydweddu ffeiliau oherwydd bod y rhyngwyneb WebDAV wedi torri.", -"Please double check the installation guides." => "Gwiriwch y canllawiau gosod eto.", -"seconds ago" => "eiliad yn ôl", -"_%n minute ago_::_%n minutes ago_" => array("","","",""), -"_%n hour ago_::_%n hours ago_" => array("","","",""), -"today" => "heddiw", -"yesterday" => "ddoe", -"_%n day go_::_%n days ago_" => array("","","",""), -"last month" => "mis diwethaf", -"_%n month ago_::_%n months ago_" => array("","","",""), -"last year" => "y llynedd", -"years ago" => "blwyddyn yn ôl", -"Could not find category \"%s\"" => "Methu canfod categori \"%s\"" -); -$PLURAL_FORMS = "nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"; diff --git a/lib/l10n/da.php b/lib/l10n/da.php deleted file mode 100644 index 05a43f42ed9..00000000000 --- a/lib/l10n/da.php +++ /dev/null @@ -1,72 +0,0 @@ - "App'en \"%s\" kan ikke blive installeret, da den ikke er kompatibel med denne version af ownCloud.", -"No app name specified" => "Intet app-navn angivet", -"Help" => "Hjælp", -"Personal" => "Personligt", -"Settings" => "Indstillinger", -"Users" => "Brugere", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Upgradering af \"%s\" fejlede", -"Custom profile pictures don't work with encryption yet" => "Personligt profilbillede virker endnu ikke sammen med kryptering", -"Unknown filetype" => "Ukendt filtype", -"Invalid image" => "Ugyldigt billede", -"web services under your control" => "Webtjenester under din kontrol", -"cannot open \"%s\"" => "Kan ikke åbne \"%s\"", -"ZIP download is turned off." => "ZIP-download er slået fra.", -"Files need to be downloaded one by one." => "Filer skal downloades en for en.", -"Back to Files" => "Tilbage til Filer", -"Selected files too large to generate zip file." => "De markerede filer er for store til at generere en ZIP-fil.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Download filerne i små bider, seperat, eller kontakt venligst din administrator.", -"No source specified when installing app" => "Ingen kilde angivet under installation af app", -"No href specified when installing app from http" => "Ingen href angivet under installation af app via http", -"No path specified when installing app from local file" => "Ingen sti angivet under installation af app fra lokal fil", -"Archives of type %s are not supported" => "Arkiver af type %s understøttes ikke", -"Failed to open archive when installing app" => "Kunne ikke åbne arkiv under installation af appen", -"App does not provide an info.xml file" => "Der følger ingen info.xml-fil med appen", -"App can't be installed because of not allowed code in the App" => "Appen kan ikke installeres, da den indeholder ikke-tilladt kode", -"App can't be installed because it is not compatible with this version of ownCloud" => "Appen kan ikke installeres, da den ikke er kompatibel med denne version af ownCloud.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Appen kan ikke installeres, da den indeholder taget\n\n\ntrue\n\n\nhvilket ikke er tilladt for ikke-medfølgende apps", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "App kan ikke installeres, da versionen i info.xml/version ikke er den samme som versionen rapporteret fra app-storen", -"App directory already exists" => "App-mappe findes allerede", -"Can't create app folder. Please fix permissions. %s" => "Kan ikke oprette app-mappe. Ret tilladelser. %s", -"Application is not enabled" => "Programmet er ikke aktiveret", -"Authentication error" => "Adgangsfejl", -"Token expired. Please reload page." => "Adgang er udløbet. Genindlæs siden.", -"Files" => "Filer", -"Text" => "SMS", -"Images" => "Billeder", -"%s enter the database username." => "%s indtast database brugernavnet.", -"%s enter the database name." => "%s indtast database navnet.", -"%s you may not use dots in the database name" => "%s du må ikke bruge punktummer i databasenavnet.", -"MS SQL username and/or password not valid: %s" => "MS SQL brugernavn og/eller adgangskode ikke er gyldigt: %s", -"You need to enter either an existing account or the administrator." => "Du bliver nødt til at indtaste en eksisterende bruger eller en administrator.", -"MySQL username and/or password not valid" => "MySQL brugernavn og/eller kodeord er ikke gyldigt.", -"DB Error: \"%s\"" => "Databasefejl: \"%s\"", -"Offending command was: \"%s\"" => "Fejlende kommando var: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL brugeren '%s'@'localhost' eksisterer allerede.", -"Drop this user from MySQL" => "Slet denne bruger fra MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL brugeren '%s'@'%%' eksisterer allerede.", -"Drop this user from MySQL." => "Slet denne bruger fra MySQL", -"Oracle connection could not be established" => "Oracle forbindelsen kunne ikke etableres", -"Oracle username and/or password not valid" => "Oracle brugernavn og/eller kodeord er ikke gyldigt.", -"Offending command was: \"%s\", name: %s, password: %s" => "Fejlende kommando var: \"%s\", navn: %s, password: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.", -"Set an admin username." => "Angiv et admin brugernavn.", -"Set an admin password." => "Angiv et admin kodeord.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din webserver er endnu ikke sat op til at tillade fil synkronisering fordi WebDAV grænsefladen virker ødelagt.", -"Please double check the installation guides." => "Dobbelttjek venligst installations vejledningerne.", -"seconds ago" => "sekunder siden", -"_%n minute ago_::_%n minutes ago_" => array("%n minut siden","%n minutter siden"), -"_%n hour ago_::_%n hours ago_" => array("%n time siden","%n timer siden"), -"today" => "i dag", -"yesterday" => "i går", -"_%n day go_::_%n days ago_" => array("%n dag siden","%n dage siden"), -"last month" => "sidste måned", -"_%n month ago_::_%n months ago_" => array("%n måned siden","%n måneder siden"), -"last year" => "sidste år", -"years ago" => "år siden", -"Caused by:" => "Forårsaget af:", -"Could not find category \"%s\"" => "Kunne ikke finde kategorien \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/de.php b/lib/l10n/de.php deleted file mode 100644 index 87e7a67b47b..00000000000 --- a/lib/l10n/de.php +++ /dev/null @@ -1,72 +0,0 @@ - "Applikation \"%s\" kann nicht installiert werden, da sie mit dieser ownCloud Version nicht kompatibel ist.", -"No app name specified" => "Es wurde kein Applikation-Name angegeben", -"Help" => "Hilfe", -"Personal" => "Persönlich", -"Settings" => "Einstellungen", -"Users" => "Benutzer", -"Admin" => "Administration", -"Failed to upgrade \"%s\"." => "Konnte \"%s\" nicht aktualisieren.", -"Custom profile pictures don't work with encryption yet" => "Individuelle Profilbilder werden noch nicht von der Verschlüsselung unterstützt", -"Unknown filetype" => "Unbekannter Dateityp", -"Invalid image" => "Ungültiges Bild", -"web services under your control" => "Web-Services unter Deiner Kontrolle", -"cannot open \"%s\"" => "Öffnen von \"%s\" fehlgeschlagen", -"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.", -"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", -"Back to Files" => "Zurück zu \"Dateien\"", -"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Lade die Dateien in kleineren, separaten, Stücken herunter oder bitte deinen Administrator.", -"No source specified when installing app" => "Für die Installation der Applikation wurde keine Quelle angegeben", -"No href specified when installing app from http" => "Der Link (href) wurde nicht angegeben um die Applikation per http zu installieren", -"No path specified when installing app from local file" => "Bei der Installation der Applikation aus einer lokalen Datei wurde kein Pfad angegeben", -"Archives of type %s are not supported" => "Archive vom Typ %s werden nicht unterstützt", -"Failed to open archive when installing app" => "Das Archiv konnte bei der Installation der Applikation nicht geöffnet werden", -"App does not provide an info.xml file" => "Die Applikation enthält keine info,xml Datei", -"App can't be installed because of not allowed code in the App" => "Die Applikation kann auf Grund von unerlaubten Code nicht installiert werden", -"App can't be installed because it is not compatible with this version of ownCloud" => "Die Anwendung konnte nicht installiert werden, weil Sie nicht mit dieser Version von ownCloud kompatibel ist.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Die Applikation konnte nicht installiert werden, da diese das true Tag beinhaltet und dieses, bei nicht mitausgelieferten Applikationen, nicht erlaubt ist ist", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Die Applikation konnte nicht installiert werden, da die Version in der info.xml nicht die gleiche Version wie im App-Store ist", -"App directory already exists" => "Das Applikationsverzeichnis existiert bereits", -"Can't create app folder. Please fix permissions. %s" => "Es kann kein Applikationsordner erstellt werden. Bitte passen sie die Berechtigungen an. %s", -"Application is not enabled" => "Die Anwendung ist nicht aktiviert", -"Authentication error" => "Fehler bei der Anmeldung", -"Token expired. Please reload page." => "Token abgelaufen. Bitte lade die Seite neu.", -"Files" => "Dateien", -"Text" => "Text", -"Images" => "Bilder", -"%s enter the database username." => "%s gib den Datenbank-Benutzernamen an.", -"%s enter the database name." => "%s gib den Datenbank-Namen an.", -"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten", -"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Password ungültig: %s", -"You need to enter either an existing account or the administrator." => "Du musst entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.", -"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig", -"DB Error: \"%s\"" => "DB Fehler: \"%s\"", -"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL Benutzer '%s'@'localhost' existiert bereits.", -"Drop this user from MySQL" => "Lösche diesen Benutzer von MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits", -"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.", -"Oracle connection could not be established" => "Es konnte keine Verbindung zur Oracle-Datenbank hergestellt werden", -"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig", -"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig", -"Set an admin username." => "Setze Administrator Benutzername.", -"Set an admin password." => "Setze Administrator Passwort", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Dein Web-Server ist noch nicht für Datei-Synchronisation bereit, weil die WebDAV-Schnittstelle vermutlich defekt ist.", -"Please double check the installation guides." => "Bitte prüfe die Installationsanleitungen.", -"seconds ago" => "Gerade eben", -"_%n minute ago_::_%n minutes ago_" => array("","Vor %n Minuten"), -"_%n hour ago_::_%n hours ago_" => array("","Vor %n Stunden"), -"today" => "Heute", -"yesterday" => "Gestern", -"_%n day go_::_%n days ago_" => array("","Vor %n Tagen"), -"last month" => "Letzten Monat", -"_%n month ago_::_%n months ago_" => array("","Vor %n Monaten"), -"last year" => "Letztes Jahr", -"years ago" => "Vor Jahren", -"Caused by:" => "Verursacht durch:", -"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden." -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/de_AT.php b/lib/l10n/de_AT.php deleted file mode 100644 index 15f78e0bce6..00000000000 --- a/lib/l10n/de_AT.php +++ /dev/null @@ -1,8 +0,0 @@ - array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/de_CH.php b/lib/l10n/de_CH.php deleted file mode 100644 index 33f3446a693..00000000000 --- a/lib/l10n/de_CH.php +++ /dev/null @@ -1,59 +0,0 @@ - "Anwendung \"%s\" kann nicht installiert werden, da sie mit dieser Version von ownCloud nicht kompatibel ist.", -"No app name specified" => "Kein App-Name spezifiziert", -"Help" => "Hilfe", -"Personal" => "Persönlich", -"Settings" => "Einstellungen", -"Users" => "Benutzer", -"Admin" => "Administrator", -"Failed to upgrade \"%s\"." => "Konnte \"%s\" nicht aktualisieren.", -"web services under your control" => "Web-Services unter Ihrer Kontrolle", -"cannot open \"%s\"" => "Öffnen von \"%s\" fehlgeschlagen", -"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.", -"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", -"Back to Files" => "Zurück zu \"Dateien\"", -"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu gross, um eine ZIP-Datei zu erstellen.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Laden Sie die Dateien in kleineren, separaten, Stücken herunter oder bitten Sie Ihren Administrator.", -"App can't be installed because of not allowed code in the App" => "Anwendung kann wegen nicht erlaubten Codes nicht installiert werden", -"App directory already exists" => "Anwendungsverzeichnis existiert bereits", -"Application is not enabled" => "Die Anwendung ist nicht aktiviert", -"Authentication error" => "Authentifizierungs-Fehler", -"Token expired. Please reload page." => "Token abgelaufen. Bitte laden Sie die Seite neu.", -"Files" => "Dateien", -"Text" => "Text", -"Images" => "Bilder", -"%s enter the database username." => "%s geben Sie den Datenbank-Benutzernamen an.", -"%s enter the database name." => "%s geben Sie den Datenbank-Namen an.", -"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten", -"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Passwort ungültig: %s", -"You need to enter either an existing account or the administrator." => "Sie müssen entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.", -"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig", -"DB Error: \"%s\"" => "DB Fehler: \"%s\"", -"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL Benutzer '%s'@'localhost' existiert bereits.", -"Drop this user from MySQL" => "Lösche diesen Benutzer aus MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits", -"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.", -"Oracle connection could not be established" => "Die Oracle-Verbindung konnte nicht aufgebaut werden.", -"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig", -"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig", -"Set an admin username." => "Setze Administrator Benutzername.", -"Set an admin password." => "Setze Administrator Passwort", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ihr Web-Server ist noch nicht für eine Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.", -"Please double check the installation guides." => "Bitte prüfen Sie die Installationsanleitungen.", -"seconds ago" => "Gerade eben", -"_%n minute ago_::_%n minutes ago_" => array("","Vor %n Minuten"), -"_%n hour ago_::_%n hours ago_" => array("","Vor %n Stunden"), -"today" => "Heute", -"yesterday" => "Gestern", -"_%n day go_::_%n days ago_" => array("","Vor %n Tagen"), -"last month" => "Letzten Monat", -"_%n month ago_::_%n months ago_" => array("","Vor %n Monaten"), -"last year" => "Letztes Jahr", -"years ago" => "Vor Jahren", -"Caused by:" => "Verursacht durch:", -"Could not find category \"%s\"" => "Die Kategorie «%s» konnte nicht gefunden werden." -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/de_DE.php b/lib/l10n/de_DE.php deleted file mode 100644 index 09be0eea22d..00000000000 --- a/lib/l10n/de_DE.php +++ /dev/null @@ -1,72 +0,0 @@ - "Applikation \"%s\" kann nicht installiert werden, da sie mit dieser ownCloud Version nicht kompatibel ist.", -"No app name specified" => "Es wurde kein Applikation-Name angegeben", -"Help" => "Hilfe", -"Personal" => "Persönlich", -"Settings" => "Einstellungen", -"Users" => "Benutzer", -"Admin" => "Administrator", -"Failed to upgrade \"%s\"." => "Konnte \"%s\" nicht aktualisieren.", -"Custom profile pictures don't work with encryption yet" => "Individuelle Profilbilder werden noch nicht von der Verschlüsselung unterstützt", -"Unknown filetype" => "Unbekannter Dateityp", -"Invalid image" => "Ungültiges Bild", -"web services under your control" => "Web-Services unter Ihrer Kontrolle", -"cannot open \"%s\"" => "Öffnen von \"%s\" fehlgeschlagen", -"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.", -"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", -"Back to Files" => "Zurück zu \"Dateien\"", -"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Laden Sie die Dateien in kleineren, separaten, Stücken herunter oder bitten Sie Ihren Administrator.", -"No source specified when installing app" => "Für die Installation der Applikation wurde keine Quelle angegeben", -"No href specified when installing app from http" => "Der Link (href) wurde nicht angegeben um die Applikation per http zu installieren", -"No path specified when installing app from local file" => "Bei der Installation der Applikation aus einer lokalen Datei wurde kein Pfad angegeben", -"Archives of type %s are not supported" => "Archive des Typs %s werden nicht unterstützt.", -"Failed to open archive when installing app" => "Das Archiv konnte bei der Installation der Applikation nicht geöffnet werden", -"App does not provide an info.xml file" => "Die Applikation enthält keine info,xml Datei", -"App can't be installed because of not allowed code in the App" => "Die Applikation kann auf Grund von unerlaubten Code nicht installiert werden", -"App can't be installed because it is not compatible with this version of ownCloud" => "Die Anwendung konnte nicht installiert werden, weil Sie nicht mit dieser Version von ownCloud kompatibel ist.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Die Applikation konnte nicht installiert werden, da diese das true Tag beinhaltet und dieses, bei nicht mitausgelieferten Applikationen, nicht erlaubt ist ist", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Die Applikation konnte nicht installiert werden, da die Version in der info.xml nicht die gleiche Version wie im App-Store ist", -"App directory already exists" => "Der Ordner für die Anwendung existiert bereits.", -"Can't create app folder. Please fix permissions. %s" => "Der Ordner für die Anwendung konnte nicht angelegt werden. Bitte überprüfen Sie die Ordner- und Dateirechte und passen Sie diese entsprechend an. %s", -"Application is not enabled" => "Die Anwendung ist nicht aktiviert", -"Authentication error" => "Authentifizierungs-Fehler", -"Token expired. Please reload page." => "Token abgelaufen. Bitte laden Sie die Seite neu.", -"Files" => "Dateien", -"Text" => "Text", -"Images" => "Bilder", -"%s enter the database username." => "%s geben Sie den Datenbank-Benutzernamen an.", -"%s enter the database name." => "%s geben Sie den Datenbank-Namen an.", -"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten", -"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Passwort ungültig: %s", -"You need to enter either an existing account or the administrator." => "Sie müssen entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.", -"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig", -"DB Error: \"%s\"" => "DB Fehler: \"%s\"", -"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL Benutzer '%s'@'localhost' existiert bereits.", -"Drop this user from MySQL" => "Lösche diesen Benutzer aus MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits", -"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.", -"Oracle connection could not be established" => "Die Oracle-Verbindung konnte nicht aufgebaut werden.", -"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig", -"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig", -"Set an admin username." => "Setze Administrator Benutzername.", -"Set an admin password." => "Setze Administrator Passwort", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ihr Web-Server ist noch nicht für eine Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.", -"Please double check the installation guides." => "Bitte prüfen Sie die Installationsanleitungen.", -"seconds ago" => "Gerade eben", -"_%n minute ago_::_%n minutes ago_" => array("Vor %n Minute","Vor %n Minuten"), -"_%n hour ago_::_%n hours ago_" => array("Vor %n Stunde","Vor %n Stunden"), -"today" => "Heute", -"yesterday" => "Gestern", -"_%n day go_::_%n days ago_" => array("Vor %n Tag","Vor %n Tagen"), -"last month" => "Letzten Monat", -"_%n month ago_::_%n months ago_" => array("Vor %n Monat","Vor %n Monaten"), -"last year" => "Letztes Jahr", -"years ago" => "Vor Jahren", -"Caused by:" => "Verursacht durch:", -"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden." -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/el.php b/lib/l10n/el.php deleted file mode 100644 index dcbf82d4a4b..00000000000 --- a/lib/l10n/el.php +++ /dev/null @@ -1,55 +0,0 @@ - "Βοήθεια", -"Personal" => "Προσωπικά", -"Settings" => "Ρυθμίσεις", -"Users" => "Χρήστες", -"Admin" => "Διαχειριστής", -"Failed to upgrade \"%s\"." => "Αποτυχία αναβάθμισης του \"%s\".", -"web services under your control" => "υπηρεσίες δικτύου υπό τον έλεγχό σας", -"cannot open \"%s\"" => "αδυναμία ανοίγματος \"%s\"", -"ZIP download is turned off." => "Η λήψη ZIP απενεργοποιήθηκε.", -"Files need to be downloaded one by one." => "Τα αρχεία πρέπει να ληφθούν ένα-ένα.", -"Back to Files" => "Πίσω στα Αρχεία", -"Selected files too large to generate zip file." => "Τα επιλεγμένα αρχεία είναι μεγάλα ώστε να δημιουργηθεί αρχείο zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Λήψη των αρχείων σε μικρότερα κομμάτια, χωριστά ή ρωτήστε τον διαχειριστή σας.", -"Application is not enabled" => "Δεν ενεργοποιήθηκε η εφαρμογή", -"Authentication error" => "Σφάλμα πιστοποίησης", -"Token expired. Please reload page." => "Το αναγνωριστικό έληξε. Παρακαλώ φορτώστε ξανά την σελίδα.", -"Files" => "Αρχεία", -"Text" => "Κείμενο", -"Images" => "Εικόνες", -"%s enter the database username." => "%s εισάγετε το όνομα χρήστη της βάσης δεδομένων.", -"%s enter the database name." => "%s εισάγετε το όνομα της βάσης δεδομένων.", -"%s you may not use dots in the database name" => "%s μάλλον δεν χρησιμοποιείτε τελείες στο όνομα της βάσης δεδομένων", -"MS SQL username and/or password not valid: %s" => "Το όνομα χρήστη και/ή ο κωδικός της MS SQL δεν είναι έγκυρα: %s", -"You need to enter either an existing account or the administrator." => "Χρειάζεται να εισάγετε είτε έναν υπάρχον λογαριασμό ή του διαχειριστή.", -"MySQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της MySQL", -"DB Error: \"%s\"" => "Σφάλμα Βάσης Δεδομένων: \"%s\"", -"Offending command was: \"%s\"" => "Η εντολη παραβατικοτητας ηταν: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Υπάρχει ήδη ο χρήστης '%s'@'localhost' της MySQL.", -"Drop this user from MySQL" => "Απόρριψη αυτού του χρήστη από την MySQL", -"MySQL user '%s'@'%%' already exists" => "Ο χρήστης '%s'@'%%' της MySQL υπάρχει ήδη", -"Drop this user from MySQL." => "Απόρριψη αυτού του χρήστη από την MySQL", -"Oracle connection could not be established" => "Αδυναμία σύνδεσης Oracle", -"Oracle username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle", -"Offending command was: \"%s\", name: %s, password: %s" => "Η εντολη παραβατικοτητας ηταν: \"%s\", ονομα: %s, κωδικος: %s", -"PostgreSQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της PostgreSQL", -"Set an admin username." => "Εισάγετε όνομα χρήστη διαχειριστή.", -"Set an admin password." => "Εισάγετε συνθηματικό διαχειριστή.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ο διακομιστής σας δεν έχει ρυθμιστεί κατάλληλα ώστε να επιτρέπει τον συγχρονισμό αρχείων γιατί η διεπαφή WebDAV πιθανόν να είναι κατεστραμμένη.", -"Please double check the installation guides." => "Ελέγξτε ξανά τις οδηγίες εγκατάστασης.", -"seconds ago" => "δευτερόλεπτα πριν", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "σήμερα", -"yesterday" => "χτες", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "τελευταίο μήνα", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "τελευταίο χρόνο", -"years ago" => "χρόνια πριν", -"Caused by:" => "Προκλήθηκε από:", -"Could not find category \"%s\"" => "Αδυναμία εύρεσης κατηγορίας \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/en@pirate.php b/lib/l10n/en@pirate.php deleted file mode 100644 index a8175b1400f..00000000000 --- a/lib/l10n/en@pirate.php +++ /dev/null @@ -1,9 +0,0 @@ - "web services under your control", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/en_GB.php b/lib/l10n/en_GB.php deleted file mode 100644 index d02f553eda8..00000000000 --- a/lib/l10n/en_GB.php +++ /dev/null @@ -1,72 +0,0 @@ - "App \"%s\" can't be installed because it is not compatible with this version of ownCloud.", -"No app name specified" => "No app name specified", -"Help" => "Help", -"Personal" => "Personal", -"Settings" => "Settings", -"Users" => "Users", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Failed to upgrade \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Custom profile pictures don't work with encryption yet", -"Unknown filetype" => "Unknown filetype", -"Invalid image" => "Invalid image", -"web services under your control" => "web services under your control", -"cannot open \"%s\"" => "cannot open \"%s\"", -"ZIP download is turned off." => "ZIP download is turned off.", -"Files need to be downloaded one by one." => "Files need to be downloaded one by one.", -"Back to Files" => "Back to Files", -"Selected files too large to generate zip file." => "Selected files too large to generate zip file.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Download the files in smaller chunks, seperately or kindly ask your administrator.", -"No source specified when installing app" => "No source specified when installing app", -"No href specified when installing app from http" => "No href specified when installing app from http", -"No path specified when installing app from local file" => "No path specified when installing app from local file", -"Archives of type %s are not supported" => "Archives of type %s are not supported", -"Failed to open archive when installing app" => "Failed to open archive when installing app", -"App does not provide an info.xml file" => "App does not provide an info.xml file", -"App can't be installed because of not allowed code in the App" => "App can't be installed because of unallowed code in the App", -"App can't be installed because it is not compatible with this version of ownCloud" => "App can't be installed because it is not compatible with this version of ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "App can't be installed because it contains the true tag which is not allowed for non shipped apps", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "App can't be installed because the version in info.xml/version is not the same as the version reported from the app store", -"App directory already exists" => "App directory already exists", -"Can't create app folder. Please fix permissions. %s" => "Can't create app folder. Please fix permissions. %s", -"Application is not enabled" => "Application is not enabled", -"Authentication error" => "Authentication error", -"Token expired. Please reload page." => "Token expired. Please reload page.", -"Files" => "Files", -"Text" => "Text", -"Images" => "Images", -"%s enter the database username." => "%s enter the database username.", -"%s enter the database name." => "%s enter the database name.", -"%s you may not use dots in the database name" => "%s you may not use dots in the database name", -"MS SQL username and/or password not valid: %s" => "MS SQL username and/or password not valid: %s", -"You need to enter either an existing account or the administrator." => "You need to enter either an existing account or the administrator.", -"MySQL username and/or password not valid" => "MySQL username and/or password not valid", -"DB Error: \"%s\"" => "DB Error: \"%s\"", -"Offending command was: \"%s\"" => "Offending command was: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL user '%s'@'localhost' exists already.", -"Drop this user from MySQL" => "Drop this user from MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL user '%s'@'%%' already exists", -"Drop this user from MySQL." => "Drop this user from MySQL.", -"Oracle connection could not be established" => "Oracle connection could not be established", -"Oracle username and/or password not valid" => "Oracle username and/or password not valid", -"Offending command was: \"%s\", name: %s, password: %s" => "Offending command was: \"%s\", name: %s, password: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL username and/or password not valid", -"Set an admin username." => "Set an admin username.", -"Set an admin password." => "Set an admin password.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Your web server is not yet properly setup to allow files synchronisation because the WebDAV interface seems to be broken.", -"Please double check the installation guides." => "Please double check the installation guides.", -"seconds ago" => "seconds ago", -"_%n minute ago_::_%n minutes ago_" => array("%n minute ago","%n minutes ago"), -"_%n hour ago_::_%n hours ago_" => array("%n hour ago","%n hours ago"), -"today" => "today", -"yesterday" => "yesterday", -"_%n day go_::_%n days ago_" => array("%n day go","%n days ago"), -"last month" => "last month", -"_%n month ago_::_%n months ago_" => array("%n month ago","%n months ago"), -"last year" => "last year", -"years ago" => "years ago", -"Caused by:" => "Caused by:", -"Could not find category \"%s\"" => "Could not find category \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/eo.php b/lib/l10n/eo.php deleted file mode 100644 index 5311dd6eb15..00000000000 --- a/lib/l10n/eo.php +++ /dev/null @@ -1,48 +0,0 @@ - "Helpo", -"Personal" => "Persona", -"Settings" => "Agordo", -"Users" => "Uzantoj", -"Admin" => "Administranto", -"web services under your control" => "TTT-servoj regataj de vi", -"ZIP download is turned off." => "ZIP-elŝuto estas malkapabligita.", -"Files need to be downloaded one by one." => "Dosieroj devas elŝutiĝi unuope.", -"Back to Files" => "Reen al la dosieroj", -"Selected files too large to generate zip file." => "La elektitaj dosieroj tro grandas por genero de ZIP-dosiero.", -"Application is not enabled" => "La aplikaĵo ne estas kapabligita", -"Authentication error" => "Aŭtentiga eraro", -"Token expired. Please reload page." => "Ĵetono eksvalidiĝis. Bonvolu reŝargi la paĝon.", -"Files" => "Dosieroj", -"Text" => "Teksto", -"Images" => "Bildoj", -"%s enter the database username." => "%s enigu la uzantonomon de la datumbazo.", -"%s enter the database name." => "%s enigu la nomon de la datumbazo.", -"%s you may not use dots in the database name" => "%s vi ne povas uzi punktojn en la nomo de la datumbazo", -"MS SQL username and/or password not valid: %s" => "La uzantonomo de MS SQL aŭ la pasvorto ne validas: %s", -"MySQL username and/or password not valid" => "La uzantonomo de MySQL aŭ la pasvorto ne validas", -"DB Error: \"%s\"" => "Datumbaza eraro: “%s”", -"MySQL user '%s'@'localhost' exists already." => "La uzanto de MySQL “%s”@“localhost” jam ekzistas.", -"Drop this user from MySQL" => "Forigi ĉi tiun uzanton el MySQL", -"MySQL user '%s'@'%%' already exists" => "La uzanto de MySQL “%s”@“%%” jam ekzistas", -"Drop this user from MySQL." => "Forigi ĉi tiun uzanton el MySQL.", -"Oracle connection could not be established" => "Konekto al Oracle ne povas stariĝi", -"Oracle username and/or password not valid" => "La uzantonomo de Oracle aŭ la pasvorto ne validas", -"PostgreSQL username and/or password not valid" => "La uzantonomo de PostgreSQL aŭ la pasvorto ne validas", -"Set an admin username." => "Starigi administran uzantonomon.", -"Set an admin password." => "Starigi administran pasvorton.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Via TTT-servilo ankoraŭ ne ĝuste agordiĝis por permesi sinkronigi dosierojn ĉar la WebDAV-interfaco ŝajnas rompita.", -"Please double check the installation guides." => "Bonvolu duoble kontroli la gvidilon por instalo.", -"seconds ago" => "sekundoj antaŭe", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "hodiaŭ", -"yesterday" => "hieraŭ", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "lastamonate", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "lastajare", -"years ago" => "jaroj antaŭe", -"Could not find category \"%s\"" => "Ne troviĝis kategorio “%s”" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/es.php b/lib/l10n/es.php deleted file mode 100644 index 047d5d955bb..00000000000 --- a/lib/l10n/es.php +++ /dev/null @@ -1,69 +0,0 @@ - "La aplicación \"%s\" no puede ser instalada porque no es compatible con esta versión de ownCloud", -"No app name specified" => "No se ha especificado nombre de la aplicación", -"Help" => "Ayuda", -"Personal" => "Personal", -"Settings" => "Ajustes", -"Users" => "Usuarios", -"Admin" => "Administración", -"Failed to upgrade \"%s\"." => "Falló la actualización \"%s\".", -"web services under your control" => "Servicios web bajo su control", -"cannot open \"%s\"" => "No se puede abrir \"%s\"", -"ZIP download is turned off." => "La descarga en ZIP está desactivada.", -"Files need to be downloaded one by one." => "Los archivos deben ser descargados uno por uno.", -"Back to Files" => "Volver a Archivos", -"Selected files too large to generate zip file." => "Los archivos seleccionados son demasiado grandes para generar el archivo zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descargue los archivos en trozos más pequeños, por separado o solicítelos amablemente su administrador.", -"No source specified when installing app" => "No se ha especificado origen cuando se ha instalado la aplicación", -"No href specified when installing app from http" => "No href especificado cuando se ha instalado la aplicación", -"No path specified when installing app from local file" => "Sin path especificado cuando se ha instalado la aplicación desde el fichero local", -"Archives of type %s are not supported" => "Ficheros de tipo %s no son soportados", -"Failed to open archive when installing app" => "Fallo de apertura de fichero mientras se instala la aplicación", -"App does not provide an info.xml file" => "La aplicación no suministra un fichero info.xml", -"App can't be installed because of not allowed code in the App" => "La aplicación no puede ser instalada por tener código no autorizado en la aplicación", -"App can't be installed because it is not compatible with this version of ownCloud" => "La aplicación no se puede instalar porque no es compatible con esta versión de ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "La aplicación no se puede instalar porque contiene la etiqueta\n\ntrue\n\nque no está permitida para aplicaciones no distribuidas", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "La aplicación no puede ser instalada por que la versión en info.xml/version no es la misma que la establecida en la app store", -"App directory already exists" => "El directorio de la aplicación ya existe", -"Can't create app folder. Please fix permissions. %s" => "No se puede crear la carpeta de la aplicación. Corrija los permisos. %s", -"Application is not enabled" => "La aplicación no está habilitada", -"Authentication error" => "Error de autenticación", -"Token expired. Please reload page." => "Token expirado. Por favor, recarga la página.", -"Files" => "Archivos", -"Text" => "Texto", -"Images" => "Imágenes", -"%s enter the database username." => "%s ingresar el usuario de la base de datos.", -"%s enter the database name." => "%s ingresar el nombre de la base de datos", -"%s you may not use dots in the database name" => "%s puede utilizar puntos en el nombre de la base de datos", -"MS SQL username and/or password not valid: %s" => "Usuario y/o contraseña de MS SQL no válidos: %s", -"You need to enter either an existing account or the administrator." => "Tiene que ingresar una cuenta existente o la del administrador.", -"MySQL username and/or password not valid" => "Usuario y/o contraseña de MySQL no válidos", -"DB Error: \"%s\"" => "Error BD: \"%s\"", -"Offending command was: \"%s\"" => "Comando infractor: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Usuario MySQL '%s'@'localhost' ya existe.", -"Drop this user from MySQL" => "Eliminar este usuario de MySQL", -"MySQL user '%s'@'%%' already exists" => "Usuario MySQL '%s'@'%%' ya existe", -"Drop this user from MySQL." => "Eliminar este usuario de MySQL.", -"Oracle connection could not be established" => "No se pudo establecer la conexión a Oracle", -"Oracle username and/or password not valid" => "Usuario y/o contraseña de Oracle no válidos", -"Offending command was: \"%s\", name: %s, password: %s" => "Comando infractor: \"%s\", nombre: %s, contraseña: %s", -"PostgreSQL username and/or password not valid" => "Usuario y/o contraseña de PostgreSQL no válidos", -"Set an admin username." => "Configurar un nombre de usuario del administrador", -"Set an admin password." => "Configurar la contraseña del administrador.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Su servidor web aún no está configurado adecuadamente para permitir sincronización de archivos ya que la interfaz WebDAV parece no estar funcionando.", -"Please double check the installation guides." => "Por favor, vuelva a comprobar las guías de instalación.", -"seconds ago" => "hace segundos", -"_%n minute ago_::_%n minutes ago_" => array("Hace %n minuto","Hace %n minutos"), -"_%n hour ago_::_%n hours ago_" => array("Hace %n hora","Hace %n horas"), -"today" => "hoy", -"yesterday" => "ayer", -"_%n day go_::_%n days ago_" => array("Hace %n día","Hace %n días"), -"last month" => "mes pasado", -"_%n month ago_::_%n months ago_" => array("Hace %n mes","Hace %n meses"), -"last year" => "año pasado", -"years ago" => "hace años", -"Caused by:" => "Causado por:", -"Could not find category \"%s\"" => "No puede encontrar la categoria \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/es_AR.php b/lib/l10n/es_AR.php deleted file mode 100644 index f637eb403ed..00000000000 --- a/lib/l10n/es_AR.php +++ /dev/null @@ -1,69 +0,0 @@ - "La app \"%s\" no puede ser instalada porque no es compatible con esta versión de ownCloud", -"No app name specified" => "No fue especificado el nombre de la app", -"Help" => "Ayuda", -"Personal" => "Personal", -"Settings" => "Configuración", -"Users" => "Usuarios", -"Admin" => "Administración", -"Failed to upgrade \"%s\"." => "No se pudo actualizar \"%s\".", -"web services under your control" => "servicios web sobre los que tenés control", -"cannot open \"%s\"" => "no se puede abrir \"%s\"", -"ZIP download is turned off." => "La descarga en ZIP está desactivada.", -"Files need to be downloaded one by one." => "Los archivos deben ser descargados de a uno.", -"Back to Files" => "Volver a Archivos", -"Selected files too large to generate zip file." => "Los archivos seleccionados son demasiado grandes para generar el archivo zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descargá los archivos en partes más chicas, de forma separada, o pedíselos al administrador", -"No source specified when installing app" => "No se especificó el origen al instalar la app", -"No href specified when installing app from http" => "No se especificó href al instalar la app", -"No path specified when installing app from local file" => "No se especificó PATH al instalar la app desde el archivo local", -"Archives of type %s are not supported" => "No hay soporte para archivos de tipo %s", -"Failed to open archive when installing app" => "Error al abrir archivo mientras se instalaba la app", -"App does not provide an info.xml file" => "La app no suministra un archivo info.xml", -"App can't be installed because of not allowed code in the App" => "No puede ser instalada la app por tener código no autorizado", -"App can't be installed because it is not compatible with this version of ownCloud" => "No se puede instalar la app porque no es compatible con esta versión de ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "La app no se puede instalar porque contiene la etiqueta true que no está permitida para apps no distribuidas", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "La app no puede ser instalada porque la versión en info.xml/version no es la misma que la establecida en el app store", -"App directory already exists" => "El directorio de la app ya existe", -"Can't create app folder. Please fix permissions. %s" => "No se puede crear el directorio para la app. Corregí los permisos. %s", -"Application is not enabled" => "La aplicación no está habilitada", -"Authentication error" => "Error al autenticar", -"Token expired. Please reload page." => "Token expirado. Por favor, recargá la página.", -"Files" => "Archivos", -"Text" => "Texto", -"Images" => "Imágenes", -"%s enter the database username." => "%s Entrá el usuario de la base de datos", -"%s enter the database name." => "%s Entrá el nombre de la base de datos.", -"%s you may not use dots in the database name" => "%s no podés usar puntos en el nombre de la base de datos", -"MS SQL username and/or password not valid: %s" => "Nombre de usuario y contraseña de MS SQL no son válidas: %s", -"You need to enter either an existing account or the administrator." => "Tenés que ingresar una cuenta existente o el administrador.", -"MySQL username and/or password not valid" => "Usuario y/o contraseña MySQL no válido", -"DB Error: \"%s\"" => "Error DB: \"%s\"", -"Offending command was: \"%s\"" => "El comando no comprendido es: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Usuario MySQL '%s'@'localhost' ya existe.", -"Drop this user from MySQL" => "Borrar este usuario de MySQL", -"MySQL user '%s'@'%%' already exists" => "Usuario MySQL '%s'@'%%' ya existe", -"Drop this user from MySQL." => "Borrar este usuario de MySQL", -"Oracle connection could not be established" => "No fue posible establecer la conexión a Oracle", -"Oracle username and/or password not valid" => "El nombre de usuario y/o contraseña no son válidos", -"Offending command was: \"%s\", name: %s, password: %s" => "El comando no comprendido es: \"%s\", nombre: \"%s\", contraseña: \"%s\"", -"PostgreSQL username and/or password not valid" => "Nombre de usuario o contraseña PostgradeSQL inválido.", -"Set an admin username." => "Configurar un nombre de administrador.", -"Set an admin password." => "Configurar una contraseña de administrador.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Tu servidor web no está configurado todavía para permitir sincronización de archivos porque la interfaz WebDAV parece no funcionar.", -"Please double check the installation guides." => "Por favor, comprobá nuevamente la guía de instalación.", -"seconds ago" => "segundos atrás", -"_%n minute ago_::_%n minutes ago_" => array("Hace %n minuto","Hace %n minutos"), -"_%n hour ago_::_%n hours ago_" => array("Hace %n hora","Hace %n horas"), -"today" => "hoy", -"yesterday" => "ayer", -"_%n day go_::_%n days ago_" => array("Hace %n día","Hace %n días"), -"last month" => "el mes pasado", -"_%n month ago_::_%n months ago_" => array("Hace %n mes","Hace %n meses"), -"last year" => "el año pasado", -"years ago" => "años atrás", -"Caused by:" => "Provocado por:", -"Could not find category \"%s\"" => "No fue posible encontrar la categoría \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/es_MX.php b/lib/l10n/es_MX.php deleted file mode 100644 index 15f78e0bce6..00000000000 --- a/lib/l10n/es_MX.php +++ /dev/null @@ -1,8 +0,0 @@ - array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/et_EE.php b/lib/l10n/et_EE.php deleted file mode 100644 index 85dfaeb52d5..00000000000 --- a/lib/l10n/et_EE.php +++ /dev/null @@ -1,72 +0,0 @@ - "Rakendit \"%s\" ei saa paigaldada, kuna see pole ühilduv selle ownCloud versiooniga.", -"No app name specified" => "Ühegi rakendi nime pole määratletud", -"Help" => "Abiinfo", -"Personal" => "Isiklik", -"Settings" => "Seaded", -"Users" => "Kasutajad", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Ebaõnnestunud uuendus \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Kohandatud profiili pildid ei toimi veel koos krüpteeringuga", -"Unknown filetype" => "Tundmatu failitüüp", -"Invalid image" => "Vigane pilt", -"web services under your control" => "veebitenused sinu kontrolli all", -"cannot open \"%s\"" => "ei suuda avada \"%s\"", -"ZIP download is turned off." => "ZIP-ina allalaadimine on välja lülitatud.", -"Files need to be downloaded one by one." => "Failid tuleb alla laadida ükshaaval.", -"Back to Files" => "Tagasi failide juurde", -"Selected files too large to generate zip file." => "Valitud failid on ZIP-faili loomiseks liiga suured.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Laadi failid alla eraldi väiksemate osadena või küsi nõu oma süsteemiadminstraatorilt.", -"No source specified when installing app" => "Ühegi lähteallikat pole rakendi paigalduseks määratletud", -"No href specified when installing app from http" => "Ühtegi aadressi pole määratletud rakendi paigalduseks veebist", -"No path specified when installing app from local file" => "Ühtegi teed pole määratletud paigaldamaks rakendit kohalikust failist", -"Archives of type %s are not supported" => "%s tüüpi arhiivid pole toetatud", -"Failed to open archive when installing app" => "Arhiivi avamine ebaõnnestus rakendi paigalduse käigus", -"App does not provide an info.xml file" => "Rakend ei paku ühtegi info.xml faili", -"App can't be installed because of not allowed code in the App" => "Rakendit ei saa paigaldada, kuna sisaldab lubamatud koodi", -"App can't be installed because it is not compatible with this version of ownCloud" => "Rakendit ei saa paigaldada, kuna see pole ühilduv selle ownCloud versiooniga.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Rakendit ei saa paigaldada, kuna see sisaldab \n\n\ntrue\n\nmärgendit, mis pole lubatud mitte veetud (non shipped) rakendites", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Rakendit ei saa paigaldada, kuna selle versioon info.xml/version pole sama, mis on märgitud rakendite laos.", -"App directory already exists" => "Rakendi kataloog on juba olemas", -"Can't create app folder. Please fix permissions. %s" => "Ei saa luua rakendi kataloogi. Palun korrigeeri õigusi. %s", -"Application is not enabled" => "Rakendus pole sisse lülitatud", -"Authentication error" => "Autentimise viga", -"Token expired. Please reload page." => "Kontrollkood aegus. Paelun lae leht uuesti.", -"Files" => "Failid", -"Text" => "Tekst", -"Images" => "Pildid", -"%s enter the database username." => "%s sisesta andmebaasi kasutajatunnus.", -"%s enter the database name." => "%s sisesta andmebaasi nimi.", -"%s you may not use dots in the database name" => "%s punktide kasutamine andmebaasi nimes pole lubatud", -"MS SQL username and/or password not valid: %s" => "MS SQL kasutajatunnus ja/või parool pole õiged: %s", -"You need to enter either an existing account or the administrator." => "Sisesta kas juba olemasolev konto või administrator.", -"MySQL username and/or password not valid" => "MySQL kasutajatunnus ja/või parool pole õiged", -"DB Error: \"%s\"" => "Andmebaasi viga: \"%s\"", -"Offending command was: \"%s\"" => "Tõrkuv käsk oli: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL kasutaja '%s'@'localhost' on juba olemas.", -"Drop this user from MySQL" => "Kustuta see kasutaja MySQL-ist", -"MySQL user '%s'@'%%' already exists" => "MySQL kasutaja '%s'@'%%' on juba olemas", -"Drop this user from MySQL." => "Kustuta see kasutaja MySQL-ist.", -"Oracle connection could not be established" => "Ei suuda luua ühendust Oracle baasiga", -"Oracle username and/or password not valid" => "Oracle kasutajatunnus ja/või parool pole õiged", -"Offending command was: \"%s\", name: %s, password: %s" => "Tõrkuv käsk oli: \"%s\", nimi: %s, parool: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL kasutajatunnus ja/või parool pole õiged", -"Set an admin username." => "Määra admin kasutajanimi.", -"Set an admin password." => "Määra admini parool.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Veebiserveri ei ole veel korralikult seadistatud võimaldamaks failide sünkroniseerimist, kuna WebDAV liides näib olevat mittetoimiv.", -"Please double check the installation guides." => "Palun tutvu veelkord paigalduse juhenditega.", -"seconds ago" => "sekundit tagasi", -"_%n minute ago_::_%n minutes ago_" => array("","%n minutit tagasi"), -"_%n hour ago_::_%n hours ago_" => array("","%n tundi tagasi"), -"today" => "täna", -"yesterday" => "eile", -"_%n day go_::_%n days ago_" => array("","%n päeva tagasi"), -"last month" => "viimasel kuul", -"_%n month ago_::_%n months ago_" => array("","%n kuud tagasi"), -"last year" => "viimasel aastal", -"years ago" => "aastat tagasi", -"Caused by:" => "Põhjustaja:", -"Could not find category \"%s\"" => "Ei leia kategooriat \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/eu.php b/lib/l10n/eu.php deleted file mode 100644 index 413819f4f94..00000000000 --- a/lib/l10n/eu.php +++ /dev/null @@ -1,55 +0,0 @@ - "Laguntza", -"Personal" => "Pertsonala", -"Settings" => "Ezarpenak", -"Users" => "Erabiltzaileak", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Ezin izan da \"%s\" eguneratu.", -"web services under your control" => "web zerbitzuak zure kontrolpean", -"cannot open \"%s\"" => "ezin da \"%s\" ireki", -"ZIP download is turned off." => "ZIP deskarga ez dago gaituta.", -"Files need to be downloaded one by one." => "Fitxategiak banan-banan deskargatu behar dira.", -"Back to Files" => "Itzuli fitxategietara", -"Selected files too large to generate zip file." => "Hautatuko fitxategiak oso handiak dira zip fitxategia sortzeko.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Deskargatu fitzategiak zati txikiagoetan, banan-banan edo eskatu mesedez zure administradoreari", -"Application is not enabled" => "Aplikazioa ez dago gaituta", -"Authentication error" => "Autentifikazio errorea", -"Token expired. Please reload page." => "Tokena iraungitu da. Mesedez birkargatu orria.", -"Files" => "Fitxategiak", -"Text" => "Testua", -"Images" => "Irudiak", -"%s enter the database username." => "%s sartu datu basearen erabiltzaile izena.", -"%s enter the database name." => "%s sartu datu basearen izena.", -"%s you may not use dots in the database name" => "%s ezin duzu punturik erabili datu basearen izenean.", -"MS SQL username and/or password not valid: %s" => "MS SQL erabiltzaile izena edota pasahitza ez dira egokiak: %s", -"You need to enter either an existing account or the administrator." => "Existitzen den kontu bat edo administradorearena jarri behar duzu.", -"MySQL username and/or password not valid" => "MySQL erabiltzaile edota pasahitza ez dira egokiak.", -"DB Error: \"%s\"" => "DB errorea: \"%s\"", -"Offending command was: \"%s\"" => "Errorea komando honek sortu du: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL '%s'@'localhost' erabiltzailea dagoeneko existitzen da.", -"Drop this user from MySQL" => "Ezabatu erabiltzaile hau MySQLtik", -"MySQL user '%s'@'%%' already exists" => "MySQL '%s'@'%%' erabiltzailea dagoeneko existitzen da", -"Drop this user from MySQL." => "Ezabatu erabiltzaile hau MySQLtik.", -"Oracle connection could not be established" => "Ezin da Oracle konexioa sortu", -"Oracle username and/or password not valid" => "Oracle erabiltzaile edota pasahitza ez dira egokiak.", -"Offending command was: \"%s\", name: %s, password: %s" => "Errorea komando honek sortu du: \"%s\", izena: %s, pasahitza: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL erabiltzaile edota pasahitza ez dira egokiak.", -"Set an admin username." => "Ezarri administraziorako erabiltzaile izena.", -"Set an admin password." => "Ezarri administraziorako pasahitza.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Zure web zerbitzaria ez dago oraindik ongi konfiguratuta fitxategien sinkronizazioa egiteko, WebDAV interfazea ongi ez dagoela dirudi.", -"Please double check the installation guides." => "Mesedez begiratu instalazio gidak.", -"seconds ago" => "segundu", -"_%n minute ago_::_%n minutes ago_" => array("orain dela minutu %n","orain dela %n minutu"), -"_%n hour ago_::_%n hours ago_" => array("orain dela ordu %n","orain dela %n ordu"), -"today" => "gaur", -"yesterday" => "atzo", -"_%n day go_::_%n days ago_" => array("orain dela egun %n","orain dela %n egun"), -"last month" => "joan den hilabetean", -"_%n month ago_::_%n months ago_" => array("orain dela hilabete %n","orain dela %n hilabete"), -"last year" => "joan den urtean", -"years ago" => "urte", -"Caused by:" => "Honek eraginda:", -"Could not find category \"%s\"" => "Ezin da \"%s\" kategoria aurkitu" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/fa.php b/lib/l10n/fa.php deleted file mode 100644 index e9cb695bade..00000000000 --- a/lib/l10n/fa.php +++ /dev/null @@ -1,51 +0,0 @@ - "راه‌نما", -"Personal" => "شخصی", -"Settings" => "تنظیمات", -"Users" => "کاربران", -"Admin" => "مدیر", -"web services under your control" => "سرویس های تحت وب در کنترل شما", -"ZIP download is turned off." => "دانلود به صورت فشرده غیر فعال است", -"Files need to be downloaded one by one." => "فایل ها باید به صورت یکی یکی دانلود شوند", -"Back to Files" => "بازگشت به فایل ها", -"Selected files too large to generate zip file." => "فایل های انتخاب شده بزرگتر از آن هستند که بتوان یک فایل فشرده تولید کرد", -"Application is not enabled" => "برنامه فعال نشده است", -"Authentication error" => "خطا در اعتبار سنجی", -"Token expired. Please reload page." => "رمز منقضی شده است. لطفا دوباره صفحه را بارگذاری نمایید.", -"Files" => "پرونده‌ها", -"Text" => "متن", -"Images" => "تصاویر", -"%s enter the database username." => "%s نام کاربری پایگاه داده را وارد نمایید.", -"%s enter the database name." => "%s نام پایگاه داده را وارد نمایید.", -"%s you may not use dots in the database name" => "%s شما نباید از نقطه در نام پایگاه داده استفاده نمایید.", -"MS SQL username and/or password not valid: %s" => "نام کاربری و / یا رمزعبور MS SQL معتبر نیست: %s", -"You need to enter either an existing account or the administrator." => "شما نیاز به وارد کردن یک حساب کاربری موجود یا حساب مدیریتی دارید.", -"MySQL username and/or password not valid" => "نام کاربری و / یا رمزعبور MySQL معتبر نیست.", -"DB Error: \"%s\"" => "خطای پایگاه داده: \"%s\"", -"Offending command was: \"%s\"" => "دستور متخلف عبارت است از: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "کاربرMySQL '%s'@'localhost' درحال حاضر موجود است.", -"Drop this user from MySQL" => "این کاربر را از MySQL حذف نمایید.", -"MySQL user '%s'@'%%' already exists" => "کاربر'%s'@'%%' MySQL در حال حاضر موجود است.", -"Drop this user from MySQL." => "این کاربر را از MySQL حذف نمایید.", -"Oracle connection could not be established" => "ارتباط اراکل نمیتواند برقرار باشد.", -"Oracle username and/or password not valid" => "نام کاربری و / یا رمزعبور اراکل معتبر نیست.", -"Offending command was: \"%s\", name: %s, password: %s" => "دستور متخلف عبارت است از: \"%s\"، نام: \"%s\"، رمزعبور:\"%s\"", -"PostgreSQL username and/or password not valid" => "PostgreSQL نام کاربری و / یا رمزعبور معتبر نیست.", -"Set an admin username." => "یک نام کاربری برای مدیر تنظیم نمایید.", -"Set an admin password." => "یک رمزعبور برای مدیر تنظیم نمایید.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "احتمالاً وب سرور شما طوری تنظیم نشده است که اجازه ی همگام سازی فایلها را بدهد زیرا به نظر میرسد رابط WebDAV از کار افتاده است.", -"Please double check the installation guides." => "لطفاً دوباره راهنمای نصبرا بررسی کنید.", -"seconds ago" => "ثانیه‌ها پیش", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "امروز", -"yesterday" => "دیروز", -"_%n day go_::_%n days ago_" => array(""), -"last month" => "ماه قبل", -"_%n month ago_::_%n months ago_" => array(""), -"last year" => "سال قبل", -"years ago" => "سال‌های قبل", -"Could not find category \"%s\"" => "دسته بندی %s یافت نشد" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/fi.php b/lib/l10n/fi.php deleted file mode 100644 index ac1f80a8f73..00000000000 --- a/lib/l10n/fi.php +++ /dev/null @@ -1,5 +0,0 @@ - "asetukset" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/fi_FI.php b/lib/l10n/fi_FI.php deleted file mode 100644 index 1d2bdab749c..00000000000 --- a/lib/l10n/fi_FI.php +++ /dev/null @@ -1,62 +0,0 @@ - "Sovellusta \"%s\" ei voi asentaa, koska se ei ole yhteensopiva käytössä olevan ownCloud-version kanssa.", -"No app name specified" => "Sovelluksen nimeä ei määritelty", -"Help" => "Ohje", -"Personal" => "Henkilökohtainen", -"Settings" => "Asetukset", -"Users" => "Käyttäjät", -"Admin" => "Ylläpitäjä", -"Failed to upgrade \"%s\"." => "Kohteen \"%s\" päivitys epäonnistui.", -"Custom profile pictures don't work with encryption yet" => "Omavalintaiset profiilikuvat eivät toimi salauksen kanssa vielä", -"Unknown filetype" => "Tuntematon tiedostotyyppi", -"Invalid image" => "Virheellinen kuva", -"web services under your control" => "verkkopalvelut hallinnassasi", -"ZIP download is turned off." => "ZIP-lataus on poistettu käytöstä.", -"Files need to be downloaded one by one." => "Tiedostot on ladattava yksittäin.", -"Back to Files" => "Takaisin tiedostoihin", -"Selected files too large to generate zip file." => "Valitut tiedostot ovat liian suurikokoisia mahtuakseen zip-tiedostoon.", -"No source specified when installing app" => "Lähdettä ei määritelty sovellusta asennettaessa", -"No path specified when installing app from local file" => "Polkua ei määritelty sovellusta asennettaessa paikallisesta tiedostosta", -"Archives of type %s are not supported" => "Tyypin %s arkistot eivät ole tuettuja", -"App does not provide an info.xml file" => "Sovellus ei sisällä info.xml-tiedostoa", -"App can't be installed because of not allowed code in the App" => "Sovellusta ei voi asentaa, koska sovellus sisältää kiellettyä koodia", -"App can't be installed because it is not compatible with this version of ownCloud" => "Sovellusta ei voi asentaa, koska se ei ole yhteensopiva käytössä olevan ownCloud-version kanssa", -"App directory already exists" => "Sovelluskansio on jo olemassa", -"Can't create app folder. Please fix permissions. %s" => "Sovelluskansion luominen ei onnistu. Korjaa käyttöoikeudet. %s", -"Application is not enabled" => "Sovellusta ei ole otettu käyttöön", -"Authentication error" => "Tunnistautumisvirhe", -"Token expired. Please reload page." => "Valtuutus vanheni. Lataa sivu uudelleen.", -"Files" => "Tiedostot", -"Text" => "Teksti", -"Images" => "Kuvat", -"%s enter the database username." => "%s anna tietokannan käyttäjätunnus.", -"%s enter the database name." => "%s anna tietokannan nimi.", -"%s you may not use dots in the database name" => "%s et voi käyttää pisteitä tietokannan nimessä", -"MS SQL username and/or password not valid: %s" => "MS SQL -käyttäjätunnus ja/tai -salasana on väärin: %s", -"MySQL username and/or password not valid" => "MySQL:n käyttäjätunnus ja/tai salasana on väärin", -"DB Error: \"%s\"" => "Tietokantavirhe: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL-käyttäjä '%s'@'localhost' on jo olemassa.", -"Drop this user from MySQL" => "Pudota tämä käyttäjä MySQL:stä", -"MySQL user '%s'@'%%' already exists" => "MySQL-käyttäjä '%s'@'%%' on jo olemassa", -"Drop this user from MySQL." => "Pudota tämä käyttäjä MySQL:stä.", -"Oracle connection could not be established" => "Oracle-yhteyttä ei voitu muodostaa", -"Oracle username and/or password not valid" => "Oraclen käyttäjätunnus ja/tai salasana on väärin", -"PostgreSQL username and/or password not valid" => "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin", -"Set an admin username." => "Aseta ylläpitäjän käyttäjätunnus.", -"Set an admin password." => "Aseta ylläpitäjän salasana.", -"Please double check the installation guides." => "Lue tarkasti asennusohjeet.", -"seconds ago" => "sekuntia sitten", -"_%n minute ago_::_%n minutes ago_" => array("%n minuutti sitten","%n minuuttia sitten"), -"_%n hour ago_::_%n hours ago_" => array("%n tunti sitten","%n tuntia sitten"), -"today" => "tänään", -"yesterday" => "eilen", -"_%n day go_::_%n days ago_" => array("%n päivä sitten","%n päivää sitten"), -"last month" => "viime kuussa", -"_%n month ago_::_%n months ago_" => array("%n kuukausi sitten","%n kuukautta sitten"), -"last year" => "viime vuonna", -"years ago" => "vuotta sitten", -"Caused by:" => "Aiheuttaja:", -"Could not find category \"%s\"" => "Luokkaa \"%s\" ei löytynyt" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/fr.php b/lib/l10n/fr.php deleted file mode 100644 index ab3d618849e..00000000000 --- a/lib/l10n/fr.php +++ /dev/null @@ -1,72 +0,0 @@ - "L'application \"%s\" ne peut être installée car elle n'est pas compatible avec cette version de ownCloud.", -"No app name specified" => "Aucun nom d'application spécifié", -"Help" => "Aide", -"Personal" => "Personnel", -"Settings" => "Paramètres", -"Users" => "Utilisateurs", -"Admin" => "Administration", -"Failed to upgrade \"%s\"." => "Echec de la mise à niveau \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Les images de profil personnalisées ne fonctionnent pas encore avec le système de chiffrement.", -"Unknown filetype" => "Type de fichier inconnu", -"Invalid image" => "Image invalide", -"web services under your control" => "services web sous votre contrôle", -"cannot open \"%s\"" => "impossible d'ouvrir \"%s\"", -"ZIP download is turned off." => "Téléchargement ZIP désactivé.", -"Files need to be downloaded one by one." => "Les fichiers nécessitent d'être téléchargés un par un.", -"Back to Files" => "Retour aux Fichiers", -"Selected files too large to generate zip file." => "Les fichiers sélectionnés sont trop volumineux pour être compressés.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Télécharger les fichiers en parties plus petites, séparément ou demander avec bienveillance à votre administrateur.", -"No source specified when installing app" => "Aucune source spécifiée pour installer l'application", -"No href specified when installing app from http" => "Aucun href spécifié pour installer l'application par http", -"No path specified when installing app from local file" => "Aucun chemin spécifié pour installer l'application depuis un fichier local", -"Archives of type %s are not supported" => "Les archives de type %s ne sont pas supportées", -"Failed to open archive when installing app" => "Échec de l'ouverture de l'archive lors de l'installation de l'application", -"App does not provide an info.xml file" => "L'application ne fournit pas de fichier info.xml", -"App can't be installed because of not allowed code in the App" => "L'application ne peut être installée car elle contient du code non-autorisé", -"App can't be installed because it is not compatible with this version of ownCloud" => "L'application ne peut être installée car elle n'est pas compatible avec cette version de ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "L'application ne peut être installée car elle contient la balise true qui n'est pas autorisée pour les applications non-diffusées", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "L'application ne peut être installée car la version de info.xml/version n'est identique à celle indiquée sur l'app store", -"App directory already exists" => "Le dossier de l'application existe déjà", -"Can't create app folder. Please fix permissions. %s" => "Impossible de créer le dossier de l'application. Corrigez les droits d'accès. %s", -"Application is not enabled" => "L'application n'est pas activée", -"Authentication error" => "Erreur d'authentification", -"Token expired. Please reload page." => "La session a expiré. Veuillez recharger la page.", -"Files" => "Fichiers", -"Text" => "Texte", -"Images" => "Images", -"%s enter the database username." => "%s entrez le nom d'utilisateur de la base de données.", -"%s enter the database name." => "%s entrez le nom de la base de données.", -"%s you may not use dots in the database name" => "%s vous nez pouvez pas utiliser de points dans le nom de la base de données", -"MS SQL username and/or password not valid: %s" => "Le nom d'utilisateur et/ou le mot de passe de la base MS SQL est invalide : %s", -"You need to enter either an existing account or the administrator." => "Vous devez spécifier soit le nom d'un compte existant, soit celui de l'administrateur.", -"MySQL username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base MySQL invalide", -"DB Error: \"%s\"" => "Erreur de la base de données : \"%s\"", -"Offending command was: \"%s\"" => "La requête en cause est : \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "L'utilisateur MySQL '%s'@'localhost' existe déjà.", -"Drop this user from MySQL" => "Retirer cet utilisateur de la base MySQL", -"MySQL user '%s'@'%%' already exists" => "L'utilisateur MySQL '%s'@'%%' existe déjà", -"Drop this user from MySQL." => "Retirer cet utilisateur de la base MySQL.", -"Oracle connection could not be established" => "La connexion Oracle ne peut pas être établie", -"Oracle username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base Oracle invalide", -"Offending command was: \"%s\", name: %s, password: %s" => "La requête en cause est : \"%s\", nom : %s, mot de passe : %s", -"PostgreSQL username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL invalide", -"Set an admin username." => "Spécifiez un nom d'utilisateur pour l'administrateur.", -"Set an admin password." => "Spécifiez un mot de passe administrateur.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Votre serveur web, n'est pas correctement configuré pour permettre la synchronisation des fichiers, car l'interface WebDav ne fonctionne pas comme il faut.", -"Please double check the installation guides." => "Veuillez vous référer au guide d'installation.", -"seconds ago" => "il y a quelques secondes", -"_%n minute ago_::_%n minutes ago_" => array("","il y a %n minutes"), -"_%n hour ago_::_%n hours ago_" => array("","Il y a %n heures"), -"today" => "aujourd'hui", -"yesterday" => "hier", -"_%n day go_::_%n days ago_" => array("","il y a %n jours"), -"last month" => "le mois dernier", -"_%n month ago_::_%n months ago_" => array("","Il y a %n mois"), -"last year" => "l'année dernière", -"years ago" => "il y a plusieurs années", -"Caused by:" => "Causé par :", -"Could not find category \"%s\"" => "Impossible de trouver la catégorie \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/l10n/gl.php b/lib/l10n/gl.php deleted file mode 100644 index 406272d690f..00000000000 --- a/lib/l10n/gl.php +++ /dev/null @@ -1,72 +0,0 @@ - "Non é posíbel instalar o aplicativo «%s» por non seren compatíbel con esta versión do ownCloud.", -"No app name specified" => "Non se especificou o nome do aplicativo", -"Help" => "Axuda", -"Personal" => "Persoal", -"Settings" => "Axustes", -"Users" => "Usuarios", -"Admin" => "Administración", -"Failed to upgrade \"%s\"." => "Non foi posíbel anovar «%s».", -"Custom profile pictures don't work with encryption yet" => "As imaxes personalizadas de perfil aínda non funcionan co cifrado", -"Unknown filetype" => "Tipo de ficheiro descoñecido", -"Invalid image" => "Imaxe incorrecta", -"web services under your control" => "servizos web baixo o seu control", -"cannot open \"%s\"" => "non foi posíbel abrir «%s»", -"ZIP download is turned off." => "As descargas ZIP están desactivadas.", -"Files need to be downloaded one by one." => "Os ficheiros necesitan seren descargados dun en un.", -"Back to Files" => "Volver aos ficheiros", -"Selected files too large to generate zip file." => "Os ficheiros seleccionados son demasiado grandes como para xerar un ficheiro zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descargue os ficheiros en cachos máis pequenos e por separado, ou pídallos amabelmente ao seu administrador.", -"No source specified when installing app" => "Non foi especificada ningunha orixe ao instalar aplicativos", -"No href specified when installing app from http" => "Non foi especificada ningunha href ao instalar aplicativos", -"No path specified when installing app from local file" => "Non foi especificada ningunha ruta ao instalar aplicativos desde un ficheiro local", -"Archives of type %s are not supported" => "Os arquivos do tipo %s non están admitidos", -"Failed to open archive when installing app" => "Non foi posíbel abrir o arquivo ao instalar aplicativos", -"App does not provide an info.xml file" => "O aplicativo non fornece un ficheiro info.xml", -"App can't be installed because of not allowed code in the App" => "Non é posíbel instalar o aplicativo por mor de conter código non permitido", -"App can't be installed because it is not compatible with this version of ownCloud" => "Non é posíbel instalar o aplicativo por non seren compatíbel con esta versión do ownCloud.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Non é posíbel instalar o aplicativo por conter a etiqueta\n\n\ntrue\n\nque non está permitida para os aplicativos non enviados", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Non é posíbel instalar o aplicativo xa que a versión en info.xml/version non é a mesma que a versión informada desde a App Store", -"App directory already exists" => "Xa existe o directorio do aplicativo", -"Can't create app folder. Please fix permissions. %s" => "Non é posíbel crear o cartafol de aplicativos. Corrixa os permisos. %s", -"Application is not enabled" => "O aplicativo non está activado", -"Authentication error" => "Produciuse un erro de autenticación", -"Token expired. Please reload page." => "Testemuña caducada. Recargue a páxina.", -"Files" => "Ficheiros", -"Text" => "Texto", -"Images" => "Imaxes", -"%s enter the database username." => "%s introduza o nome de usuario da base de datos", -"%s enter the database name." => "%s introduza o nome da base de datos", -"%s you may not use dots in the database name" => "%s non se poden empregar puntos na base de datos", -"MS SQL username and/or password not valid: %s" => "Nome de usuario e/ou contrasinal de MS SQL incorrecto: %s", -"You need to enter either an existing account or the administrator." => "Deberá introducir unha conta existente ou o administrador.", -"MySQL username and/or password not valid" => "Nome de usuario e/ou contrasinal de MySQL incorrecto", -"DB Error: \"%s\"" => "Produciuse un erro na base de datos: «%s»", -"Offending command was: \"%s\"" => "A orde ofensiva foi: «%s»", -"MySQL user '%s'@'localhost' exists already." => "O usuario MySQL '%s'@'localhost' xa existe.", -"Drop this user from MySQL" => "Omitir este usuario de MySQL", -"MySQL user '%s'@'%%' already exists" => "O usuario MySQL «%s»@«%%» xa existe.", -"Drop this user from MySQL." => "Omitir este usuario de MySQL.", -"Oracle connection could not be established" => "Non foi posíbel estabelecer a conexión con Oracle", -"Oracle username and/or password not valid" => "Nome de usuario e/ou contrasinal de Oracle incorrecto", -"Offending command was: \"%s\", name: %s, password: %s" => "A orde ofensiva foi: «%s», nome: %s, contrasinal: %s", -"PostgreSQL username and/or password not valid" => "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto", -"Set an admin username." => "Estabeleza un nome de usuario administrador", -"Set an admin password." => "Estabeleza un contrasinal de administrador", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "O seu servidor web non está aínda configurado adecuadamente para permitir a sincronización de ficheiros xa que semella que a interface WebDAV non está a funcionar.", -"Please double check the installation guides." => "Volva comprobar as guías de instalación", -"seconds ago" => "segundos atrás", -"_%n minute ago_::_%n minutes ago_" => array("hai %n minuto","hai %n minutos"), -"_%n hour ago_::_%n hours ago_" => array("hai %n hora","hai %n horas"), -"today" => "hoxe", -"yesterday" => "onte", -"_%n day go_::_%n days ago_" => array("hai %n día","hai %n días"), -"last month" => "último mes", -"_%n month ago_::_%n months ago_" => array("hai %n mes","hai %n meses"), -"last year" => "último ano", -"years ago" => "anos atrás", -"Caused by:" => "Causado por:", -"Could not find category \"%s\"" => "Non foi posíbel atopar a categoría «%s»" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/he.php b/lib/l10n/he.php deleted file mode 100644 index ced6244ee91..00000000000 --- a/lib/l10n/he.php +++ /dev/null @@ -1,33 +0,0 @@ - "עזרה", -"Personal" => "אישי", -"Settings" => "הגדרות", -"Users" => "משתמשים", -"Admin" => "מנהל", -"web services under your control" => "שירותי רשת תחת השליטה שלך", -"ZIP download is turned off." => "הורדת ZIP כבויה", -"Files need to be downloaded one by one." => "יש להוריד את הקבצים אחד אחרי השני.", -"Back to Files" => "חזרה לקבצים", -"Selected files too large to generate zip file." => "הקבצים הנבחרים גדולים מידי ליצירת קובץ zip.", -"Application is not enabled" => "יישומים אינם מופעלים", -"Authentication error" => "שגיאת הזדהות", -"Token expired. Please reload page." => "פג תוקף. נא לטעון שוב את הדף.", -"Files" => "קבצים", -"Text" => "טקסט", -"Images" => "תמונות", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "שרת האינטרנט שלך אינו מוגדר לצורכי סנכרון קבצים עדיין כיוון שמנשק ה־WebDAV כנראה אינו תקין.", -"Please double check the installation guides." => "נא לעיין שוב במדריכי ההתקנה.", -"seconds ago" => "שניות", -"_%n minute ago_::_%n minutes ago_" => array("","לפני %n דקות"), -"_%n hour ago_::_%n hours ago_" => array("","לפני %n שעות"), -"today" => "היום", -"yesterday" => "אתמול", -"_%n day go_::_%n days ago_" => array("","לפני %n ימים"), -"last month" => "חודש שעבר", -"_%n month ago_::_%n months ago_" => array("","לפני %n חודשים"), -"last year" => "שנה שעברה", -"years ago" => "שנים", -"Could not find category \"%s\"" => "לא ניתן למצוא את הקטגוריה „%s“" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/hi.php b/lib/l10n/hi.php deleted file mode 100644 index 039dfa4465d..00000000000 --- a/lib/l10n/hi.php +++ /dev/null @@ -1,12 +0,0 @@ - "सहयोग", -"Personal" => "यक्तिगत", -"Settings" => "सेटिंग्स", -"Users" => "उपयोगकर्ता", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/hr.php b/lib/l10n/hr.php deleted file mode 100644 index d217f924099..00000000000 --- a/lib/l10n/hr.php +++ /dev/null @@ -1,23 +0,0 @@ - "Pomoć", -"Personal" => "Osobno", -"Settings" => "Postavke", -"Users" => "Korisnici", -"Admin" => "Administrator", -"web services under your control" => "web usluge pod vašom kontrolom", -"Authentication error" => "Greška kod autorizacije", -"Files" => "Datoteke", -"Text" => "Tekst", -"seconds ago" => "sekundi prije", -"_%n minute ago_::_%n minutes ago_" => array("","",""), -"_%n hour ago_::_%n hours ago_" => array("","",""), -"today" => "danas", -"yesterday" => "jučer", -"_%n day go_::_%n days ago_" => array("","",""), -"last month" => "prošli mjesec", -"_%n month ago_::_%n months ago_" => array("","",""), -"last year" => "prošlu godinu", -"years ago" => "godina" -); -$PLURAL_FORMS = "nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"; diff --git a/lib/l10n/hu_HU.php b/lib/l10n/hu_HU.php deleted file mode 100644 index e944291caee..00000000000 --- a/lib/l10n/hu_HU.php +++ /dev/null @@ -1,62 +0,0 @@ - "Nincs az alkalmazás név megadva.", -"Help" => "Súgó", -"Personal" => "Személyes", -"Settings" => "Beállítások", -"Users" => "Felhasználók", -"Admin" => "Adminsztráció", -"Failed to upgrade \"%s\"." => "Sikertelen Frissítés \"%s\".", -"Unknown filetype" => "Ismeretlen file tipús", -"Invalid image" => "Hibás kép", -"web services under your control" => "webszolgáltatások saját kézben", -"cannot open \"%s\"" => "nem sikerült megnyitni \"%s\"", -"ZIP download is turned off." => "A ZIP-letöltés nincs engedélyezve.", -"Files need to be downloaded one by one." => "A fájlokat egyenként kell letölteni.", -"Back to Files" => "Vissza a Fájlokhoz", -"Selected files too large to generate zip file." => "A kiválasztott fájlok túl nagyok a zip tömörítéshez.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Tölts le a fileokat kisebb chunkokban, kölün vagy kérj segitséget a rendszergazdádtól.", -"App does not provide an info.xml file" => "Az alkalmazás nem szolgáltatott info.xml file-t", -"App can't be installed because it is not compatible with this version of ownCloud" => "Az alalmazás nem telepíthető, mert nem kompatibilis az ownClod ezzel a verziójával.", -"App directory already exists" => "Az alkalmazás mappája már létezik", -"Can't create app folder. Please fix permissions. %s" => "Nem lehetett létrehozni az alkalmzás mappáját. Kérlek ellenőrizd a jogosultásgokat. %s", -"Application is not enabled" => "Az alkalmazás nincs engedélyezve", -"Authentication error" => "Azonosítási hiba", -"Token expired. Please reload page." => "A token lejárt. Frissítse az oldalt.", -"Files" => "Fájlok", -"Text" => "Szöveg", -"Images" => "Képek", -"%s enter the database username." => "%s adja meg az adatbázist elérő felhasználó login nevét.", -"%s enter the database name." => "%s adja meg az adatbázis nevét.", -"%s you may not use dots in the database name" => "%s az adatbázis neve nem tartalmazhat pontot", -"MS SQL username and/or password not valid: %s" => "Az MS SQL felhasználónév és/vagy jelszó érvénytelen: %s", -"You need to enter either an existing account or the administrator." => "Vagy egy létező felhasználó vagy az adminisztrátor bejelentkezési nevét kell megadnia", -"MySQL username and/or password not valid" => "A MySQL felhasználói név és/vagy jelszó érvénytelen", -"DB Error: \"%s\"" => "Adatbázis hiba: \"%s\"", -"Offending command was: \"%s\"" => "A hibát ez a parancs okozta: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "A '%s'@'localhost' MySQL felhasználó már létezik.", -"Drop this user from MySQL" => "Törölje ezt a felhasználót a MySQL-ből", -"MySQL user '%s'@'%%' already exists" => "A '%s'@'%%' MySQL felhasználó már létezik", -"Drop this user from MySQL." => "Törölje ezt a felhasználót a MySQL-ből.", -"Oracle connection could not be established" => "Az Oracle kapcsolat nem hozható létre", -"Oracle username and/or password not valid" => "Az Oracle felhasználói név és/vagy jelszó érvénytelen", -"Offending command was: \"%s\", name: %s, password: %s" => "A hibát okozó parancs ez volt: \"%s\", login név: %s, jelszó: %s", -"PostgreSQL username and/or password not valid" => "A PostgreSQL felhasználói név és/vagy jelszó érvénytelen", -"Set an admin username." => "Állítson be egy felhasználói nevet az adminisztrációhoz.", -"Set an admin password." => "Állítson be egy jelszót az adminisztrációhoz.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Az Ön webkiszolgálója nincs megfelelően beállítva az állományok szinkronizálásához, mert a WebDAV-elérés úgy tűnik, nem működik.", -"Please double check the installation guides." => "Kérjük tüzetesen tanulmányozza át a telepítési útmutatót.", -"Could not find category \"%s\"" => "Ez a kategória nem található: \"%s\"", -"seconds ago" => "pár másodperce", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "ma", -"yesterday" => "tegnap", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "múlt hónapban", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "tavaly", -"years ago" => "több éve", -"Caused by:" => "Okozta:" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/hy.php b/lib/l10n/hy.php deleted file mode 100644 index 15f78e0bce6..00000000000 --- a/lib/l10n/hy.php +++ /dev/null @@ -1,8 +0,0 @@ - array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ia.php b/lib/l10n/ia.php deleted file mode 100644 index 34f43bc424a..00000000000 --- a/lib/l10n/ia.php +++ /dev/null @@ -1,16 +0,0 @@ - "Adjuta", -"Personal" => "Personal", -"Settings" => "Configurationes", -"Users" => "Usatores", -"Admin" => "Administration", -"web services under your control" => "servicios web sub tu controlo", -"Files" => "Files", -"Text" => "Texto", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/id.php b/lib/l10n/id.php deleted file mode 100644 index 080faddb321..00000000000 --- a/lib/l10n/id.php +++ /dev/null @@ -1,50 +0,0 @@ - "Bantuan", -"Personal" => "Pribadi", -"Settings" => "Setelan", -"Users" => "Pengguna", -"Admin" => "Admin", -"web services under your control" => "layanan web dalam kontrol Anda", -"ZIP download is turned off." => "Pengunduhan ZIP dimatikan.", -"Files need to be downloaded one by one." => "Berkas harus diunduh satu persatu.", -"Back to Files" => "Kembali ke Daftar Berkas", -"Selected files too large to generate zip file." => "Berkas yang dipilih terlalu besar untuk dibuat berkas zip-nya.", -"Application is not enabled" => "Aplikasi tidak diaktifkan", -"Authentication error" => "Galat saat autentikasi", -"Token expired. Please reload page." => "Token kedaluwarsa. Silakan muat ulang halaman.", -"Files" => "Berkas", -"Text" => "Teks", -"Images" => "Gambar", -"%s enter the database username." => "%s masukkan nama pengguna basis data.", -"%s enter the database name." => "%s masukkan nama basis data.", -"%s you may not use dots in the database name" => "%sAnda tidak boleh menggunakan karakter titik pada nama basis data", -"MS SQL username and/or password not valid: %s" => "Nama pengguna dan/atau sandi MySQL tidak valid: %s", -"You need to enter either an existing account or the administrator." => "Anda harus memasukkan akun yang sudah ada atau administrator.", -"MySQL username and/or password not valid" => "Nama pengguna dan/atau sandi MySQL tidak valid", -"DB Error: \"%s\"" => "Galat Basis Data: \"%s\"", -"Offending command was: \"%s\"" => "Perintah yang bermasalah: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Pengguna MySQL '%s'@'localhost' sudah ada.", -"Drop this user from MySQL" => "Hapus pengguna ini dari MySQL", -"MySQL user '%s'@'%%' already exists" => "Pengguna MySQL '%s'@'%%' sudah ada.", -"Drop this user from MySQL." => "Hapus pengguna ini dari MySQL.", -"Oracle username and/or password not valid" => "Nama pengguna dan/atau sandi Oracle tidak valid", -"Offending command was: \"%s\", name: %s, password: %s" => "Perintah yang bermasalah: \"%s\", nama pengguna: %s, sandi: %s", -"PostgreSQL username and/or password not valid" => "Nama pengguna dan/atau sandi PostgreSQL tidak valid", -"Set an admin username." => "Setel nama pengguna admin.", -"Set an admin password." => "Setel sandi admin.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Web server Anda belum dikonfigurasikan dengan baik untuk mengizinkan sinkronisasi berkas karena tampaknya antarmuka WebDAV rusak.", -"Please double check the installation guides." => "Silakan periksa ulang panduan instalasi.", -"seconds ago" => "beberapa detik yang lalu", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "hari ini", -"yesterday" => "kemarin", -"_%n day go_::_%n days ago_" => array(""), -"last month" => "bulan kemarin", -"_%n month ago_::_%n months ago_" => array(""), -"last year" => "tahun kemarin", -"years ago" => "beberapa tahun lalu", -"Could not find category \"%s\"" => "Tidak dapat menemukan kategori \"%s\"" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/is.php b/lib/l10n/is.php deleted file mode 100644 index 7512d278fb8..00000000000 --- a/lib/l10n/is.php +++ /dev/null @@ -1,31 +0,0 @@ - "Hjálp", -"Personal" => "Um mig", -"Settings" => "Stillingar", -"Users" => "Notendur", -"Admin" => "Stjórnun", -"web services under your control" => "vefþjónusta undir þinni stjórn", -"ZIP download is turned off." => "Slökkt á ZIP niðurhali.", -"Files need to be downloaded one by one." => "Skrárnar verður að sækja eina og eina", -"Back to Files" => "Aftur í skrár", -"Selected files too large to generate zip file." => "Valdar skrár eru of stórar til að búa til ZIP skrá.", -"Application is not enabled" => "Forrit ekki virkt", -"Authentication error" => "Villa við auðkenningu", -"Token expired. Please reload page." => "Auðkenning útrunnin. Vinsamlegast skráðu þig aftur inn.", -"Files" => "Skrár", -"Text" => "Texti", -"Images" => "Myndir", -"seconds ago" => "sek.", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "í dag", -"yesterday" => "í gær", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "síðasta mánuði", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "síðasta ári", -"years ago" => "einhverjum árum", -"Could not find category \"%s\"" => "Fann ekki flokkinn \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/it.php b/lib/l10n/it.php deleted file mode 100644 index b00789bc86f..00000000000 --- a/lib/l10n/it.php +++ /dev/null @@ -1,72 +0,0 @@ - "L'applicazione \"%s\" non può essere installata poiché non è compatibile con questa versione di ownCloud.", -"No app name specified" => "Il nome dell'applicazione non è specificato", -"Help" => "Aiuto", -"Personal" => "Personale", -"Settings" => "Impostazioni", -"Users" => "Utenti", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Aggiornamento non riuscito \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Le immagini personalizzate del profilo non funzionano ancora con la cifratura", -"Unknown filetype" => "Tipo di file sconosciuto", -"Invalid image" => "Immagine non valida", -"web services under your control" => "servizi web nelle tue mani", -"cannot open \"%s\"" => "impossibile aprire \"%s\"", -"ZIP download is turned off." => "Lo scaricamento in formato ZIP è stato disabilitato.", -"Files need to be downloaded one by one." => "I file devono essere scaricati uno alla volta.", -"Back to Files" => "Torna ai file", -"Selected files too large to generate zip file." => "I file selezionati sono troppo grandi per generare un file zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Scarica i file in blocchi più piccoli, separatamente o chiedi al tuo amministratore.", -"No source specified when installing app" => "Nessuna fonte specificata durante l'installazione dell'applicazione", -"No href specified when installing app from http" => "Nessun href specificato durante l'installazione dell'applicazione da http", -"No path specified when installing app from local file" => "Nessun percorso specificato durante l'installazione dell'applicazione da file locale", -"Archives of type %s are not supported" => "Gli archivi di tipo %s non sono supportati", -"Failed to open archive when installing app" => "Apertura archivio non riuscita durante l'installazione dell'applicazione", -"App does not provide an info.xml file" => "L'applicazione non fornisce un file info.xml", -"App can't be installed because of not allowed code in the App" => "L'applicazione non può essere installata a causa di codice non consentito al suo interno", -"App can't be installed because it is not compatible with this version of ownCloud" => "L'applicazione non può essere installata poiché non è compatibile con questa versione di ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "L'applicazione non può essere installata poiché contiene il tag true che non è permesso alle applicazioni non shipped", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "L'applicazione non può essere installata poiché la versione in info.xml/version non è la stessa riportata dall'app store", -"App directory already exists" => "La cartella dell'applicazione esiste già", -"Can't create app folder. Please fix permissions. %s" => "Impossibile creare la cartella dell'applicazione. Correggi i permessi. %s", -"Application is not enabled" => "L'applicazione non è abilitata", -"Authentication error" => "Errore di autenticazione", -"Token expired. Please reload page." => "Token scaduto. Ricarica la pagina.", -"Files" => "File", -"Text" => "Testo", -"Images" => "Immagini", -"%s enter the database username." => "%s digita il nome utente del database.", -"%s enter the database name." => "%s digita il nome del database.", -"%s you may not use dots in the database name" => "%s non dovresti utilizzare punti nel nome del database", -"MS SQL username and/or password not valid: %s" => "Nome utente e/o password MS SQL non validi: %s", -"You need to enter either an existing account or the administrator." => "È necessario inserire un account esistente o l'amministratore.", -"MySQL username and/or password not valid" => "Nome utente e/o password di MySQL non validi", -"DB Error: \"%s\"" => "Errore DB: \"%s\"", -"Offending command was: \"%s\"" => "Il comando non consentito era: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "L'utente MySQL '%s'@'localhost' esiste già.", -"Drop this user from MySQL" => "Elimina questo utente da MySQL", -"MySQL user '%s'@'%%' already exists" => "L'utente MySQL '%s'@'%%' esiste già", -"Drop this user from MySQL." => "Elimina questo utente da MySQL.", -"Oracle connection could not be established" => "La connessione a Oracle non può essere stabilita", -"Oracle username and/or password not valid" => "Nome utente e/o password di Oracle non validi", -"Offending command was: \"%s\", name: %s, password: %s" => "Il comando non consentito era: \"%s\", nome: %s, password: %s", -"PostgreSQL username and/or password not valid" => "Nome utente e/o password di PostgreSQL non validi", -"Set an admin username." => "Imposta un nome utente di amministrazione.", -"Set an admin password." => "Imposta una password di amministrazione.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Il tuo server web non è configurato correttamente per consentire la sincronizzazione dei file poiché l'interfaccia WebDAV sembra essere danneggiata.", -"Please double check the installation guides." => "Leggi attentamente le guide d'installazione.", -"seconds ago" => "secondi fa", -"_%n minute ago_::_%n minutes ago_" => array("%n minuto fa","%n minuti fa"), -"_%n hour ago_::_%n hours ago_" => array("%n ora fa","%n ore fa"), -"today" => "oggi", -"yesterday" => "ieri", -"_%n day go_::_%n days ago_" => array("%n giorno fa","%n giorni fa"), -"last month" => "mese scorso", -"_%n month ago_::_%n months ago_" => array("%n mese fa","%n mesi fa"), -"last year" => "anno scorso", -"years ago" => "anni fa", -"Caused by:" => "Causato da:", -"Could not find category \"%s\"" => "Impossibile trovare la categoria \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ja_JP.php b/lib/l10n/ja_JP.php deleted file mode 100644 index b9e6a0e6924..00000000000 --- a/lib/l10n/ja_JP.php +++ /dev/null @@ -1,72 +0,0 @@ - " \"%s\" アプリは、このバージョンのownCloudと互換性がない為、インストールできません。", -"No app name specified" => "アプリ名が未指定", -"Help" => "ヘルプ", -"Personal" => "個人", -"Settings" => "設定", -"Users" => "ユーザ", -"Admin" => "管理", -"Failed to upgrade \"%s\"." => "\"%s\" へのアップグレードに失敗しました。", -"Custom profile pictures don't work with encryption yet" => "暗号無しでは利用不可なカスタムプロフィール画像", -"Unknown filetype" => "不明なファイルタイプ", -"Invalid image" => "無効な画像", -"web services under your control" => "管理下のウェブサービス", -"cannot open \"%s\"" => "\"%s\" が開けません", -"ZIP download is turned off." => "ZIPダウンロードは無効です。", -"Files need to be downloaded one by one." => "ファイルは1つずつダウンロードする必要があります。", -"Back to Files" => "ファイルに戻る", -"Selected files too large to generate zip file." => "選択したファイルはZIPファイルの生成には大きすぎます。", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "ファイルは、小さいファイルに分割されてダウンロードされます。もしくは、管理者にお尋ねください。", -"No source specified when installing app" => "アプリインストール時のソースが未指定", -"No href specified when installing app from http" => "アプリインストール時のhttpの URL が未指定", -"No path specified when installing app from local file" => "アプリインストール時のローカルファイルのパスが未指定", -"Archives of type %s are not supported" => "\"%s\"タイプのアーカイブ形式は未サポート", -"Failed to open archive when installing app" => "アプリをインストール中にアーカイブファイルを開けませんでした。", -"App does not provide an info.xml file" => "アプリにinfo.xmlファイルが入っていません", -"App can't be installed because of not allowed code in the App" => "アプリで許可されないコードが入っているのが原因でアプリがインストールできません", -"App can't be installed because it is not compatible with this version of ownCloud" => "アプリは、このバージョンのownCloudと互換性がない為、インストールできません。", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "非shippedアプリには許可されないtrueタグが含まれているためにアプリをインストール出来ません。", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "info.xml/versionのバージョンがアプリストアのバージョンと合っていない為、アプリはインストールされません", -"App directory already exists" => "アプリディレクトリは既に存在します", -"Can't create app folder. Please fix permissions. %s" => "アプリフォルダを作成出来ませんでした。%s のパーミッションを修正してください。", -"Application is not enabled" => "アプリケーションは無効です", -"Authentication error" => "認証エラー", -"Token expired. Please reload page." => "トークンが無効になりました。ページを再読込してください。", -"Files" => "ファイル", -"Text" => "TTY TDD", -"Images" => "画像", -"%s enter the database username." => "%s のデータベースのユーザ名を入力してください。", -"%s enter the database name." => "%s のデータベース名を入力してください。", -"%s you may not use dots in the database name" => "%s ではデータベース名にドットを利用できないかもしれません。", -"MS SQL username and/or password not valid: %s" => "MS SQL サーバーのユーザー名/パスワードが正しくありません: %s", -"You need to enter either an existing account or the administrator." => "既存のアカウントもしくは管理者のどちらかを入力する必要があります。", -"MySQL username and/or password not valid" => "MySQLのユーザ名もしくはパスワードは有効ではありません", -"DB Error: \"%s\"" => "DBエラー: \"%s\"", -"Offending command was: \"%s\"" => "違反コマンド: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQLのユーザ '%s'@'localhost' はすでに存在します。", -"Drop this user from MySQL" => "MySQLからこのユーザを削除", -"MySQL user '%s'@'%%' already exists" => "MySQLのユーザ '%s'@'%%' はすでに存在します。", -"Drop this user from MySQL." => "MySQLからこのユーザを削除する。", -"Oracle connection could not be established" => "Oracleへの接続が確立できませんでした。", -"Oracle username and/or password not valid" => "Oracleのユーザ名もしくはパスワードは有効ではありません", -"Offending command was: \"%s\", name: %s, password: %s" => "違反コマンド: \"%s\"、名前: %s、パスワード: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQLのユーザ名もしくはパスワードは有効ではありません", -"Set an admin username." => "管理者のユーザ名を設定。", -"Set an admin password." => "管理者のパスワードを設定。", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "WebDAVインタフェースが動作していないと考えられるため、あなたのWEBサーバはまだファイルの同期を許可するように適切な設定がされていません。", -"Please double check the installation guides." => "インストールガイドをよく確認してください。", -"seconds ago" => "数秒前", -"_%n minute ago_::_%n minutes ago_" => array("%n 分前"), -"_%n hour ago_::_%n hours ago_" => array("%n 時間後"), -"today" => "今日", -"yesterday" => "昨日", -"_%n day go_::_%n days ago_" => array("%n 日後"), -"last month" => "一月前", -"_%n month ago_::_%n months ago_" => array("%n カ月後"), -"last year" => "一年前", -"years ago" => "年前", -"Caused by:" => "原因は以下:", -"Could not find category \"%s\"" => "カテゴリ \"%s\" が見つかりませんでした" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/ka.php b/lib/l10n/ka.php deleted file mode 100644 index 04fefe8bdf1..00000000000 --- a/lib/l10n/ka.php +++ /dev/null @@ -1,17 +0,0 @@ - "შველა", -"Personal" => "პერსონა", -"Users" => "მომხმარებლები", -"Admin" => "ადმინისტრატორი", -"ZIP download is turned off." => "ZIP გადმოწერა გამორთულია", -"Files" => "ფაილები", -"seconds ago" => "წამის წინ", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "დღეს", -"yesterday" => "გუშინ", -"_%n day go_::_%n days ago_" => array(""), -"_%n month ago_::_%n months ago_" => array("") -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/ka_GE.php b/lib/l10n/ka_GE.php deleted file mode 100644 index 8fbe34e6786..00000000000 --- a/lib/l10n/ka_GE.php +++ /dev/null @@ -1,50 +0,0 @@ - "დახმარება", -"Personal" => "პირადი", -"Settings" => "პარამეტრები", -"Users" => "მომხმარებელი", -"Admin" => "ადმინისტრატორი", -"web services under your control" => "web services under your control", -"ZIP download is turned off." => "ZIP download–ი გათიშულია", -"Files need to be downloaded one by one." => "ფაილები უნდა გადმოიტვირთოს სათითაოდ.", -"Back to Files" => "უკან ფაილებში", -"Selected files too large to generate zip file." => "არჩეული ფაილები ძალიან დიდია zip ფაილის გენერაციისთვის.", -"Application is not enabled" => "აპლიკაცია არ არის აქტიური", -"Authentication error" => "ავთენტიფიკაციის შეცდომა", -"Token expired. Please reload page." => "Token–ს ვადა გაუვიდა. გთხოვთ განაახლოთ გვერდი.", -"Files" => "ფაილები", -"Text" => "ტექსტი", -"Images" => "სურათები", -"%s enter the database username." => "%s შეიყვანეთ ბაზის იუზერნეიმი.", -"%s enter the database name." => "%s შეიყვანეთ ბაზის სახელი.", -"%s you may not use dots in the database name" => "%s არ მიუთითოთ წერტილი ბაზის სახელში", -"MS SQL username and/or password not valid: %s" => "MS SQL მომხმარებელი და/ან პაროლი არ არის მართებული: %s", -"You need to enter either an existing account or the administrator." => "თქვენ უნდა შეიყვანოთ არსებული მომხმარებელის სახელი ან ადმინისტრატორი.", -"MySQL username and/or password not valid" => "MySQL იუზერნეიმი და/ან პაროლი არ არის სწორი", -"DB Error: \"%s\"" => "DB შეცდომა: \"%s\"", -"Offending command was: \"%s\"" => "Offending ბრძანება იყო: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL მომხმარებელი '%s'@'localhost' უკვე არსებობს.", -"Drop this user from MySQL" => "წაშალე ეს მომხამრებელი MySQL–იდან", -"MySQL user '%s'@'%%' already exists" => "MySQL მომხმარებელი '%s'@'%%' უკვე არსებობს", -"Drop this user from MySQL." => "წაშალე ეს მომხამრებელი MySQL–იდან", -"Oracle username and/or password not valid" => "Oracle იუზერნეიმი და/ან პაროლი არ არის სწორი", -"Offending command was: \"%s\", name: %s, password: %s" => "Offending ბრძანება იყო: \"%s\", სახელი: %s, პაროლი: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL იუზერნეიმი და/ან პაროლი არ არის სწორი", -"Set an admin username." => "დააყენეთ ადმინისტრატორის სახელი.", -"Set an admin password." => "დააყენეთ ადმინისტრატორის პაროლი.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "თქვენი web სერვერი არ არის კონფიგურირებული ფაილ სინქრონიზაციისთვის, რადგან WebDAV ინტერფეისი შეიძლება იყოს გატეხილი.", -"Please double check the installation guides." => "გთხოვთ გადაათვალიეროთ ინსტალაციის გზამკვლევი.", -"seconds ago" => "წამის წინ", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "დღეს", -"yesterday" => "გუშინ", -"_%n day go_::_%n days ago_" => array(""), -"last month" => "გასულ თვეში", -"_%n month ago_::_%n months ago_" => array(""), -"last year" => "ბოლო წელს", -"years ago" => "წლის წინ", -"Could not find category \"%s\"" => "\"%s\" კატეგორიის მოძებნა ვერ მოხერხდა" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/km.php b/lib/l10n/km.php deleted file mode 100644 index e7b09649a24..00000000000 --- a/lib/l10n/km.php +++ /dev/null @@ -1,8 +0,0 @@ - array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"_%n day go_::_%n days ago_" => array(""), -"_%n month ago_::_%n months ago_" => array("") -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/kn.php b/lib/l10n/kn.php deleted file mode 100644 index e7b09649a24..00000000000 --- a/lib/l10n/kn.php +++ /dev/null @@ -1,8 +0,0 @@ - array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"_%n day go_::_%n days ago_" => array(""), -"_%n month ago_::_%n months ago_" => array("") -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/ko.php b/lib/l10n/ko.php deleted file mode 100644 index 3ef39fefa60..00000000000 --- a/lib/l10n/ko.php +++ /dev/null @@ -1,72 +0,0 @@ - "현재 ownCloud 버전과 호환되지 않기 때문에 \"%s\" 앱을 설치할 수 없습니다.", -"No app name specified" => "앱 이름이 지정되지 않았습니다.", -"Help" => "도움말", -"Personal" => "개인", -"Settings" => "설정", -"Users" => "사용자", -"Admin" => "관리자", -"Failed to upgrade \"%s\"." => "\"%s\" 업그레이드에 실패했습니다.", -"Custom profile pictures don't work with encryption yet" => "개개인의 프로필 사진은 아직은 암호화 되지 않습니다", -"Unknown filetype" => "알수없는 파일형식", -"Invalid image" => "잘못된 그림", -"web services under your control" => "내가 관리하는 웹 서비스", -"cannot open \"%s\"" => "\"%s\"을(를) 열 수 없습니다.", -"ZIP download is turned off." => "ZIP 다운로드가 비활성화되었습니다.", -"Files need to be downloaded one by one." => "파일을 개별적으로 다운로드해야 합니다.", -"Back to Files" => "파일로 돌아가기", -"Selected files too large to generate zip file." => "선택한 파일들은 ZIP 파일을 생성하기에 너무 큽니다.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "작은 조각들 안에 들어있는 파일들을 받고자 하신다면, 나누어서 받으시거나 혹은 시스템 관리자에게 정중하게 물어보십시오", -"No source specified when installing app" => "앱을 설치할 때 소스가 지정되지 않았습니다.", -"No href specified when installing app from http" => "http에서 앱을 설치할 대 href가 지정되지 않았습니다.", -"No path specified when installing app from local file" => "로컬 파일에서 앱을 설치할 때 경로가 지정되지 않았습니다.", -"Archives of type %s are not supported" => "%s 타입 아카이브는 지원되지 않습니다.", -"Failed to open archive when installing app" => "앱을 설치할 때 아카이브를 열지 못했습니다.", -"App does not provide an info.xml file" => "앱에서 info.xml 파일이 제공되지 않았습니다.", -"App can't be installed because of not allowed code in the App" => "앱에 허용되지 않는 코드가 있어서 앱을 설치할 수 없습니다. ", -"App can't be installed because it is not compatible with this version of ownCloud" => "현재 ownCloud 버전과 호환되지 않기 때문에 앱을 설치할 수 없습니다.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "출하되지 않은 앱에 허용되지 않는 true 태그를 포함하고 있기 때문에 앱을 설치할 수 없습니다.", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "info.xml/version에 포함된 버전과 앱 스토어에 보고된 버전이 같지 않아서 앱을 설치할 수 없습니다. ", -"App directory already exists" => "앱 디렉토리가 이미 존재합니다. ", -"Can't create app folder. Please fix permissions. %s" => "앱 폴더를 만들 수 없습니다. 권한을 수정하십시오. %s ", -"Application is not enabled" => "앱이 활성화되지 않았습니다", -"Authentication error" => "인증 오류", -"Token expired. Please reload page." => "토큰이 만료되었습니다. 페이지를 새로 고치십시오.", -"Files" => "파일", -"Text" => "텍스트", -"Images" => "그림", -"%s enter the database username." => "데이터베이스 사용자 명을 %s 에 입력해주십시오", -"%s enter the database name." => "데이터베이스 명을 %s 에 입력해주십시오", -"%s you may not use dots in the database name" => "%s 에 적으신 데이터베이스 이름에는 점을 사용할수 없습니다", -"MS SQL username and/or password not valid: %s" => "MS SQL 사용자 이름이나 암호가 잘못되었습니다: %s", -"You need to enter either an existing account or the administrator." => "기존 계정이나 administrator(관리자)를 입력해야 합니다.", -"MySQL username and/or password not valid" => "MySQL 사용자 이름이나 암호가 잘못되었습니다.", -"DB Error: \"%s\"" => "DB 오류: \"%s\"", -"Offending command was: \"%s\"" => "잘못된 명령: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL 사용자 '%s'@'localhost'이(가) 이미 존재합니다.", -"Drop this user from MySQL" => "이 사용자를 MySQL에서 뺍니다.", -"MySQL user '%s'@'%%' already exists" => "MySQL 사용자 '%s'@'%%'이(가) 이미 존재합니다. ", -"Drop this user from MySQL." => "이 사용자를 MySQL에서 뺍니다.", -"Oracle connection could not be established" => "Oracle 연결을 수립할 수 없습니다.", -"Oracle username and/or password not valid" => "Oracle 사용자 이름이나 암호가 잘못되었습니다.", -"Offending command was: \"%s\", name: %s, password: %s" => "잘못된 명령: \"%s\", 이름: %s, 암호: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL의 사용자 명 혹은 비밀번호가 잘못되었습니다", -"Set an admin username." => "관리자 이름 설정", -"Set an admin password." => "관리자 비밀번호 설정", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "WebDAV 인터페이스가 제대로 작동하지 않습니다. 웹 서버에서 파일 동기화를 사용할 수 있도록 설정이 제대로 되지 않은 것 같습니다.", -"Please double check the installation guides." => "설치 가이드를 다시 한 번 확인하십시오.", -"Could not find category \"%s\"" => "분류 \"%s\"을(를) 찾을 수 없습니다.", -"seconds ago" => "초 전", -"_%n minute ago_::_%n minutes ago_" => array("%n분 전 "), -"_%n hour ago_::_%n hours ago_" => array("%n시간 전 "), -"today" => "오늘", -"yesterday" => "어제", -"_%n day go_::_%n days ago_" => array("%n일 전 "), -"last month" => "지난 달", -"_%n month ago_::_%n months ago_" => array("%n달 전 "), -"last year" => "작년", -"years ago" => "년 전", -"Caused by:" => "원인: " -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/ku_IQ.php b/lib/l10n/ku_IQ.php deleted file mode 100644 index c99f9dd2a12..00000000000 --- a/lib/l10n/ku_IQ.php +++ /dev/null @@ -1,13 +0,0 @@ - "یارمەتی", -"Settings" => "ده‌ستكاری", -"Users" => "به‌كارهێنه‌ر", -"Admin" => "به‌ڕێوه‌به‌ری سه‌ره‌كی", -"web services under your control" => "ڕاژه‌ی وێب له‌ژێر چاودێریت دایه", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/lb.php b/lib/l10n/lb.php deleted file mode 100644 index c25f5b55bd5..00000000000 --- a/lib/l10n/lb.php +++ /dev/null @@ -1,23 +0,0 @@ - "Hëllef", -"Personal" => "Perséinlech", -"Settings" => "Astellungen", -"Users" => "Benotzer", -"Admin" => "Admin", -"web services under your control" => "Web-Servicer ënnert denger Kontroll", -"Authentication error" => "Authentifikatioun's Fehler", -"Files" => "Dateien", -"Text" => "SMS", -"seconds ago" => "Sekonnen hir", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "haut", -"yesterday" => "gëschter", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "Läschte Mount", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "Läscht Joer", -"years ago" => "Joren hier" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/lt_LT.php b/lib/l10n/lt_LT.php deleted file mode 100644 index db8d96c1018..00000000000 --- a/lib/l10n/lt_LT.php +++ /dev/null @@ -1,72 +0,0 @@ - "Programa „%s“ negali būti įdiegta, nes yra nesuderinama su šia ownCloud versija.", -"No app name specified" => "Nenurodytas programos pavadinimas", -"Help" => "Pagalba", -"Personal" => "Asmeniniai", -"Settings" => "Nustatymai", -"Users" => "Vartotojai", -"Admin" => "Administravimas", -"Failed to upgrade \"%s\"." => "Nepavyko pakelti „%s“ versijos.", -"Custom profile pictures don't work with encryption yet" => "Saviti profilio paveiksliukai dar neveikia su šifravimu", -"Unknown filetype" => "Nežinomas failo tipas", -"Invalid image" => "Netinkamas paveikslėlis", -"web services under your control" => "jūsų valdomos web paslaugos", -"cannot open \"%s\"" => "nepavyksta atverti „%s“", -"ZIP download is turned off." => "ZIP atsisiuntimo galimybė yra išjungta.", -"Files need to be downloaded one by one." => "Failai turi būti parsiunčiami vienas po kito.", -"Back to Files" => "Atgal į Failus", -"Selected files too large to generate zip file." => "Pasirinkti failai per dideli archyvavimui į ZIP.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Atsisiųskite failus mažesnėmis dalimis atskirai, arba mandagiai prašykite savo administratoriaus.", -"No source specified when installing app" => "Nenurodytas šaltinis diegiant programą", -"No href specified when installing app from http" => "Nenurodytas href diegiant programą iš http", -"No path specified when installing app from local file" => "Nenurodytas kelias diegiant programą iš vietinio failo", -"Archives of type %s are not supported" => "%s tipo archyvai nepalaikomi", -"Failed to open archive when installing app" => "Nepavyko atverti archyvo diegiant programą", -"App does not provide an info.xml file" => "Programa nepateikia info.xml failo", -"App can't be installed because of not allowed code in the App" => "Programa negali būti įdiegta, nes turi neleistiną kodą", -"App can't be installed because it is not compatible with this version of ownCloud" => "Programa negali būti įdiegta, nes yra nesuderinama su šia ownCloud versija", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Programa negali būti įdiegta, nes turi true žymę, kuri yra neleistina ne kartu platinamoms programoms", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Programa negali būti įdiegta, nes versija pateikta info.xml/version nesutampa su versija deklaruota programų saugykloje", -"App directory already exists" => "Programos aplankas jau egzistuoja", -"Can't create app folder. Please fix permissions. %s" => "Nepavyksta sukurti aplanko. Prašome pataisyti leidimus. %s", -"Application is not enabled" => "Programa neįjungta", -"Authentication error" => "Autentikacijos klaida", -"Token expired. Please reload page." => "Sesija baigėsi. Prašome perkrauti puslapį.", -"Files" => "Failai", -"Text" => "Žinučių", -"Images" => "Paveikslėliai", -"%s enter the database username." => "%s įrašykite duombazės naudotojo vardą.", -"%s enter the database name." => "%s įrašykite duombazės pavadinimą.", -"%s you may not use dots in the database name" => "%s negalite naudoti taškų duombazės pavadinime", -"MS SQL username and/or password not valid: %s" => "MS SQL naudotojo vardas ir/arba slaptažodis netinka: %s", -"You need to enter either an existing account or the administrator." => "Turite prisijungti su egzistuojančia paskyra arba su administratoriumi.", -"MySQL username and/or password not valid" => "Neteisingas MySQL naudotojo vardas ir/arba slaptažodis", -"DB Error: \"%s\"" => "DB klaida: \"%s\"", -"Offending command was: \"%s\"" => "Vykdyta komanda buvo: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL naudotojas '%s'@'localhost' jau egzistuoja.", -"Drop this user from MySQL" => "Pašalinti šį naudotoją iš MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL naudotojas '%s'@'%%' jau egzistuoja", -"Drop this user from MySQL." => "Pašalinti šį naudotoją iš MySQL.", -"Oracle connection could not be established" => "Nepavyko sukurti Oracle ryšio", -"Oracle username and/or password not valid" => "Neteisingas Oracle naudotojo vardas ir/arba slaptažodis", -"Offending command was: \"%s\", name: %s, password: %s" => "Vykdyta komanda buvo: \"%s\", name: %s, password: %s", -"PostgreSQL username and/or password not valid" => "Neteisingas PostgreSQL naudotojo vardas ir/arba slaptažodis", -"Set an admin username." => "Nustatyti administratoriaus naudotojo vardą.", -"Set an admin password." => "Nustatyti administratoriaus slaptažodį.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Jūsų serveris nėra tvarkingai nustatytas leisti failų sinchronizaciją, nes WebDAV sąsaja panašu, kad yra sugadinta.", -"Please double check the installation guides." => "Prašome pažiūrėkite dar kartą diegimo instrukcijas.", -"seconds ago" => "prieš sekundę", -"_%n minute ago_::_%n minutes ago_" => array("prieš %n min.","Prieš % minutes","Prieš %n minučių"), -"_%n hour ago_::_%n hours ago_" => array("Prieš %n valandą","Prieš %n valandas","Prieš %n valandų"), -"today" => "šiandien", -"yesterday" => "vakar", -"_%n day go_::_%n days ago_" => array("Prieš %n dieną","Prieš %n dienas","Prieš %n dienų"), -"last month" => "praeitą mėnesį", -"_%n month ago_::_%n months ago_" => array("Prieš %n mėnesį","Prieš %n mėnesius","Prieš %n mėnesių"), -"last year" => "praeitais metais", -"years ago" => "prieš metus", -"Caused by:" => "Iššaukė:", -"Could not find category \"%s\"" => "Nepavyko rasti kategorijos „%s“" -); -$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/lv.php b/lib/l10n/lv.php deleted file mode 100644 index 4090a36edcc..00000000000 --- a/lib/l10n/lv.php +++ /dev/null @@ -1,55 +0,0 @@ - "Palīdzība", -"Personal" => "Personīgi", -"Settings" => "Iestatījumi", -"Users" => "Lietotāji", -"Admin" => "Administratori", -"Failed to upgrade \"%s\"." => "Kļūda atjauninot \"%s\"", -"web services under your control" => "tīmekļa servisi tavā varā", -"cannot open \"%s\"" => "Nevar atvērt \"%s\"", -"ZIP download is turned off." => "ZIP lejupielādēšana ir izslēgta.", -"Files need to be downloaded one by one." => "Datnes var lejupielādēt tikai katru atsevišķi.", -"Back to Files" => "Atpakaļ pie datnēm", -"Selected files too large to generate zip file." => "Izvēlētās datnes ir pārāk lielas, lai izveidotu zip datni.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Lejupielādējiet savus failus mazākās daļās, atsevišķi vai palūdziet tos administratoram.", -"Application is not enabled" => "Lietotne nav aktivēta", -"Authentication error" => "Autentifikācijas kļūda", -"Token expired. Please reload page." => "Pilnvarai ir beidzies termiņš. Lūdzu, pārlādējiet lapu.", -"Files" => "Datnes", -"Text" => "Teksts", -"Images" => "Attēli", -"%s enter the database username." => "%s ievadiet datubāzes lietotājvārdu.", -"%s enter the database name." => "%s ievadiet datubāzes nosaukumu.", -"%s you may not use dots in the database name" => "%s datubāžu nosaukumos nedrīkst izmantot punktus", -"MS SQL username and/or password not valid: %s" => "Nav derīga MySQL parole un/vai lietotājvārds — %s", -"You need to enter either an existing account or the administrator." => "Jums jāievada vai nu esošs vai administratora konts.", -"MySQL username and/or password not valid" => "Nav derīga MySQL parole un/vai lietotājvārds", -"DB Error: \"%s\"" => "DB kļūda — “%s”", -"Offending command was: \"%s\"" => "Vainīgā komanda bija “%s”", -"MySQL user '%s'@'localhost' exists already." => "MySQL lietotājs %s'@'localhost' jau eksistē.", -"Drop this user from MySQL" => "Izmest šo lietotāju no MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL lietotājs '%s'@'%%' jau eksistē", -"Drop this user from MySQL." => "Izmest šo lietotāju no MySQL.", -"Oracle connection could not be established" => "Nevar izveidot savienojumu ar Oracle", -"Oracle username and/or password not valid" => "Nav derīga Oracle parole un/vai lietotājvārds", -"Offending command was: \"%s\", name: %s, password: %s" => "Vainīgā komanda bija \"%s\", vārds: %s, parole: %s", -"PostgreSQL username and/or password not valid" => "Nav derīga PostgreSQL parole un/vai lietotājvārds", -"Set an admin username." => "Iestatiet administratora lietotājvārdu.", -"Set an admin password." => "Iestatiet administratora paroli.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Jūsu serveris vēl nav pareizi iestatīts, lai ļautu sinhronizēt datnes, jo izskatās, ka WebDAV saskarne ir salauzta.", -"Please double check the installation guides." => "Lūdzu, vēlreiz pārbaudiet instalēšanas palīdzību.", -"seconds ago" => "sekundes atpakaļ", -"_%n minute ago_::_%n minutes ago_" => array("","","Pirms %n minūtēm"), -"_%n hour ago_::_%n hours ago_" => array("","","Pirms %n stundām"), -"today" => "šodien", -"yesterday" => "vakar", -"_%n day go_::_%n days ago_" => array("","","Pirms %n dienām"), -"last month" => "pagājušajā mēnesī", -"_%n month ago_::_%n months ago_" => array("","","Pirms %n mēnešiem"), -"last year" => "gājušajā gadā", -"years ago" => "gadus atpakaļ", -"Caused by:" => "Cēlonis:", -"Could not find category \"%s\"" => "Nevarēja atrast kategoriju “%s”" -); -$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"; diff --git a/lib/l10n/mk.php b/lib/l10n/mk.php deleted file mode 100644 index 69d4a1cb694..00000000000 --- a/lib/l10n/mk.php +++ /dev/null @@ -1,31 +0,0 @@ - "Помош", -"Personal" => "Лично", -"Settings" => "Подесувања", -"Users" => "Корисници", -"Admin" => "Админ", -"web services under your control" => "веб сервиси под Ваша контрола", -"ZIP download is turned off." => "Преземање во ZIP е исклучено", -"Files need to be downloaded one by one." => "Датотеките треба да се симнат една по една.", -"Back to Files" => "Назад кон датотеки", -"Selected files too large to generate zip file." => "Избраните датотеки се преголеми за да се генерира zip.", -"Application is not enabled" => "Апликацијата не е овозможена", -"Authentication error" => "Грешка во автентикација", -"Token expired. Please reload page." => "Жетонот е истечен. Ве молам превчитајте ја страницата.", -"Files" => "Датотеки", -"Text" => "Текст", -"Images" => "Слики", -"seconds ago" => "пред секунди", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "денеска", -"yesterday" => "вчера", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "минатиот месец", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "минатата година", -"years ago" => "пред години", -"Could not find category \"%s\"" => "Не можам да најдам категорија „%s“" -); -$PLURAL_FORMS = "nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"; diff --git a/lib/l10n/ml_IN.php b/lib/l10n/ml_IN.php deleted file mode 100644 index 15f78e0bce6..00000000000 --- a/lib/l10n/ml_IN.php +++ /dev/null @@ -1,8 +0,0 @@ - array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ms_MY.php b/lib/l10n/ms_MY.php deleted file mode 100644 index 17ef07f83dd..00000000000 --- a/lib/l10n/ms_MY.php +++ /dev/null @@ -1,17 +0,0 @@ - "Bantuan", -"Personal" => "Peribadi", -"Settings" => "Tetapan", -"Users" => "Pengguna", -"Admin" => "Admin", -"web services under your control" => "Perkhidmatan web di bawah kawalan anda", -"Authentication error" => "Ralat pengesahan", -"Files" => "Fail-fail", -"Text" => "Teks", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"_%n day go_::_%n days ago_" => array(""), -"_%n month ago_::_%n months ago_" => array("") -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/my_MM.php b/lib/l10n/my_MM.php deleted file mode 100644 index 5f4b6ddc820..00000000000 --- a/lib/l10n/my_MM.php +++ /dev/null @@ -1,27 +0,0 @@ - "အကူအညီ", -"Users" => "သုံးစွဲသူ", -"Admin" => "အက်ဒမင်", -"web services under your control" => "သင်၏ထိန်းချုပ်မှု့အောက်တွင်ရှိသော Web services", -"ZIP download is turned off." => "ZIP ဒေါင်းလုတ်ကိုပိတ်ထားသည်", -"Files need to be downloaded one by one." => "ဖိုင်များသည် တစ်ခုပြီး တစ်ခုဒေါင်းလုတ်ချရန်လိုအပ်သည်", -"Back to Files" => "ဖိုင်သို့ပြန်သွားမည်", -"Selected files too large to generate zip file." => "zip ဖိုင်အဖြစ်ပြုလုပ်ရန် ရွေးချယ်ထားသောဖိုင်များသည် အရမ်းကြီးလွန်းသည်", -"Authentication error" => "ခွင့်ပြုချက်မအောင်မြင်", -"Files" => "ဖိုင်များ", -"Text" => "စာသား", -"Images" => "ပုံရိပ်များ", -"seconds ago" => "စက္ကန့်အနည်းငယ်က", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "ယနေ့", -"yesterday" => "မနေ့က", -"_%n day go_::_%n days ago_" => array(""), -"last month" => "ပြီးခဲ့သောလ", -"_%n month ago_::_%n months ago_" => array(""), -"last year" => "မနှစ်က", -"years ago" => "နှစ် အရင်က", -"Could not find category \"%s\"" => "\"%s\"ခေါင်းစဉ်ကို ရှာမတွေ့ပါ" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/nb_NO.php b/lib/l10n/nb_NO.php deleted file mode 100644 index 8e7d095d369..00000000000 --- a/lib/l10n/nb_NO.php +++ /dev/null @@ -1,33 +0,0 @@ - "Hjelp", -"Personal" => "Personlig", -"Settings" => "Innstillinger", -"Users" => "Brukere", -"Admin" => "Admin", -"web services under your control" => "web tjenester du kontrollerer", -"ZIP download is turned off." => "ZIP-nedlasting av avslått", -"Files need to be downloaded one by one." => "Filene må lastes ned en om gangen", -"Back to Files" => "Tilbake til filer", -"Selected files too large to generate zip file." => "De valgte filene er for store til å kunne generere ZIP-fil", -"Application is not enabled" => "Applikasjon er ikke påslått", -"Authentication error" => "Autentikasjonsfeil", -"Token expired. Please reload page." => "Symbol utløpt. Vennligst last inn siden på nytt.", -"Files" => "Filer", -"Text" => "Tekst", -"Images" => "Bilder", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din nettservev er ikke konfigurert korrekt for filsynkronisering. WebDAV ser ut til å ikke funkere.", -"Please double check the installation guides." => "Vennligst dobbelsjekk installasjonsguiden.", -"seconds ago" => "sekunder siden", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "i dag", -"yesterday" => "i går", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "forrige måned", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "forrige år", -"years ago" => "år siden", -"Could not find category \"%s\"" => "Kunne ikke finne kategori \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ne.php b/lib/l10n/ne.php deleted file mode 100644 index 15f78e0bce6..00000000000 --- a/lib/l10n/ne.php +++ /dev/null @@ -1,8 +0,0 @@ - array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/nl.php b/lib/l10n/nl.php deleted file mode 100644 index 20374f1f0f8..00000000000 --- a/lib/l10n/nl.php +++ /dev/null @@ -1,72 +0,0 @@ - "App \"%s\" kan niet worden geïnstalleerd omdat die niet compatible is met deze versie van ownCloud.", -"No app name specified" => "De app naam is niet gespecificeerd.", -"Help" => "Help", -"Personal" => "Persoonlijk", -"Settings" => "Instellingen", -"Users" => "Gebruikers", -"Admin" => "Beheerder", -"Failed to upgrade \"%s\"." => "Upgrade \"%s\" mislukt.", -"Custom profile pictures don't work with encryption yet" => "Maatwerk profielafbeelding werkt nog niet met versleuteling", -"Unknown filetype" => "Onbekend bestandsformaat", -"Invalid image" => "Ongeldige afbeelding", -"web services under your control" => "Webdiensten in eigen beheer", -"cannot open \"%s\"" => "Kon \"%s\" niet openen", -"ZIP download is turned off." => "ZIP download is uitgeschakeld.", -"Files need to be downloaded one by one." => "Bestanden moeten één voor één worden gedownload.", -"Back to Files" => "Terug naar bestanden", -"Selected files too large to generate zip file." => "De geselecteerde bestanden zijn te groot om een zip bestand te maken.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Download de bestanden in kleinere brokken, appart of vraag uw administrator.", -"No source specified when installing app" => "Geen bron opgegeven bij installatie van de app", -"No href specified when installing app from http" => "Geen href opgegeven bij installeren van de app vanaf http", -"No path specified when installing app from local file" => "Geen pad opgegeven bij installeren van de app vanaf een lokaal bestand", -"Archives of type %s are not supported" => "Archiefbestanden van type %s niet ondersteund", -"Failed to open archive when installing app" => "Kon archiefbestand bij installatie van de app niet openen", -"App does not provide an info.xml file" => "De app heeft geen info.xml bestand", -"App can't be installed because of not allowed code in the App" => "De app kan niet worden geïnstalleerd wegens onjuiste code in de app", -"App can't be installed because it is not compatible with this version of ownCloud" => "De app kan niet worden geïnstalleerd omdat die niet compatible is met deze versie van ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "De app kan niet worden geïnstallerd omdat het de true tag bevat die niet is toegestaan voor niet gepubliceerde apps", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "De app kan niet worden geïnstalleerd omdat de versie in info.xml/version niet dezelfde is als de versie zoals die in de app store staat vermeld", -"App directory already exists" => "App directory bestaat al", -"Can't create app folder. Please fix permissions. %s" => "Kan de app map niet aanmaken, Herstel de permissies. %s", -"Application is not enabled" => "De applicatie is niet actief", -"Authentication error" => "Authenticatie fout", -"Token expired. Please reload page." => "Token verlopen. Herlaad de pagina.", -"Files" => "Bestanden", -"Text" => "Tekst", -"Images" => "Afbeeldingen", -"%s enter the database username." => "%s opgeven database gebruikersnaam.", -"%s enter the database name." => "%s opgeven databasenaam.", -"%s you may not use dots in the database name" => "%s er mogen geen puntjes in de databasenaam voorkomen", -"MS SQL username and/or password not valid: %s" => "MS SQL gebruikersnaam en/of wachtwoord niet geldig: %s", -"You need to enter either an existing account or the administrator." => "Geef of een bestaand account op of het beheerdersaccount.", -"MySQL username and/or password not valid" => "MySQL gebruikersnaam en/of wachtwoord ongeldig", -"DB Error: \"%s\"" => "DB Fout: \"%s\"", -"Offending command was: \"%s\"" => "Onjuiste commande was: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL gebruiker '%s'@'localhost' bestaat al.", -"Drop this user from MySQL" => "Verwijder deze gebruiker uit MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQL gebruiker '%s'@'%%' bestaat al", -"Drop this user from MySQL." => "Verwijder deze gebruiker uit MySQL.", -"Oracle connection could not be established" => "Er kon geen verbinding met Oracle worden bereikt", -"Oracle username and/or password not valid" => "Oracle gebruikersnaam en/of wachtwoord ongeldig", -"Offending command was: \"%s\", name: %s, password: %s" => "Onjuiste commando was: \"%s\", naam: %s, wachtwoord: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig", -"Set an admin username." => "Stel de gebruikersnaam van de beheerder in.", -"Set an admin password." => "Stel een beheerderswachtwoord in.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Uw webserver is nog niet goed ingesteld voor bestandssynchronisatie omdat de WebDAV interface verbroken lijkt.", -"Please double check the installation guides." => "Controleer de installatiehandleiding goed.", -"seconds ago" => "seconden geleden", -"_%n minute ago_::_%n minutes ago_" => array("%n minuut geleden","%n minuten geleden"), -"_%n hour ago_::_%n hours ago_" => array("%n uur geleden","%n uur geleden"), -"today" => "vandaag", -"yesterday" => "gisteren", -"_%n day go_::_%n days ago_" => array("%n dag terug","%n dagen geleden"), -"last month" => "vorige maand", -"_%n month ago_::_%n months ago_" => array("%n maand geleden","%n maanden geleden"), -"last year" => "vorig jaar", -"years ago" => "jaar geleden", -"Caused by:" => "Gekomen door:", -"Could not find category \"%s\"" => "Kon categorie \"%s\" niet vinden" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/nn_NO.php b/lib/l10n/nn_NO.php deleted file mode 100644 index e8bf8dfdef4..00000000000 --- a/lib/l10n/nn_NO.php +++ /dev/null @@ -1,27 +0,0 @@ - "Hjelp", -"Personal" => "Personleg", -"Settings" => "Innstillingar", -"Users" => "Brukarar", -"Admin" => "Administrer", -"Unknown filetype" => "Ukjend filtype", -"Invalid image" => "Ugyldig bilete", -"web services under your control" => "Vev tjenester under din kontroll", -"Authentication error" => "Feil i autentisering", -"Files" => "Filer", -"Text" => "Tekst", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Tenaren din er ikkje enno rett innstilt til å tilby filsynkronisering sidan WebDAV-grensesnittet ser ut til å vera øydelagt.", -"Please double check the installation guides." => "Ver venleg og dobbeltsjekk installasjonsrettleiinga.", -"seconds ago" => "sekund sidan", -"_%n minute ago_::_%n minutes ago_" => array("","%n minutt sidan"), -"_%n hour ago_::_%n hours ago_" => array("","%n timar sidan"), -"today" => "i dag", -"yesterday" => "i går", -"_%n day go_::_%n days ago_" => array("","%n dagar sidan"), -"last month" => "førre månad", -"_%n month ago_::_%n months ago_" => array("","%n månadar sidan"), -"last year" => "i fjor", -"years ago" => "år sidan" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/nqo.php b/lib/l10n/nqo.php deleted file mode 100644 index e7b09649a24..00000000000 --- a/lib/l10n/nqo.php +++ /dev/null @@ -1,8 +0,0 @@ - array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"_%n day go_::_%n days ago_" => array(""), -"_%n month ago_::_%n months ago_" => array("") -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/oc.php b/lib/l10n/oc.php deleted file mode 100644 index 40a527cc76c..00000000000 --- a/lib/l10n/oc.php +++ /dev/null @@ -1,25 +0,0 @@ - "Ajuda", -"Personal" => "Personal", -"Settings" => "Configuracion", -"Users" => "Usancièrs", -"Admin" => "Admin", -"web services under your control" => "Services web jos ton contraròtle", -"ZIP download is turned off." => "Avalcargar los ZIP es inactiu.", -"Files need to be downloaded one by one." => "Los fichièrs devan èsser avalcargats un per un.", -"Back to Files" => "Torna cap als fichièrs", -"Authentication error" => "Error d'autentificacion", -"Files" => "Fichièrs", -"seconds ago" => "segonda a", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "uèi", -"yesterday" => "ièr", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "mes passat", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "an passat", -"years ago" => "ans a" -); -$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/l10n/pa.php b/lib/l10n/pa.php deleted file mode 100644 index 069fea6e710..00000000000 --- a/lib/l10n/pa.php +++ /dev/null @@ -1,16 +0,0 @@ - "ਸੈਟਿੰਗ", -"Files" => "ਫਾਇਲਾਂ", -"seconds ago" => "ਸਕਿੰਟ ਪਹਿਲਾਂ", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "ਅੱਜ", -"yesterday" => "ਕੱਲ੍ਹ", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "ਪਿਛਲੇ ਮਹੀਨੇ", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "ਪਿਛਲੇ ਸਾਲ", -"years ago" => "ਸਾਲਾਂ ਪਹਿਲਾਂ" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/pl.php b/lib/l10n/pl.php deleted file mode 100644 index 270559b4e50..00000000000 --- a/lib/l10n/pl.php +++ /dev/null @@ -1,72 +0,0 @@ - "Aplikacja \"%s\" nie może zostać zainstalowana, ponieważ nie jest zgodna z tą wersją ownCloud.", -"No app name specified" => "Nie określono nazwy aplikacji", -"Help" => "Pomoc", -"Personal" => "Osobiste", -"Settings" => "Ustawienia", -"Users" => "Użytkownicy", -"Admin" => "Administrator", -"Failed to upgrade \"%s\"." => "Błąd przy aktualizacji \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Domyślny profil zdjęć nie działa z szyfrowaniem jeszcze", -"Unknown filetype" => "Nieznany typ pliku", -"Invalid image" => "Błędne zdjęcie", -"web services under your control" => "Kontrolowane serwisy", -"cannot open \"%s\"" => "Nie można otworzyć \"%s\"", -"ZIP download is turned off." => "Pobieranie ZIP jest wyłączone.", -"Files need to be downloaded one by one." => "Pliki muszą zostać pobrane pojedynczo.", -"Back to Files" => "Wróć do plików", -"Selected files too large to generate zip file." => "Wybrane pliki są zbyt duże, aby wygenerować plik zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Pobierz pliki w mniejszy kawałkach, oddzielnie lub poproś administratora o zwiększenie limitu.", -"No source specified when installing app" => "Nie określono źródła podczas instalacji aplikacji", -"No href specified when installing app from http" => "Nie określono linku skąd aplikacja ma być zainstalowana", -"No path specified when installing app from local file" => "Nie określono lokalnego pliku z którego miała być instalowana aplikacja", -"Archives of type %s are not supported" => "Typ archiwum %s nie jest obsługiwany", -"Failed to open archive when installing app" => "Nie udało się otworzyć archiwum podczas instalacji aplikacji", -"App does not provide an info.xml file" => "Aplikacja nie posiada pliku info.xml", -"App can't be installed because of not allowed code in the App" => "Aplikacja nie może być zainstalowany ponieważ nie dopuszcza kod w aplikacji", -"App can't be installed because it is not compatible with this version of ownCloud" => "Aplikacja nie może zostać zainstalowana ponieważ jest niekompatybilna z tą wersja ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Aplikacja nie może być zainstalowana ponieważ true tag nie jest true , co nie jest dozwolone dla aplikacji nie wysłanych", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Nie można zainstalować aplikacji, ponieważ w wersji info.xml/version nie jest taka sama, jak wersja z app store", -"App directory already exists" => "Katalog aplikacji już isnieje", -"Can't create app folder. Please fix permissions. %s" => "Nie mogę utworzyć katalogu aplikacji. Proszę popraw uprawnienia. %s", -"Application is not enabled" => "Aplikacja nie jest włączona", -"Authentication error" => "Błąd uwierzytelniania", -"Token expired. Please reload page." => "Token wygasł. Proszę ponownie załadować stronę.", -"Files" => "Pliki", -"Text" => "Połączenie tekstowe", -"Images" => "Obrazy", -"%s enter the database username." => "%s wpisz nazwę użytkownika do bazy", -"%s enter the database name." => "%s wpisz nazwę bazy.", -"%s you may not use dots in the database name" => "%s nie można używać kropki w nazwie bazy danych", -"MS SQL username and/or password not valid: %s" => "Nazwa i/lub hasło serwera MS SQL jest niepoprawne: %s.", -"You need to enter either an existing account or the administrator." => "Należy wprowadzić istniejące konto użytkownika lub administratora.", -"MySQL username and/or password not valid" => "MySQL: Nazwa użytkownika i/lub hasło jest niepoprawne", -"DB Error: \"%s\"" => "Błąd DB: \"%s\"", -"Offending command was: \"%s\"" => "Niepoprawna komenda: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Użytkownik MySQL '%s'@'localhost' już istnieje", -"Drop this user from MySQL" => "Usuń tego użytkownika z MySQL", -"MySQL user '%s'@'%%' already exists" => "Użytkownik MySQL '%s'@'%%t' już istnieje", -"Drop this user from MySQL." => "Usuń tego użytkownika z MySQL.", -"Oracle connection could not be established" => "Nie można ustanowić połączenia z bazą Oracle", -"Oracle username and/or password not valid" => "Oracle: Nazwa użytkownika i/lub hasło jest niepoprawne", -"Offending command was: \"%s\", name: %s, password: %s" => "Niepoprawne polecania: \"%s\", nazwa: %s, hasło: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL: Nazwa użytkownika i/lub hasło jest niepoprawne", -"Set an admin username." => "Ustaw nazwę administratora.", -"Set an admin password." => "Ustaw hasło administratora.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serwer internetowy nie jest jeszcze poprawnie skonfigurowany, aby umożliwić synchronizację plików, ponieważ interfejs WebDAV wydaje się być uszkodzony.", -"Please double check the installation guides." => "Sprawdź ponownie przewodniki instalacji.", -"Could not find category \"%s\"" => "Nie można odnaleźć kategorii \"%s\"", -"seconds ago" => "sekund temu", -"_%n minute ago_::_%n minutes ago_" => array("%n minute temu","%n minut temu","%n minut temu"), -"_%n hour ago_::_%n hours ago_" => array("%n godzinę temu","%n godzin temu","%n godzin temu"), -"today" => "dziś", -"yesterday" => "wczoraj", -"_%n day go_::_%n days ago_" => array("%n dzień temu","%n dni temu","%n dni temu"), -"last month" => "w zeszłym miesiącu", -"_%n month ago_::_%n months ago_" => array("%n miesiąc temu","%n miesięcy temu","%n miesięcy temu"), -"last year" => "w zeszłym roku", -"years ago" => "lat temu", -"Caused by:" => "Spowodowane przez:" -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/pl_PL.php b/lib/l10n/pl_PL.php deleted file mode 100644 index 5494e3dab25..00000000000 --- a/lib/l10n/pl_PL.php +++ /dev/null @@ -1,5 +0,0 @@ - "Ustawienia" -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/pt_BR.php b/lib/l10n/pt_BR.php deleted file mode 100644 index 7a580799701..00000000000 --- a/lib/l10n/pt_BR.php +++ /dev/null @@ -1,72 +0,0 @@ - "O aplicativo \"%s\" não pode ser instalado porque não é compatível com esta versão do ownCloud.", -"No app name specified" => "O nome do aplicativo não foi especificado.", -"Help" => "Ajuda", -"Personal" => "Pessoal", -"Settings" => "Ajustes", -"Users" => "Usuários", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Falha na atualização de \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Fotos de perfil personalizados ainda não funcionam com criptografia", -"Unknown filetype" => "Tipo de arquivo desconhecido", -"Invalid image" => "Imagem inválida", -"web services under your control" => "serviços web sob seu controle", -"cannot open \"%s\"" => "não pode abrir \"%s\"", -"ZIP download is turned off." => "Download ZIP está desligado.", -"Files need to be downloaded one by one." => "Arquivos precisam ser baixados um de cada vez.", -"Back to Files" => "Voltar para Arquivos", -"Selected files too large to generate zip file." => "Arquivos selecionados são muito grandes para gerar arquivo zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Baixe os arquivos em pedaços menores, separadamente ou solicite educadamente ao seu administrador.", -"No source specified when installing app" => "Nenhuma fonte foi especificada enquanto instalava o aplicativo", -"No href specified when installing app from http" => "Nenhuma href foi especificada enquanto instalava o aplicativo de httml", -"No path specified when installing app from local file" => "Nenhum caminho foi especificado enquanto instalava o aplicativo do arquivo local", -"Archives of type %s are not supported" => "Arquivos do tipo %s não são suportados", -"Failed to open archive when installing app" => "Falha para abrir o arquivo enquanto instalava o aplicativo", -"App does not provide an info.xml file" => "O aplicativo não fornece um arquivo info.xml", -"App can't be installed because of not allowed code in the App" => "O aplicativo não pode ser instalado por causa do código não permitido no Aplivativo", -"App can't be installed because it is not compatible with this version of ownCloud" => "O aplicativo não pode ser instalado porque não é compatível com esta versão do ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "O aplicativo não pode ser instalado porque ele contém a marca verdadeiro que não é permitido para aplicações não embarcadas", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "O aplicativo não pode ser instalado porque a versão em info.xml /versão não é a mesma que a versão relatada na App Store", -"App directory already exists" => "Diretório App já existe", -"Can't create app folder. Please fix permissions. %s" => "Não é possível criar pasta app. Corrija as permissões. %s", -"Application is not enabled" => "Aplicação não está habilitada", -"Authentication error" => "Erro de autenticação", -"Token expired. Please reload page." => "Token expirou. Por favor recarregue a página.", -"Files" => "Arquivos", -"Text" => "Texto", -"Images" => "Imagens", -"%s enter the database username." => "%s insira o nome de usuário do banco de dados.", -"%s enter the database name." => "%s insira o nome do banco de dados.", -"%s you may not use dots in the database name" => "%s você não pode usar pontos no nome do banco de dados", -"MS SQL username and/or password not valid: %s" => "Nome de usuário e/ou senha MS SQL inválido(s): %s", -"You need to enter either an existing account or the administrator." => "Você precisa inserir uma conta existente ou o administrador.", -"MySQL username and/or password not valid" => "Nome de usuário e/ou senha MySQL inválido(s)", -"DB Error: \"%s\"" => "Erro no BD: \"%s\"", -"Offending command was: \"%s\"" => "Comando ofensivo era: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "O usuário MySQL '%s'@'localhost' já existe.", -"Drop this user from MySQL" => "Derrubar este usuário do MySQL", -"MySQL user '%s'@'%%' already exists" => "Usuário MySQL '%s'@'%%' já existe", -"Drop this user from MySQL." => "Derrube este usuário do MySQL.", -"Oracle connection could not be established" => "Conexão Oracle não pode ser estabelecida", -"Oracle username and/or password not valid" => "Nome de usuário e/ou senha Oracle inválido(s)", -"Offending command was: \"%s\", name: %s, password: %s" => "Comando ofensivo era: \"%s\", nome: %s, senha: %s", -"PostgreSQL username and/or password not valid" => "Nome de usuário e/ou senha PostgreSQL inválido(s)", -"Set an admin username." => "Defina um nome de usuário de administrador.", -"Set an admin password." => "Defina uma senha de administrador.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Seu servidor web não está configurado corretamente para permitir sincronização de arquivos porque a interface WebDAV parece estar quebrada.", -"Please double check the installation guides." => "Por favor, confira os guias de instalação.", -"seconds ago" => "segundos atrás", -"_%n minute ago_::_%n minutes ago_" => array("","ha %n minutos"), -"_%n hour ago_::_%n hours ago_" => array("","ha %n horas"), -"today" => "hoje", -"yesterday" => "ontem", -"_%n day go_::_%n days ago_" => array("","ha %n dias"), -"last month" => "último mês", -"_%n month ago_::_%n months ago_" => array("","ha %n meses"), -"last year" => "último ano", -"years ago" => "anos atrás", -"Caused by:" => "Causados ​​por:", -"Could not find category \"%s\"" => "Impossível localizar categoria \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/l10n/pt_PT.php b/lib/l10n/pt_PT.php deleted file mode 100644 index 6e2bcba7b10..00000000000 --- a/lib/l10n/pt_PT.php +++ /dev/null @@ -1,57 +0,0 @@ - "Ajuda", -"Personal" => "Pessoal", -"Settings" => "Configurações", -"Users" => "Utilizadores", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "A actualização \"%s\" falhou.", -"Unknown filetype" => "Ficheiro desconhecido", -"Invalid image" => "Imagem inválida", -"web services under your control" => "serviços web sob o seu controlo", -"cannot open \"%s\"" => "Não foi possível abrir \"%s\"", -"ZIP download is turned off." => "Descarregamento em ZIP está desligado.", -"Files need to be downloaded one by one." => "Os ficheiros precisam de ser descarregados um por um.", -"Back to Files" => "Voltar a Ficheiros", -"Selected files too large to generate zip file." => "Os ficheiros seleccionados são grandes demais para gerar um ficheiro zip.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descarregue os ficheiros em partes menores, separados ou peça gentilmente ao seu administrador.", -"Application is not enabled" => "A aplicação não está activada", -"Authentication error" => "Erro na autenticação", -"Token expired. Please reload page." => "O token expirou. Por favor recarregue a página.", -"Files" => "Ficheiros", -"Text" => "Texto", -"Images" => "Imagens", -"%s enter the database username." => "%s introduza o nome de utilizador da base de dados", -"%s enter the database name." => "%s introduza o nome da base de dados", -"%s you may not use dots in the database name" => "%s não é permitido utilizar pontos (.) no nome da base de dados", -"MS SQL username and/or password not valid: %s" => "Nome de utilizador/password do MySQL é inválido: %s", -"You need to enter either an existing account or the administrator." => "Precisa de introduzir uma conta existente ou de administrador", -"MySQL username and/or password not valid" => "Nome de utilizador/password do MySQL inválida", -"DB Error: \"%s\"" => "Erro na BD: \"%s\"", -"Offending command was: \"%s\"" => "O comando gerador de erro foi: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "O utilizador '%s'@'localhost' do MySQL já existe.", -"Drop this user from MySQL" => "Eliminar este utilizador do MySQL", -"MySQL user '%s'@'%%' already exists" => "O utilizador '%s'@'%%' do MySQL já existe", -"Drop this user from MySQL." => "Eliminar este utilizador do MySQL", -"Oracle connection could not be established" => "Não foi possível estabelecer a ligação Oracle", -"Oracle username and/or password not valid" => "Nome de utilizador/password do Oracle inválida", -"Offending command was: \"%s\", name: %s, password: %s" => "O comando gerador de erro foi: \"%s\", nome: %s, password: %s", -"PostgreSQL username and/or password not valid" => "Nome de utilizador/password do PostgreSQL inválido", -"Set an admin username." => "Definir um nome de utilizador de administrador", -"Set an admin password." => "Definiar uma password de administrador", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "O seu servidor web não está configurado correctamente para autorizar sincronização de ficheiros, pois o interface WebDAV parece estar com problemas.", -"Please double check the installation guides." => "Por favor verifique installation guides.", -"seconds ago" => "Minutos atrás", -"_%n minute ago_::_%n minutes ago_" => array("","%n minutos atrás"), -"_%n hour ago_::_%n hours ago_" => array("","%n horas atrás"), -"today" => "hoje", -"yesterday" => "ontem", -"_%n day go_::_%n days ago_" => array("","%n dias atrás"), -"last month" => "ultímo mês", -"_%n month ago_::_%n months ago_" => array("","%n meses atrás"), -"last year" => "ano passado", -"years ago" => "anos atrás", -"Caused by:" => "Causado por:", -"Could not find category \"%s\"" => "Não foi encontrado a categoria \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ro.php b/lib/l10n/ro.php deleted file mode 100644 index 76dafcd03e0..00000000000 --- a/lib/l10n/ro.php +++ /dev/null @@ -1,35 +0,0 @@ - "Ajutor", -"Personal" => "Personal", -"Settings" => "Setări", -"Users" => "Utilizatori", -"Admin" => "Admin", -"Unknown filetype" => "Tip fișier necunoscut", -"Invalid image" => "Imagine invalidă", -"web services under your control" => "servicii web controlate de tine", -"ZIP download is turned off." => "Descărcarea ZIP este dezactivată.", -"Files need to be downloaded one by one." => "Fișierele trebuie descărcate unul câte unul.", -"Back to Files" => "Înapoi la fișiere", -"Selected files too large to generate zip file." => "Fișierele selectate sunt prea mari pentru a genera un fișier zip.", -"Application is not enabled" => "Aplicația nu este activată", -"Authentication error" => "Eroare la autentificare", -"Token expired. Please reload page." => "Token expirat. Te rugăm să reîncarci pagina.", -"Files" => "Fișiere", -"Text" => "Text", -"Images" => "Imagini", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serverul de web nu este încă setat corespunzător pentru a permite sincronizarea fișierelor deoarece interfața WebDAV pare a fi întreruptă.", -"Please double check the installation guides." => "Vă rugăm să verificați ghiduri de instalare.", -"seconds ago" => "secunde în urmă", -"_%n minute ago_::_%n minutes ago_" => array("","","acum %n minute"), -"_%n hour ago_::_%n hours ago_" => array("","","acum %n ore"), -"today" => "astăzi", -"yesterday" => "ieri", -"_%n day go_::_%n days ago_" => array("","","acum %n zile"), -"last month" => "ultima lună", -"_%n month ago_::_%n months ago_" => array("","",""), -"last year" => "ultimul an", -"years ago" => "ani în urmă", -"Could not find category \"%s\"" => "Cloud nu a gasit categoria \"%s\"" -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"; diff --git a/lib/l10n/ru.php b/lib/l10n/ru.php deleted file mode 100644 index 501065f8b5f..00000000000 --- a/lib/l10n/ru.php +++ /dev/null @@ -1,72 +0,0 @@ - "Приложение \"%s\" нельзя установить, так как оно не совместимо с текущей версией ownCloud.", -"No app name specified" => "Не выбрано имя приложения", -"Help" => "Помощь", -"Personal" => "Личное", -"Settings" => "Конфигурация", -"Users" => "Пользователи", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Не смог обновить \"%s\".", -"Custom profile pictures don't work with encryption yet" => "Пользовательские картинки профиля ещё не поддерживают шифрование", -"Unknown filetype" => "Неизвестный тип файла", -"Invalid image" => "Изображение повреждено", -"web services under your control" => "веб-сервисы под вашим управлением", -"cannot open \"%s\"" => "не могу открыть \"%s\"", -"ZIP download is turned off." => "ZIP-скачивание отключено.", -"Files need to be downloaded one by one." => "Файлы должны быть загружены по одному.", -"Back to Files" => "Назад к файлам", -"Selected files too large to generate zip file." => "Выбранные файлы слишком велики, чтобы создать zip файл.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Загрузите файл маленьшими порциями, раздельно или вежливо попросите Вашего администратора.", -"No source specified when installing app" => "Не указан источник при установке приложения", -"No href specified when installing app from http" => "Не указан атрибут href при установке приложения через http", -"No path specified when installing app from local file" => "Не указан путь при установке приложения из локального файла", -"Archives of type %s are not supported" => "Архивы %s не поддерживаются", -"Failed to open archive when installing app" => "Не возможно открыть архив при установке приложения", -"App does not provide an info.xml file" => "Приложение не имеет файла info.xml", -"App can't be installed because of not allowed code in the App" => "Приложение невозможно установить. В нем содержится запрещенный код.", -"App can't be installed because it is not compatible with this version of ownCloud" => "Приложение невозможно установить. Не совместимо с текущей версией ownCloud.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Приложение невозможно установить. Оно содержит параметр true который не допустим для приложений, не входящих в поставку.", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Приложение невозможно установить. Версия в info.xml/version не совпадает с версией заявленной в магазине приложений", -"App directory already exists" => "Папка приложения уже существует", -"Can't create app folder. Please fix permissions. %s" => "Не удалось создать директорию. Исправьте права доступа. %s", -"Application is not enabled" => "Приложение не разрешено", -"Authentication error" => "Ошибка аутентификации", -"Token expired. Please reload page." => "Токен просрочен. Перезагрузите страницу.", -"Files" => "Файлы", -"Text" => "Текст", -"Images" => "Изображения", -"%s enter the database username." => "%s введите имя пользователя базы данных.", -"%s enter the database name." => "%s введите имя базы данных.", -"%s you may not use dots in the database name" => "%s Вы не можете использовать точки в имени базы данных", -"MS SQL username and/or password not valid: %s" => "Имя пользователя и/или пароль MS SQL не подходит: %s", -"You need to enter either an existing account or the administrator." => "Вы должны войти или в существующий аккаунт или под администратором.", -"MySQL username and/or password not valid" => "Неверное имя пользователя и/или пароль MySQL", -"DB Error: \"%s\"" => "Ошибка БД: \"%s\"", -"Offending command was: \"%s\"" => "Вызываемая команда была: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Пользователь MySQL '%s'@'localhost' уже существует.", -"Drop this user from MySQL" => "Удалить этого пользователя из MySQL", -"MySQL user '%s'@'%%' already exists" => "Пользователь MySQL '%s'@'%%' уже существует", -"Drop this user from MySQL." => "Удалить этого пользователя из MySQL.", -"Oracle connection could not be established" => "соединение с Oracle не может быть установлено", -"Oracle username and/or password not valid" => "Неверное имя пользователя и/или пароль Oracle", -"Offending command was: \"%s\", name: %s, password: %s" => "Вызываемая команда была: \"%s\", имя: %s, пароль: %s", -"PostgreSQL username and/or password not valid" => "Неверное имя пользователя и/или пароль PostgreSQL", -"Set an admin username." => "Установить имя пользователя для admin.", -"Set an admin password." => "становит пароль для admin.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш веб сервер до сих пор не настроен правильно для возможности синхронизации файлов, похоже что проблема в неисправности интерфейса WebDAV.", -"Please double check the installation guides." => "Пожалуйста, дважды просмотрите инструкции по установке.", -"seconds ago" => "несколько секунд назад", -"_%n minute ago_::_%n minutes ago_" => array("%n минута назад","%n минуты назад","%n минут назад"), -"_%n hour ago_::_%n hours ago_" => array("%n час назад","%n часа назад","%n часов назад"), -"today" => "сегодня", -"yesterday" => "вчера", -"_%n day go_::_%n days ago_" => array("%n день назад","%n дня назад","%n дней назад"), -"last month" => "в прошлом месяце", -"_%n month ago_::_%n months ago_" => array("%n месяц назад","%n месяца назад","%n месяцев назад"), -"last year" => "в прошлом году", -"years ago" => "несколько лет назад", -"Caused by:" => "Вызвано:", -"Could not find category \"%s\"" => "Категория \"%s\" не найдена" -); -$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/si_LK.php b/lib/l10n/si_LK.php deleted file mode 100644 index d10804cae69..00000000000 --- a/lib/l10n/si_LK.php +++ /dev/null @@ -1,30 +0,0 @@ - "උදව්", -"Personal" => "පෞද්ගලික", -"Settings" => "සිටුවම්", -"Users" => "පරිශීලකයන්", -"Admin" => "පරිපාලක", -"web services under your control" => "ඔබට පාලනය කළ හැකි වෙබ් සේවාවන්", -"ZIP download is turned off." => "ZIP භාගත කිරීම් අක්‍රියයි", -"Files need to be downloaded one by one." => "ගොනු එකින් එක භාගත යුතුයි", -"Back to Files" => "ගොනු වෙතට නැවත යන්න", -"Selected files too large to generate zip file." => "තෝරාගත් ගොනු ZIP ගොනුවක් තැනීමට විශාල වැඩිය.", -"Application is not enabled" => "යෙදුම සක්‍රිය කර නොමැත", -"Authentication error" => "සත්‍යාපන දෝෂයක්", -"Token expired. Please reload page." => "ටෝකනය කල් ඉකුත් වී ඇත. පිටුව නැවුම් කරන්න", -"Files" => "ගොනු", -"Text" => "පෙළ", -"Images" => "අනු රූ", -"seconds ago" => "තත්පරයන්ට පෙර", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "අද", -"yesterday" => "ඊයේ", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "පෙර මාසයේ", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "පෙර අවුරුද්දේ", -"years ago" => "අවුරුදු කීපයකට පෙර" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/sk.php b/lib/l10n/sk.php deleted file mode 100644 index 54812b15a6f..00000000000 --- a/lib/l10n/sk.php +++ /dev/null @@ -1,8 +0,0 @@ - array("","",""), -"_%n hour ago_::_%n hours ago_" => array("","",""), -"_%n day go_::_%n days ago_" => array("","",""), -"_%n month ago_::_%n months ago_" => array("","","") -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/lib/l10n/sk_SK.php b/lib/l10n/sk_SK.php deleted file mode 100644 index 13487b039d6..00000000000 --- a/lib/l10n/sk_SK.php +++ /dev/null @@ -1,69 +0,0 @@ - "Aplikácia \"%s\" nemôže byť nainštalovaná kvôli nekompatibilite z danou verziou ownCloudu.", -"No app name specified" => "Nešpecifikované meno aplikácie", -"Help" => "Pomoc", -"Personal" => "Osobné", -"Settings" => "Nastavenia", -"Users" => "Používatelia", -"Admin" => "Administrátor", -"Failed to upgrade \"%s\"." => "Zlyhala aktualizácia \"%s\".", -"web services under your control" => "webové služby pod Vašou kontrolou", -"cannot open \"%s\"" => "nemožno otvoriť \"%s\"", -"ZIP download is turned off." => "Sťahovanie súborov ZIP je vypnuté.", -"Files need to be downloaded one by one." => "Súbory musia byť nahrávané jeden za druhým.", -"Back to Files" => "Späť na súbory", -"Selected files too large to generate zip file." => "Zvolené súbory sú príliš veľké na vygenerovanie zip súboru.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Stiahnite súbory po menších častiach, samostatne, alebo sa obráťte na správcu.", -"No source specified when installing app" => "Nešpecifikovaný zdroj pri inštalácii aplikácie", -"No href specified when installing app from http" => "Nešpecifikovaný atribút \"href\" pri inštalácii aplikácie pomocou protokolu \"http\"", -"No path specified when installing app from local file" => "Nešpecifikovaná cesta pri inštalácii aplikácie z lokálneho súboru", -"Archives of type %s are not supported" => "Typ archívu %s nie je podporovaný", -"Failed to open archive when installing app" => "Zlyhanie pri otváraní archívu počas inštalácie aplikácie", -"App does not provide an info.xml file" => "Aplikácia neposkytuje súbor info.xml", -"App can't be installed because of not allowed code in the App" => "Aplikácia nemôže byť inštalovaná pre nepovolený kód v aplikácii", -"App can't be installed because it is not compatible with this version of ownCloud" => "Aplikácia nemôže byť inštalovaná pre nekompatibilitu z danou verziou ownCloudu", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Aplikácia nemôže byť inštalovaná pretože obsahuje pravý štítok, ktorý nie je povolený pre zaslané \"shipped\" aplikácie", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Aplikácia nemôže byť inštalovaná pretože verzia v info.xml/version nezodpovedá verzii špecifikovanej v aplikačnom obchode", -"App directory already exists" => "Aplikačný adresár už existuje", -"Can't create app folder. Please fix permissions. %s" => "Nemožno vytvoriť aplikačný priečinok. Prosím upravte povolenia. %s", -"Application is not enabled" => "Aplikácia nie je zapnutá", -"Authentication error" => "Chyba autentifikácie", -"Token expired. Please reload page." => "Token vypršal. Obnovte, prosím, stránku.", -"Files" => "Súbory", -"Text" => "Text", -"Images" => "Obrázky", -"%s enter the database username." => "Zadajte používateľské meno %s databázy..", -"%s enter the database name." => "Zadajte názov databázy pre %s databázy.", -"%s you may not use dots in the database name" => "V názve databázy %s nemôžete používať bodky", -"MS SQL username and/or password not valid: %s" => "Používateľské meno, alebo heslo MS SQL nie je platné: %s", -"You need to enter either an existing account or the administrator." => "Musíte zadať jestvujúci účet alebo administrátora.", -"MySQL username and/or password not valid" => "Používateľské meno a/alebo heslo pre MySQL databázu je neplatné", -"DB Error: \"%s\"" => "Chyba DB: \"%s\"", -"Offending command was: \"%s\"" => "Podozrivý príkaz bol: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Používateľ '%s'@'localhost' už v MySQL existuje.", -"Drop this user from MySQL" => "Zahodiť používateľa z MySQL.", -"MySQL user '%s'@'%%' already exists" => "Používateľ '%s'@'%%' už v MySQL existuje", -"Drop this user from MySQL." => "Zahodiť používateľa z MySQL.", -"Oracle connection could not be established" => "Nie je možné pripojiť sa k Oracle", -"Oracle username and/or password not valid" => "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné", -"Offending command was: \"%s\", name: %s, password: %s" => "Podozrivý príkaz bol: \"%s\", meno: %s, heslo: %s", -"PostgreSQL username and/or password not valid" => "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné", -"Set an admin username." => "Zadajte používateľské meno administrátora.", -"Set an admin password." => "Zadajte heslo administrátora.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Váš webový server nie je správne nastavený na synchronizáciu, pretože rozhranie WebDAV je poškodené.", -"Please double check the installation guides." => "Prosím skontrolujte inštalačnú príručku.", -"seconds ago" => "pred sekundami", -"_%n minute ago_::_%n minutes ago_" => array("","","pred %n minútami"), -"_%n hour ago_::_%n hours ago_" => array("","","pred %n hodinami"), -"today" => "dnes", -"yesterday" => "včera", -"_%n day go_::_%n days ago_" => array("","","pred %n dňami"), -"last month" => "minulý mesiac", -"_%n month ago_::_%n months ago_" => array("","","pred %n mesiacmi"), -"last year" => "minulý rok", -"years ago" => "pred rokmi", -"Caused by:" => "Príčina:", -"Could not find category \"%s\"" => "Nemožno nájsť danú kategóriu \"%s\"" -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/lib/l10n/sl.php b/lib/l10n/sl.php deleted file mode 100644 index 5722191aedf..00000000000 --- a/lib/l10n/sl.php +++ /dev/null @@ -1,51 +0,0 @@ - "Pomoč", -"Personal" => "Osebno", -"Settings" => "Nastavitve", -"Users" => "Uporabniki", -"Admin" => "Skrbništvo", -"web services under your control" => "spletne storitve pod vašim nadzorom", -"ZIP download is turned off." => "Prejemanje datotek v paketu ZIP je onemogočeno.", -"Files need to be downloaded one by one." => "Datoteke je mogoče prejeti le posamično.", -"Back to Files" => "Nazaj na datoteke", -"Selected files too large to generate zip file." => "Izbrane datoteke so prevelike za ustvarjanje datoteke arhiva zip.", -"Application is not enabled" => "Program ni omogočen", -"Authentication error" => "Napaka pri overjanju", -"Token expired. Please reload page." => "Žeton je potekel. Stran je treba ponovno naložiti.", -"Files" => "Datoteke", -"Text" => "Besedilo", -"Images" => "Slike", -"%s enter the database username." => "%s - vnos uporabniškega imena podatkovne zbirke.", -"%s enter the database name." => "%s - vnos imena podatkovne zbirke.", -"%s you may not use dots in the database name" => "%s - v imenu podatkovne zbirke ni dovoljeno uporabljati pik.", -"MS SQL username and/or password not valid: %s" => "Uporabniško ime ali geslo MS SQL ni veljavno: %s", -"You need to enter either an existing account or the administrator." => "Prijaviti se je treba v obstoječi ali pa skrbniški račun.", -"MySQL username and/or password not valid" => "Uporabniško ime ali geslo MySQL ni veljavno", -"DB Error: \"%s\"" => "Napaka podatkovne zbirke: \"%s\"", -"Offending command was: \"%s\"" => "Napačni ukaz je: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Uporabnik MySQL '%s'@'localhost' že obstaja.", -"Drop this user from MySQL" => "Odstrani uporabnika s podatkovne zbirke MySQL", -"MySQL user '%s'@'%%' already exists" => "Uporabnik MySQL '%s'@'%%' že obstaja.", -"Drop this user from MySQL." => "Odstrani uporabnika s podatkovne zbirke MySQL", -"Oracle connection could not be established" => "Povezava z bazo Oracle ni uspela.", -"Oracle username and/or password not valid" => "Uporabniško ime ali geslo Oracle ni veljavno", -"Offending command was: \"%s\", name: %s, password: %s" => "Napačni ukaz je: \"%s\", ime: %s, geslo: %s", -"PostgreSQL username and/or password not valid" => "Uporabniško ime ali geslo PostgreSQL ni veljavno", -"Set an admin username." => "Nastavi uporabniško ime skrbnika.", -"Set an admin password." => "Nastavi geslo skrbnika.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Spletni stražnik še ni ustrezno nastavljen in ne omogoča usklajevanja, saj je nastavitev WebDAV okvarjena.", -"Please double check the installation guides." => "Preverite navodila namestitve.", -"seconds ago" => "pred nekaj sekundami", -"_%n minute ago_::_%n minutes ago_" => array("","","",""), -"_%n hour ago_::_%n hours ago_" => array("","","",""), -"today" => "danes", -"yesterday" => "včeraj", -"_%n day go_::_%n days ago_" => array("","","",""), -"last month" => "zadnji mesec", -"_%n month ago_::_%n months ago_" => array("","","",""), -"last year" => "lansko leto", -"years ago" => "let nazaj", -"Could not find category \"%s\"" => "Kategorije \"%s\" ni mogoče najti." -); -$PLURAL_FORMS = "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"; diff --git a/lib/l10n/sq.php b/lib/l10n/sq.php deleted file mode 100644 index edaa1df2b86..00000000000 --- a/lib/l10n/sq.php +++ /dev/null @@ -1,50 +0,0 @@ - "Ndihmë", -"Personal" => "Personale", -"Settings" => "Parametra", -"Users" => "Përdoruesit", -"Admin" => "Admin", -"web services under your control" => "shërbime web nën kontrollin tënd", -"ZIP download is turned off." => "Shkarimi i skedarëve ZIP është i çaktivizuar.", -"Files need to be downloaded one by one." => "Skedarët duhet të shkarkohen një nga një.", -"Back to Files" => "Kthehu tek skedarët", -"Selected files too large to generate zip file." => "Skedarët e selektuar janë shumë të mëdhenj për të krijuar një skedar ZIP.", -"Application is not enabled" => "Programi nuk është i aktivizuar.", -"Authentication error" => "Veprim i gabuar gjatë vërtetimit të identitetit", -"Token expired. Please reload page." => "Përmbajtja ka skaduar. Ju lutemi ringarkoni faqen.", -"Files" => "Skedarët", -"Text" => "Tekst", -"Images" => "Foto", -"%s enter the database username." => "% shkruani përdoruesin e database-it.", -"%s enter the database name." => "%s shkruani emrin e database-it.", -"%s you may not use dots in the database name" => "%s nuk mund të përdorni pikat tek emri i database-it", -"MS SQL username and/or password not valid: %s" => "Përdoruesi dhe/apo kodi i MS SQL i pavlefshëm: %s", -"You need to enter either an existing account or the administrator." => "Duhet të përdorni një llogari ekzistuese ose llogarinë e administratorit.", -"MySQL username and/or password not valid" => "Përdoruesi dhe/apo kodi i MySQL-it i pavlefshëm.", -"DB Error: \"%s\"" => "Veprim i gabuar i DB-it: \"%s\"", -"Offending command was: \"%s\"" => "Komanda e gabuar ishte: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Përdoruesi MySQL '%s'@'localhost' ekziston.", -"Drop this user from MySQL" => "Eliminoni këtë përdorues nga MySQL", -"MySQL user '%s'@'%%' already exists" => "Përdoruesi MySQL '%s'@'%%' ekziston", -"Drop this user from MySQL." => "Eliminoni këtë përdorues nga MySQL.", -"Oracle username and/or password not valid" => "Përdoruesi dhe/apo kodi i Oracle-it i pavlefshëm", -"Offending command was: \"%s\", name: %s, password: %s" => "Komanda e gabuar ishte: \"%s\", përdoruesi: %s, kodi: %s", -"PostgreSQL username and/or password not valid" => "Përdoruesi dhe/apo kodi i PostgreSQL i pavlefshëm", -"Set an admin username." => "Cakto emrin e administratorit.", -"Set an admin password." => "Cakto kodin e administratorit.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serveri web i juaji nuk është konfiguruar akoma për të lejuar sinkronizimin e skedarëve sepse ndërfaqja WebDAV mund të jetë e dëmtuar.", -"Please double check the installation guides." => "Ju lutemi kontrolloni mirë shoqëruesin e instalimit.", -"seconds ago" => "sekonda më parë", -"_%n minute ago_::_%n minutes ago_" => array("","%n minuta më parë"), -"_%n hour ago_::_%n hours ago_" => array("","%n orë më parë"), -"today" => "sot", -"yesterday" => "dje", -"_%n day go_::_%n days ago_" => array("","%n ditë më parë"), -"last month" => "muajin e shkuar", -"_%n month ago_::_%n months ago_" => array("","%n muaj më parë"), -"last year" => "vitin e shkuar", -"years ago" => "vite më parë", -"Could not find category \"%s\"" => "Kategoria \"%s\" nuk u gjet" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/sr.php b/lib/l10n/sr.php deleted file mode 100644 index 9441d0578fc..00000000000 --- a/lib/l10n/sr.php +++ /dev/null @@ -1,33 +0,0 @@ - "Помоћ", -"Personal" => "Лично", -"Settings" => "Поставке", -"Users" => "Корисници", -"Admin" => "Администратор", -"web services under your control" => "веб сервиси под контролом", -"ZIP download is turned off." => "Преузимање ZIP-а је искључено.", -"Files need to be downloaded one by one." => "Датотеке морате преузимати једну по једну.", -"Back to Files" => "Назад на датотеке", -"Selected files too large to generate zip file." => "Изабране датотеке су превелике да бисте направили ZIP датотеку.", -"Application is not enabled" => "Апликација није омогућена", -"Authentication error" => "Грешка при провери идентитета", -"Token expired. Please reload page." => "Жетон је истекао. Поново учитајте страницу.", -"Files" => "Датотеке", -"Text" => "Текст", -"Images" => "Слике", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш веб сервер тренутно не подржава синхронизацију датотека јер се чини да је WebDAV сучеље неисправно.", -"Please double check the installation guides." => "Погледајте водиче за инсталацију.", -"seconds ago" => "пре неколико секунди", -"_%n minute ago_::_%n minutes ago_" => array("","",""), -"_%n hour ago_::_%n hours ago_" => array("","",""), -"today" => "данас", -"yesterday" => "јуче", -"_%n day go_::_%n days ago_" => array("","",""), -"last month" => "прошлог месеца", -"_%n month ago_::_%n months ago_" => array("","",""), -"last year" => "прошле године", -"years ago" => "година раније", -"Could not find category \"%s\"" => "Не могу да пронађем категорију „%s“." -); -$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/sr@latin.php b/lib/l10n/sr@latin.php deleted file mode 100644 index d8fa9289221..00000000000 --- a/lib/l10n/sr@latin.php +++ /dev/null @@ -1,22 +0,0 @@ - "Pomoć", -"Personal" => "Lično", -"Settings" => "Podešavanja", -"Users" => "Korisnici", -"Admin" => "Adninistracija", -"Authentication error" => "Greška pri autentifikaciji", -"Files" => "Fajlovi", -"Text" => "Tekst", -"seconds ago" => "Pre par sekundi", -"_%n minute ago_::_%n minutes ago_" => array("","",""), -"_%n hour ago_::_%n hours ago_" => array("","",""), -"today" => "Danas", -"yesterday" => "juče", -"_%n day go_::_%n days ago_" => array("","",""), -"last month" => "prošlog meseca", -"_%n month ago_::_%n months ago_" => array("","",""), -"last year" => "prošle godine", -"years ago" => "pre nekoliko godina" -); -$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/string.php b/lib/l10n/string.php deleted file mode 100644 index 88c85b32e70..00000000000 --- a/lib/l10n/string.php +++ /dev/null @@ -1,56 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_L10N_String{ - /** - * @var OC_L10N - */ - protected $l10n; - - /** - * @var string - */ - protected $text; - - /** - * @var array - */ - protected $parameters; - - /** - * @var integer - */ - protected $count; - - public function __construct($l10n, $text, $parameters, $count = 1) { - $this->l10n = $l10n; - $this->text = $text; - $this->parameters = $parameters; - $this->count = $count; - } - - public function __toString() { - $translations = $this->l10n->getTranslations(); - - $text = $this->text; - if(array_key_exists($this->text, $translations)) { - if(is_array($translations[$this->text])) { - $fn = $this->l10n->getPluralFormFunction(); - $id = $fn($this->count); - $text = $translations[$this->text][$id]; - } - else{ - $text = $translations[$this->text]; - } - } - - // Replace %n first (won't interfere with vsprintf) - $text = str_replace('%n', $this->count, $text); - return vsprintf($text, $this->parameters); - } -} diff --git a/lib/l10n/sv.php b/lib/l10n/sv.php deleted file mode 100644 index e7c3420a85b..00000000000 --- a/lib/l10n/sv.php +++ /dev/null @@ -1,69 +0,0 @@ - "Appen \"%s\" kan inte installeras eftersom att den inte är kompatibel med denna version av ownCloud.", -"No app name specified" => "Inget appnamn angivet", -"Help" => "Hjälp", -"Personal" => "Personligt", -"Settings" => "Inställningar", -"Users" => "Användare", -"Admin" => "Admin", -"Failed to upgrade \"%s\"." => "Misslyckades med att uppgradera \"%s\".", -"web services under your control" => "webbtjänster under din kontroll", -"cannot open \"%s\"" => "Kan inte öppna \"%s\"", -"ZIP download is turned off." => "Nerladdning av ZIP är avstängd.", -"Files need to be downloaded one by one." => "Filer laddas ner en åt gången.", -"Back to Files" => "Tillbaka till Filer", -"Selected files too large to generate zip file." => "Valda filer är för stora för att skapa zip-fil.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Ladda ner filerna i mindre bitar, separat eller fråga din administratör.", -"No source specified when installing app" => "Ingen källa angiven vid installation av app ", -"No href specified when installing app from http" => "Ingen href angiven vid installation av app från http", -"No path specified when installing app from local file" => "Ingen sökväg angiven vid installation av app från lokal fil", -"Archives of type %s are not supported" => "Arkiv av typen %s stöds ej", -"Failed to open archive when installing app" => "Kunde inte öppna arkivet när appen skulle installeras", -"App does not provide an info.xml file" => "Appen har ingen info.xml fil", -"App can't be installed because of not allowed code in the App" => "Appen kan inte installeras eftersom att den innehåller otillåten kod", -"App can't be installed because it is not compatible with this version of ownCloud" => "Appen kan inte installeras eftersom att den inte är kompatibel med denna version av ownCloud", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Appen kan inte installeras eftersom att den innehåller etiketten true vilket inte är tillåtet för icke inkluderade appar", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Appen kan inte installeras eftersom versionen i info.xml inte är samma som rapporteras från app store", -"App directory already exists" => "Appens mapp finns redan", -"Can't create app folder. Please fix permissions. %s" => "Kan inte skapa appens mapp. Var god åtgärda rättigheterna. %s", -"Application is not enabled" => "Applikationen är inte aktiverad", -"Authentication error" => "Fel vid autentisering", -"Token expired. Please reload page." => "Ogiltig token. Ladda om sidan.", -"Files" => "Filer", -"Text" => "Text", -"Images" => "Bilder", -"%s enter the database username." => "%s ange databasanvändare.", -"%s enter the database name." => "%s ange databasnamn", -"%s you may not use dots in the database name" => "%s du får inte använda punkter i databasnamnet", -"MS SQL username and/or password not valid: %s" => "MS SQL-användaren och/eller lösenordet var inte giltigt: %s", -"You need to enter either an existing account or the administrator." => "Du måste antingen ange ett befintligt konto eller administratör.", -"MySQL username and/or password not valid" => "MySQL-användarnamnet och/eller lösenordet är felaktigt", -"DB Error: \"%s\"" => "DB error: \"%s\"", -"Offending command was: \"%s\"" => "Det felaktiga kommandot var: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL-användaren '%s'@'localhost' existerar redan.", -"Drop this user from MySQL" => "Radera denna användare från MySQL", -"MySQL user '%s'@'%%' already exists" => "MySQl-användare '%s'@'%%' existerar redan", -"Drop this user from MySQL." => "Radera denna användare från MySQL.", -"Oracle connection could not be established" => "Oracle-anslutning kunde inte etableras", -"Oracle username and/or password not valid" => "Oracle-användarnamnet och/eller lösenordet är felaktigt", -"Offending command was: \"%s\", name: %s, password: %s" => "Det felande kommandot var: \"%s\", name: %s, password: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt", -"Set an admin username." => "Ange ett användarnamn för administratören.", -"Set an admin password." => "Ange ett administratörslösenord.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din webbserver är inte korrekt konfigurerad för att tillåta filsynkronisering eftersom WebDAV inte verkar fungera.", -"Please double check the installation guides." => "Var god kontrollera installationsguiden.", -"seconds ago" => "sekunder sedan", -"_%n minute ago_::_%n minutes ago_" => array("%n minut sedan","%n minuter sedan"), -"_%n hour ago_::_%n hours ago_" => array("%n timme sedan","%n timmar sedan"), -"today" => "i dag", -"yesterday" => "i går", -"_%n day go_::_%n days ago_" => array("%n dag sedan","%n dagar sedan"), -"last month" => "förra månaden", -"_%n month ago_::_%n months ago_" => array("%n månad sedan","%n månader sedan"), -"last year" => "förra året", -"years ago" => "år sedan", -"Caused by:" => "Orsakad av:", -"Could not find category \"%s\"" => "Kunde inte hitta kategorin \"%s\"" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/sw_KE.php b/lib/l10n/sw_KE.php deleted file mode 100644 index 15f78e0bce6..00000000000 --- a/lib/l10n/sw_KE.php +++ /dev/null @@ -1,8 +0,0 @@ - array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/ta_LK.php b/lib/l10n/ta_LK.php deleted file mode 100644 index e70e65845be..00000000000 --- a/lib/l10n/ta_LK.php +++ /dev/null @@ -1,31 +0,0 @@ - "உதவி", -"Personal" => "தனிப்பட்ட", -"Settings" => "அமைப்புகள்", -"Users" => "பயனாளர்", -"Admin" => "நிர்வாகம்", -"web services under your control" => "வலைய சேவைகள் உங்களுடைய கட்டுப்பாட்டின் கீழ் உள்ளது", -"ZIP download is turned off." => "வீசொலிப் பூட்டு பதிவிறக்கம் நிறுத்தப்பட்டுள்ளது.", -"Files need to be downloaded one by one." => "கோப்புகள்ஒன்றன் பின் ஒன்றாக பதிவிறக்கப்படவேண்டும்.", -"Back to Files" => "கோப்புகளுக்கு செல்க", -"Selected files too large to generate zip file." => "வீ சொலிக் கோப்புகளை உருவாக்குவதற்கு தெரிவுசெய்யப்பட்ட கோப்புகள் மிகப்பெரியவை", -"Application is not enabled" => "செயலி இயலுமைப்படுத்தப்படவில்லை", -"Authentication error" => "அத்தாட்சிப்படுத்தலில் வழு", -"Token expired. Please reload page." => "அடையாளவில்லை காலாவதியாகிவிட்டது. தயவுசெய்து பக்கத்தை மீள் ஏற்றுக.", -"Files" => "கோப்புகள்", -"Text" => "உரை", -"Images" => "படங்கள்", -"seconds ago" => "செக்கன்களுக்கு முன்", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "இன்று", -"yesterday" => "நேற்று", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "கடந்த மாதம்", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "கடந்த வருடம்", -"years ago" => "வருடங்களுக்கு முன்", -"Could not find category \"%s\"" => "பிரிவு \"%s\" ஐ கண்டுப்பிடிக்க முடியவில்லை" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/te.php b/lib/l10n/te.php deleted file mode 100644 index 524ea0c6024..00000000000 --- a/lib/l10n/te.php +++ /dev/null @@ -1,17 +0,0 @@ - "సహాయం", -"Settings" => "అమరికలు", -"Users" => "వాడుకరులు", -"seconds ago" => "క్షణాల క్రితం", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"today" => "ఈరోజు", -"yesterday" => "నిన్న", -"_%n day go_::_%n days ago_" => array("",""), -"last month" => "పోయిన నెల", -"_%n month ago_::_%n months ago_" => array("",""), -"last year" => "పోయిన సంవత్సరం", -"years ago" => "సంవత్సరాల క్రితం" -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/th_TH.php b/lib/l10n/th_TH.php deleted file mode 100644 index 3344d0bb18e..00000000000 --- a/lib/l10n/th_TH.php +++ /dev/null @@ -1,31 +0,0 @@ - "ช่วยเหลือ", -"Personal" => "ส่วนตัว", -"Settings" => "ตั้งค่า", -"Users" => "ผู้ใช้งาน", -"Admin" => "ผู้ดูแล", -"web services under your control" => "เว็บเซอร์วิสที่คุณควบคุมการใช้งานได้", -"ZIP download is turned off." => "คุณสมบัติการดาวน์โหลด zip ถูกปิดการใช้งานไว้", -"Files need to be downloaded one by one." => "ไฟล์สามารถดาวน์โหลดได้ทีละครั้งเท่านั้น", -"Back to Files" => "กลับไปที่ไฟล์", -"Selected files too large to generate zip file." => "ไฟล์ที่เลือกมีขนาดใหญ่เกินกว่าที่จะสร้างเป็นไฟล์ zip", -"Application is not enabled" => "แอพพลิเคชั่นดังกล่าวยังไม่ได้เปิดใช้งาน", -"Authentication error" => "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน", -"Token expired. Please reload page." => "รหัสยืนยันความถูกต้องหมดอายุแล้ว กรุณาโหลดหน้าเว็บใหม่อีกครั้ง", -"Files" => "ไฟล์", -"Text" => "ข้อความ", -"Images" => "รูปภาพ", -"seconds ago" => "วินาที ก่อนหน้านี้", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "วันนี้", -"yesterday" => "เมื่อวานนี้", -"_%n day go_::_%n days ago_" => array(""), -"last month" => "เดือนที่แล้ว", -"_%n month ago_::_%n months ago_" => array(""), -"last year" => "ปีที่แล้ว", -"years ago" => "ปี ที่ผ่านมา", -"Could not find category \"%s\"" => "ไม่พบหมวดหมู่ \"%s\"" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/tr.php b/lib/l10n/tr.php deleted file mode 100644 index b63c37c7240..00000000000 --- a/lib/l10n/tr.php +++ /dev/null @@ -1,69 +0,0 @@ - "Owncloud yazılımının bu sürümü ile uyumlu olmadığı için \"%s\" uygulaması kurulamaz.", -"No app name specified" => "Uygulama adı belirtimedli", -"Help" => "Yardım", -"Personal" => "Kişisel", -"Settings" => "Ayarlar", -"Users" => "Kullanıcılar", -"Admin" => "Yönetici", -"Failed to upgrade \"%s\"." => "\"%s\" yükseltme başarısız oldu.", -"web services under your control" => "Bilgileriniz güvenli ve şifreli", -"cannot open \"%s\"" => "\"%s\" açılamıyor", -"ZIP download is turned off." => "ZIP indirmeleri kapatılmıştır.", -"Files need to be downloaded one by one." => "Dosyaların birer birer indirilmesi gerekmektedir.", -"Back to Files" => "Dosyalara dön", -"Selected files too large to generate zip file." => "Seçilen dosyalar bir zip dosyası oluşturmak için fazla büyüktür.", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Dosyaları ayrı ayrı, küçük parçalar halinde indirin ya da yöneticinizden yardım isteyin. ", -"No source specified when installing app" => "Uygulama kurulurken bir kaynak belirtilmedi", -"No href specified when installing app from http" => "Uygulama kuruluyorken http'de href belirtilmedi.", -"No path specified when installing app from local file" => "Uygulama yerel dosyadan kuruluyorken dosya yolu belirtilmedi", -"Archives of type %s are not supported" => "%s arşiv tipi desteklenmiyor", -"Failed to open archive when installing app" => "Uygulama kuruluyorken arşiv dosyası açılamadı", -"App does not provide an info.xml file" => "Uygulama info.xml dosyası sağlamıyor", -"App can't be installed because of not allowed code in the App" => "Uygulamada izin verilmeyeden kodlar olduğu için kurulamıyor.", -"App can't be installed because it is not compatible with this version of ownCloud" => "Owncloud versiyonunuz ile uyumsuz olduğu için uygulama kurulamıyor.", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Uygulama kurulamıyor. Çünkü \"non shipped\" uygulamalar için true tag içermektedir.", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Uygulama kurulamıyor çünkü info.xml/version ile uygulama marketde belirtilen sürüm aynı değil.", -"App directory already exists" => "App dizini zaten mevcut", -"Can't create app folder. Please fix permissions. %s" => "app dizini oluşturulamıyor. Lütfen izinleri düzeltin. %s", -"Application is not enabled" => "Uygulama etkinleştirilmedi", -"Authentication error" => "Kimlik doğrulama hatası", -"Token expired. Please reload page." => "Jetonun süresi geçti. Lütfen sayfayı yenileyin.", -"Files" => "Dosyalar", -"Text" => "Metin", -"Images" => "Resimler", -"%s enter the database username." => "%s veritabanı kullanıcı adını gir.", -"%s enter the database name." => "%s veritabanı adını gir.", -"%s you may not use dots in the database name" => "%s veritabanı adında nokta kullanamayabilirsiniz", -"MS SQL username and/or password not valid: %s" => "MS SQL kullanıcı adı ve/veya parolası geçersiz: %s", -"You need to enter either an existing account or the administrator." => "Bir konto veya kullanici birlemek ihtiyacin. ", -"MySQL username and/or password not valid" => "MySQL kullanıcı adı ve/veya parolası geçerli değil", -"DB Error: \"%s\"" => "DB Hata: ''%s''", -"Offending command was: \"%s\"" => "Komut rahasiz ''%s''. ", -"MySQL user '%s'@'localhost' exists already." => "MySQL kullanici '%s @local host zatan var. ", -"Drop this user from MySQL" => "Bu kullanici MySQLden list disari koymak. ", -"MySQL user '%s'@'%%' already exists" => "MySQL kullanici '%s @ % % zaten var (zaten yazili)", -"Drop this user from MySQL." => "Bu kulanıcıyı MySQL veritabanından kaldır", -"Oracle connection could not be established" => "Oracle bağlantısı kurulamadı", -"Oracle username and/or password not valid" => "Adi klullanici ve/veya parola Oracle mantikli değildir. ", -"Offending command was: \"%s\", name: %s, password: %s" => "Hatalı komut: \"%s\", ad: %s, parola: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL adi kullanici ve/veya parola yasal degildir. ", -"Set an admin username." => "Bir adi kullanici vermek. ", -"Set an admin password." => "Parola yonetici birlemek. ", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Web sunucunuz dosya transferi için düzgün bir şekilde yapılandırılmamış. WevDAV arabirimini sorunlu gözüküyor.", -"Please double check the installation guides." => "Lütfen kurulum kılavuzlarını iki kez kontrol edin.", -"seconds ago" => "saniye önce", -"_%n minute ago_::_%n minutes ago_" => array("","%n dakika önce"), -"_%n hour ago_::_%n hours ago_" => array("","%n saat önce"), -"today" => "bugün", -"yesterday" => "dün", -"_%n day go_::_%n days ago_" => array("","%n gün önce"), -"last month" => "geçen ay", -"_%n month ago_::_%n months ago_" => array("","%n ay önce"), -"last year" => "geçen yıl", -"years ago" => "yıl önce", -"Caused by:" => "Neden olan:", -"Could not find category \"%s\"" => "\"%s\" kategorisi bulunamadı" -); -$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/l10n/ug.php b/lib/l10n/ug.php deleted file mode 100644 index e2cf38ecc8c..00000000000 --- a/lib/l10n/ug.php +++ /dev/null @@ -1,19 +0,0 @@ - "ياردەم", -"Personal" => "شەخسىي", -"Settings" => "تەڭشەكلەر", -"Users" => "ئىشلەتكۈچىلەر", -"Authentication error" => "سالاھىيەت دەلىللەش خاتالىقى", -"Files" => "ھۆججەتلەر", -"Text" => "قىسقا ئۇچۇر", -"Images" => "سۈرەتلەر", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "سىزنىڭ تور مۇلازىمېتىرىڭىز ھۆججەت قەدەمداشلاشقا يول قويىدىغان قىلىپ توغرا تەڭشەلمەپتۇ، چۈنكى WebDAV نىڭ ئېغىزى بۇزۇلغاندەك تۇرىدۇ.", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "بۈگۈن", -"yesterday" => "تۈنۈگۈن", -"_%n day go_::_%n days ago_" => array(""), -"_%n month ago_::_%n months ago_" => array("") -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/uk.php b/lib/l10n/uk.php deleted file mode 100644 index c1513c5bb79..00000000000 --- a/lib/l10n/uk.php +++ /dev/null @@ -1,50 +0,0 @@ - "Допомога", -"Personal" => "Особисте", -"Settings" => "Налаштування", -"Users" => "Користувачі", -"Admin" => "Адмін", -"web services under your control" => "підконтрольні Вам веб-сервіси", -"ZIP download is turned off." => "ZIP завантаження вимкнено.", -"Files need to be downloaded one by one." => "Файли повинні бути завантаженні послідовно.", -"Back to Files" => "Повернутися до файлів", -"Selected files too large to generate zip file." => "Вибрані фали завеликі для генерування zip файлу.", -"Application is not enabled" => "Додаток не увімкнений", -"Authentication error" => "Помилка автентифікації", -"Token expired. Please reload page." => "Строк дії токена скінчився. Будь ласка, перезавантажте сторінку.", -"Files" => "Файли", -"Text" => "Текст", -"Images" => "Зображення", -"%s enter the database username." => "%s введіть ім'я користувача бази даних.", -"%s enter the database name." => "%s введіть назву бази даних.", -"%s you may not use dots in the database name" => "%s не можна використовувати крапки в назві бази даних", -"MS SQL username and/or password not valid: %s" => "MS SQL ім'я користувача та/або пароль не дійсні: %s", -"You need to enter either an existing account or the administrator." => "Вам потрібно ввести або існуючий обліковий запис або administrator.", -"MySQL username and/or password not valid" => "MySQL ім'я користувача та/або пароль не дійсні", -"DB Error: \"%s\"" => "Помилка БД: \"%s\"", -"Offending command was: \"%s\"" => "Команда, що викликала проблему: \"%s\"", -"MySQL user '%s'@'localhost' exists already." => "Користувач MySQL '%s'@'localhost' вже існує.", -"Drop this user from MySQL" => "Видалити цього користувача з MySQL", -"MySQL user '%s'@'%%' already exists" => "Користувач MySQL '%s'@'%%' вже існує", -"Drop this user from MySQL." => "Видалити цього користувача з MySQL.", -"Oracle username and/or password not valid" => "Oracle ім'я користувача та/або пароль не дійсні", -"Offending command was: \"%s\", name: %s, password: %s" => "Команда, що викликала проблему: \"%s\", ім'я: %s, пароль: %s", -"PostgreSQL username and/or password not valid" => "PostgreSQL ім'я користувача та/або пароль не дійсні", -"Set an admin username." => "Встановіть ім'я адміністратора.", -"Set an admin password." => "Встановіть пароль адміністратора.", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш Web-сервер ще не налаштований належним чином для того, щоб дозволити синхронізацію файлів, через те що інтерфейс WebDAV, здається, зламаний.", -"Please double check the installation guides." => "Будь ласка, перевірте інструкції по встановленню.", -"seconds ago" => "секунди тому", -"_%n minute ago_::_%n minutes ago_" => array("","",""), -"_%n hour ago_::_%n hours ago_" => array("","",""), -"today" => "сьогодні", -"yesterday" => "вчора", -"_%n day go_::_%n days ago_" => array("","",""), -"last month" => "минулого місяця", -"_%n month ago_::_%n months ago_" => array("","",""), -"last year" => "минулого року", -"years ago" => "роки тому", -"Could not find category \"%s\"" => "Не вдалося знайти категорію \"%s\"" -); -$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/l10n/ur_PK.php b/lib/l10n/ur_PK.php deleted file mode 100644 index 7dc967ccd93..00000000000 --- a/lib/l10n/ur_PK.php +++ /dev/null @@ -1,14 +0,0 @@ - "مدد", -"Personal" => "ذاتی", -"Settings" => "سیٹینگز", -"Users" => "یوزرز", -"Admin" => "ایڈمن", -"web services under your control" => "آپ کے اختیار میں ویب سروسیز", -"_%n minute ago_::_%n minutes ago_" => array("",""), -"_%n hour ago_::_%n hours ago_" => array("",""), -"_%n day go_::_%n days ago_" => array("",""), -"_%n month ago_::_%n months ago_" => array("","") -); -$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/l10n/vi.php b/lib/l10n/vi.php deleted file mode 100644 index dc0045c35ca..00000000000 --- a/lib/l10n/vi.php +++ /dev/null @@ -1,31 +0,0 @@ - "Giúp đỡ", -"Personal" => "Cá nhân", -"Settings" => "Cài đặt", -"Users" => "Người dùng", -"Admin" => "Quản trị", -"web services under your control" => "dịch vụ web dưới sự kiểm soát của bạn", -"ZIP download is turned off." => "Tải về ZIP đã bị tắt.", -"Files need to be downloaded one by one." => "Tập tin cần phải được tải về từng người một.", -"Back to Files" => "Trở lại tập tin", -"Selected files too large to generate zip file." => "Tập tin được chọn quá lớn để tạo tập tin ZIP.", -"Application is not enabled" => "Ứng dụng không được BẬT", -"Authentication error" => "Lỗi xác thực", -"Token expired. Please reload page." => "Mã Token đã hết hạn. Hãy tải lại trang.", -"Files" => "Tập tin", -"Text" => "Văn bản", -"Images" => "Hình ảnh", -"seconds ago" => "vài giây trước", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "hôm nay", -"yesterday" => "hôm qua", -"_%n day go_::_%n days ago_" => array(""), -"last month" => "tháng trước", -"_%n month ago_::_%n months ago_" => array(""), -"last year" => "năm trước", -"years ago" => "năm trước", -"Could not find category \"%s\"" => "không thể tìm thấy mục \"%s\"" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/zh_CN.php b/lib/l10n/zh_CN.php deleted file mode 100644 index 2c34356ea10..00000000000 --- a/lib/l10n/zh_CN.php +++ /dev/null @@ -1,52 +0,0 @@ - "帮助", -"Personal" => "个人", -"Settings" => "设置", -"Users" => "用户", -"Admin" => "管理", -"web services under your control" => "您控制的web服务", -"ZIP download is turned off." => "ZIP 下载已经关闭", -"Files need to be downloaded one by one." => "需要逐一下载文件", -"Back to Files" => "回到文件", -"Selected files too large to generate zip file." => "选择的文件太大,无法生成 zip 文件。", -"App does not provide an info.xml file" => "应用未提供 info.xml 文件", -"Application is not enabled" => "应用程序未启用", -"Authentication error" => "认证出错", -"Token expired. Please reload page." => "Token 过期,请刷新页面。", -"Files" => "文件", -"Text" => "文本", -"Images" => "图片", -"%s enter the database username." => "%s 输入数据库用户名。", -"%s enter the database name." => "%s 输入数据库名称。", -"%s you may not use dots in the database name" => "%s 您不能在数据库名称中使用英文句号。", -"MS SQL username and/or password not valid: %s" => "MS SQL 用户名和/或密码无效:%s", -"You need to enter either an existing account or the administrator." => "你需要输入一个数据库中已有的账户或管理员账户。", -"MySQL username and/or password not valid" => "MySQL 数据库用户名和/或密码无效", -"DB Error: \"%s\"" => "数据库错误:\"%s\"", -"Offending command was: \"%s\"" => "冲突命令为:\"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL 用户 '%s'@'localhost' 已存在。", -"Drop this user from MySQL" => "建议从 MySQL 数据库中丢弃 Drop 此用户", -"MySQL user '%s'@'%%' already exists" => "MySQL 用户 '%s'@'%%' 已存在", -"Drop this user from MySQL." => "建议从 MySQL 数据库中丢弃 Drop 此用户。", -"Oracle connection could not be established" => "不能建立甲骨文连接", -"Oracle username and/or password not valid" => "Oracle 数据库用户名和/或密码无效", -"Offending command was: \"%s\", name: %s, password: %s" => "冲突命令为:\"%s\",名称:%s,密码:%s", -"PostgreSQL username and/or password not valid" => "PostgreSQL 数据库用户名和/或密码无效", -"Set an admin username." => "请设置一个管理员用户名。", -"Set an admin password." => "请设置一个管理员密码。", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "您的Web服务器尚未正确设置以允许文件同步, 因为WebDAV的接口似乎已损坏.", -"Please double check the installation guides." => "请认真检查安装指南.", -"seconds ago" => "秒前", -"_%n minute ago_::_%n minutes ago_" => array("%n 分钟前"), -"_%n hour ago_::_%n hours ago_" => array("%n 小时前"), -"today" => "今天", -"yesterday" => "昨天", -"_%n day go_::_%n days ago_" => array("%n 天前"), -"last month" => "上月", -"_%n month ago_::_%n months ago_" => array("%n 月前"), -"last year" => "去年", -"years ago" => "年前", -"Could not find category \"%s\"" => "无法找到分类 \"%s\"" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/zh_HK.php b/lib/l10n/zh_HK.php deleted file mode 100644 index ca3e6d504e7..00000000000 --- a/lib/l10n/zh_HK.php +++ /dev/null @@ -1,18 +0,0 @@ - "幫助", -"Personal" => "個人", -"Settings" => "設定", -"Users" => "用戶", -"Admin" => "管理", -"Files" => "文件", -"Text" => "文字", -"_%n minute ago_::_%n minutes ago_" => array(""), -"_%n hour ago_::_%n hours ago_" => array(""), -"today" => "今日", -"yesterday" => "昨日", -"_%n day go_::_%n days ago_" => array(""), -"last month" => "前一月", -"_%n month ago_::_%n months ago_" => array("") -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/l10n/zh_TW.php b/lib/l10n/zh_TW.php deleted file mode 100644 index 210c766aa59..00000000000 --- a/lib/l10n/zh_TW.php +++ /dev/null @@ -1,69 +0,0 @@ - "無法安裝應用程式 %s 因為它和此版本的 ownCloud 不相容。", -"No app name specified" => "沒有指定應用程式名稱", -"Help" => "說明", -"Personal" => "個人", -"Settings" => "設定", -"Users" => "使用者", -"Admin" => "管理", -"Failed to upgrade \"%s\"." => "升級失敗:%s", -"web services under your control" => "由您控制的網路服務", -"cannot open \"%s\"" => "無法開啓 %s", -"ZIP download is turned off." => "ZIP 下載已關閉。", -"Files need to be downloaded one by one." => "檔案需要逐一下載。", -"Back to Files" => "回到檔案列表", -"Selected files too large to generate zip file." => "選擇的檔案太大以致於無法產生壓縮檔。", -"Download the files in smaller chunks, seperately or kindly ask your administrator." => "以小分割下載您的檔案,請詢問您的系統管理員。", -"No source specified when installing app" => "沒有指定應用程式安裝來源", -"No href specified when installing app from http" => "從 http 安裝應用程式,找不到 href 屬性", -"No path specified when installing app from local file" => "從本地檔案安裝應用程式時沒有指定路徑", -"Archives of type %s are not supported" => "不支援 %s 格式的壓縮檔", -"Failed to open archive when installing app" => "安裝應用程式時無法開啓壓縮檔", -"App does not provide an info.xml file" => "應用程式沒有提供 info.xml 檔案", -"App can't be installed because of not allowed code in the App" => "無法安裝應用程式因為在當中找到危險的代碼", -"App can't be installed because it is not compatible with this version of ownCloud" => "無法安裝應用程式因為它和此版本的 ownCloud 不相容。", -"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "無法安裝應用程式,因為它包含了 true 標籤,在未發行的應用程式當中這是不允許的", -"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "無法安裝應用程式,因為它在 info.xml/version 宣告的版本與 app store 當中記載的版本不同", -"App directory already exists" => "應用程式目錄已經存在", -"Can't create app folder. Please fix permissions. %s" => "無法建立應用程式目錄,請檢查權限:%s", -"Application is not enabled" => "應用程式未啟用", -"Authentication error" => "認證錯誤", -"Token expired. Please reload page." => "Token 過期,請重新整理頁面。", -"Files" => "檔案", -"Text" => "文字", -"Images" => "圖片", -"%s enter the database username." => "%s 輸入資料庫使用者名稱。", -"%s enter the database name." => "%s 輸入資料庫名稱。", -"%s you may not use dots in the database name" => "%s 資料庫名稱不能包含小數點", -"MS SQL username and/or password not valid: %s" => "MS SQL 使用者和/或密碼無效:%s", -"You need to enter either an existing account or the administrator." => "您必須輸入一個現有的帳號或管理員帳號。", -"MySQL username and/or password not valid" => "MySQL 用戶名和/或密碼無效", -"DB Error: \"%s\"" => "資料庫錯誤:\"%s\"", -"Offending command was: \"%s\"" => "有問題的指令是:\"%s\"", -"MySQL user '%s'@'localhost' exists already." => "MySQL 使用者 '%s'@'localhost' 已經存在。", -"Drop this user from MySQL" => "在 MySQL 移除這個使用者", -"MySQL user '%s'@'%%' already exists" => "MySQL 使用者 '%s'@'%%' 已經存在", -"Drop this user from MySQL." => "在 MySQL 移除這個使用者。", -"Oracle connection could not be established" => "無法建立 Oracle 資料庫連線", -"Oracle username and/or password not valid" => "Oracle 用戶名和/或密碼無效", -"Offending command was: \"%s\", name: %s, password: %s" => "有問題的指令是:\"%s\" ,使用者:\"%s\",密碼:\"%s\"", -"PostgreSQL username and/or password not valid" => "PostgreSQL 用戶名和/或密碼無效", -"Set an admin username." => "設定管理員帳號。", -"Set an admin password." => "設定管理員密碼。", -"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "您的網頁伺服器尚未被正確設定來進行檔案同步,因為您的 WebDAV 界面似乎無法使用。", -"Please double check the installation guides." => "請參考安裝指南。", -"seconds ago" => "幾秒前", -"_%n minute ago_::_%n minutes ago_" => array("%n 分鐘前"), -"_%n hour ago_::_%n hours ago_" => array("%n 小時前"), -"today" => "今天", -"yesterday" => "昨天", -"_%n day go_::_%n days ago_" => array("%n 天前"), -"last month" => "上個月", -"_%n month ago_::_%n months ago_" => array("%n 個月前"), -"last year" => "去年", -"years ago" => "幾年前", -"Caused by:" => "原因:", -"Could not find category \"%s\"" => "找不到分類:\"%s\"" -); -$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/legacy/cache.php b/lib/legacy/cache.php deleted file mode 100644 index f915eb516b1..00000000000 --- a/lib/legacy/cache.php +++ /dev/null @@ -1,10 +0,0 @@ -. - * - */ -/* - * - * An example of config.php - * - * "mysql", - * "firstrun" => false, - * "pi" => 3.14 - * ); - * ?> - * - */ - -/** - * This class is responsible for reading and writing config.php, the very basic - * configuration file of ownCloud. - */ -OC_Config::$object = new \OC\Config(OC::$SERVERROOT.'/config/'); -class OC_Config { - - /** - * @var \OC\Config - */ - public static $object; - - public static function getObject() { - return self::$object; - } - - /** - * @brief Lists all available config keys - * @return array with key names - * - * This function returns all keys saved in config.php. Please note that it - * does not return the values. - */ - public static function getKeys() { - return self::$object->getKeys(); - } - - /** - * @brief Gets a value from config.php - * @param string $key key - * @param string $default = null default value - * @return string the value or $default - * - * This function gets the value from config.php. If it does not exist, - * $default will be returned. - */ - public static function getValue($key, $default = null) { - return self::$object->getValue($key, $default); - } - - /** - * @brief Sets a value - * @param string $key key - * @param string $value value - * - * This function sets the value and writes the config.php. - * - */ - public static function setValue($key, $value) { - try { - self::$object->setValue($key, $value); - } catch (\OC\HintException $e) { - \OC_Template::printErrorPage($e->getMessage(), $e->getHint()); - } - } - - /** - * @brief Removes a key from the config - * @param string $key key - * - * This function removes a key from the config.php. - * - */ - public static function deleteKey($key) { - try { - self::$object->deleteKey($key); - } catch (\OC\HintException $e) { - \OC_Template::printErrorPage($e->getMessage(), $e->getHint()); - } - } -} diff --git a/lib/legacy/filesystem.php b/lib/legacy/filesystem.php deleted file mode 100644 index 34f92b357ca..00000000000 --- a/lib/legacy/filesystem.php +++ /dev/null @@ -1,415 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * Class for abstraction of filesystem functions - * This class won't call any filesystem functions for itself but but will pass them to the correct OC_Filestorage object - * this class should also handle all the file permission related stuff - * - * Hooks provided: - * read(path) - * write(path, &run) - * post_write(path) - * create(path, &run) (when a file is created, both create and write will be emitted in that order) - * post_create(path) - * delete(path, &run) - * post_delete(path) - * rename(oldpath,newpath, &run) - * post_rename(oldpath,newpath) - * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order) - * post_rename(oldpath,newpath) - * - * the &run parameter can be set to false to prevent the operation from occurring - */ - -/** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ -class OC_Filesystem { - /** - * get the mountpoint of the storage object for a path - * ( note: because a storage is not always mounted inside the fakeroot, the - * returned mountpoint is relative to the absolute root of the filesystem - * and doesn't take the chroot into account ) - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @return string - */ - static public function getMountPoint($path) { - return \OC\Files\Filesystem::getMountPoint($path); - } - - /** - * resolve a path to a storage and internal path - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @return array consisting of the storage and the internal path - */ - static public function resolvePath($path) { - return \OC\Files\Filesystem::resolvePath($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function init($user, $root) { - return \OC\Files\Filesystem::init($user, $root); - } - - /** - * get the default filesystem view - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @return \OC\Files\View - */ - static public function getView() { - return \OC\Files\Filesystem::getView(); - } - - /** - * tear down the filesystem, removing all storage providers - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function tearDown() { - \OC\Files\Filesystem::tearDown(); - } - - /** - * @brief get the relative path of the root data directory for the current user - * @return string - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * Returns path like /admin/files - */ - static public function getRoot() { - return \OC\Files\Filesystem::getRoot(); - } - - /** - * clear all mounts and storage backends - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - public static function clearMounts() { - \OC\Files\Filesystem::clearMounts(); - } - - /** - * mount an \OC\Files\Storage\Storage in our virtual filesystem - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param \OC\Files\Storage\Storage $class - * @param array $arguments - * @param string $mountpoint - */ - static public function mount($class, $arguments, $mountpoint) { - \OC\Files\Filesystem::mount($class, $arguments, $mountpoint); - } - - /** - * return the path to a local version of the file - * we need this because we can't know if a file is stored local or not from - * outside the filestorage and for some purposes a local file is needed - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @return string - */ - static public function getLocalFile($path) { - return \OC\Files\Filesystem::getLocalFile($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @return string - */ - static public function getLocalFolder($path) { - return \OC\Files\Filesystem::getLocalFolder($path); - } - - /** - * return path to file which reflects one visible in browser - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @return string - */ - static public function getLocalPath($path) { - return \OC\Files\Filesystem::getLocalPath($path); - } - - /** - * check if the requested path is valid - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @return bool - */ - static public function isValidPath($path) { - return \OC\Files\Filesystem::isValidPath($path); - } - - /** - * checks if a file is blacklisted for storage in the filesystem - * Listens to write and rename hooks - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param array $data from hook - */ - static public function isBlacklisted($data) { - \OC\Files\Filesystem::isBlacklisted($data); - } - - /** - * following functions are equivalent to their php builtin equivalents for arguments/return values. - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function mkdir($path) { - return \OC\Files\Filesystem::mkdir($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function rmdir($path) { - return \OC\Files\Filesystem::rmdir($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function opendir($path) { - return \OC\Files\Filesystem::opendir($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function readdir($path) { - return \OC\Files\Filesystem::readdir($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function is_dir($path) { - return \OC\Files\Filesystem::is_dir($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function is_file($path) { - return \OC\Files\Filesystem::is_file($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function stat($path) { - return \OC\Files\Filesystem::stat($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function filetype($path) { - return \OC\Files\Filesystem::filetype($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function filesize($path) { - return \OC\Files\Filesystem::filesize($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function readfile($path) { - return \OC\Files\Filesystem::readfile($path); - } - - /** - * @deprecated Replaced by isReadable() as part of CRUDS - */ - static public function is_readable($path) { - return \OC\Files\Filesystem::isReadable($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function isCreatable($path) { - return \OC\Files\Filesystem::isCreatable($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function isReadable($path) { - return \OC\Files\Filesystem::isReadable($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function isUpdatable($path) { - return \OC\Files\Filesystem::isUpdatable($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function isDeletable($path) { - return \OC\Files\Filesystem::isDeletable($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function isSharable($path) { - return \OC\Files\Filesystem::isSharable($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function file_exists($path) { - return \OC\Files\Filesystem::file_exists($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function filemtime($path) { - return \OC\Files\Filesystem::filemtime($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function touch($path, $mtime = null) { - return \OC\Files\Filesystem::touch($path, $mtime); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function file_get_contents($path) { - return \OC\Files\Filesystem::file_get_contents($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function file_put_contents($path, $data) { - return \OC\Files\Filesystem::file_put_contents($path, $data); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function unlink($path) { - return \OC\Files\Filesystem::unlink($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function rename($path1, $path2) { - return \OC\Files\Filesystem::rename($path1, $path2); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function copy($path1, $path2) { - return \OC\Files\Filesystem::copy($path1, $path2); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function fopen($path, $mode) { - return \OC\Files\Filesystem::fopen($path, $mode); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function toTmpFile($path) { - return \OC\Files\Filesystem::toTmpFile($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function fromTmpFile($tmpFile, $path) { - return \OC\Files\Filesystem::fromTmpFile($tmpFile, $path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function getMimeType($path) { - return \OC\Files\Filesystem::getMimeType($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function hash($type, $path, $raw = false) { - return \OC\Files\Filesystem::hash($type, $path, $raw); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function free_space($path = '/') { - return \OC\Files\Filesystem::free_space($path); - } - - /** - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - */ - static public function search($query) { - return \OC\Files\Filesystem::search($query); - } - - /** - * check if a file or folder has been updated since $time - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @param int $time - * @return bool - */ - static public function hasUpdated($path, $time) { - return \OC\Files\Filesystem::hasUpdated($path, $time); - } - - /** - * normalize a path - * - * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem - * @param string $path - * @param bool $stripTrailingSlash - * @return string - */ - public static function normalizePath($path, $stripTrailingSlash = true) { - return \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash); - } -} diff --git a/lib/legacy/filesystemview.php b/lib/legacy/filesystemview.php deleted file mode 100644 index d6bca62e06a..00000000000 --- a/lib/legacy/filesystemview.php +++ /dev/null @@ -1,9 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. */ - -class OC_FilesystemView extends \OC\Files\View {} diff --git a/lib/legacy/log.php b/lib/legacy/log.php deleted file mode 100644 index 027cb89e97c..00000000000 --- a/lib/legacy/log.php +++ /dev/null @@ -1,50 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * logging utilities - * - * Log is saved by default at data/owncloud.log using OC_Log_Owncloud. - * Selecting other backend is done with a config option 'log_type'. - */ - -OC_Log::$object = new \OC\Log(); -class OC_Log { - public static $object; - - const DEBUG=0; - const INFO=1; - const WARN=2; - const ERROR=3; - const FATAL=4; - - static private $level_funcs = array( - self::DEBUG => 'debug', - self::INFO => 'info', - self::WARN => 'warning', - self::ERROR => 'error', - self::FATAL => 'emergency', - ); - - static public $enabled = true; - static protected $class = null; - - /** - * write a message in the log - * @param string $app - * @param string $message - * @param int $level - */ - public static function write($app, $message, $level) { - if (self::$enabled) { - $context = array('app' => $app); - $func = array(self::$object, self::$level_funcs[$level]); - call_user_func($func, $message, $context); - } - } -} diff --git a/lib/legacy/preferences.php b/lib/legacy/preferences.php deleted file mode 100644 index a663db7598b..00000000000 --- a/lib/legacy/preferences.php +++ /dev/null @@ -1,146 +0,0 @@ -. - * - */ - -/** - * This class provides an easy way for storing user preferences. - */ -OC_Preferences::$object = new \OC\Preferences(OC_DB::getConnection()); -class OC_Preferences{ - public static $object; - /** - * @brief Get all users using the preferences - * @return array with user ids - * - * This function returns a list of all users that have at least one entry - * in the preferences table. - */ - public static function getUsers() { - return self::$object->getUsers(); - } - - /** - * @brief Get all apps of a user - * @param string $user user - * @return array with app ids - * - * This function returns a list of all apps of the user that have at least - * one entry in the preferences table. - */ - public static function getApps( $user ) { - return self::$object->getApps( $user ); - } - - /** - * @brief Get the available keys for an app - * @param string $user user - * @param string $app the app we are looking for - * @return array with key names - * - * This function gets all keys of an app of an user. Please note that the - * values are not returned. - */ - public static function getKeys( $user, $app ) { - return self::$object->getKeys( $user, $app ); - } - - /** - * @brief Gets the preference - * @param string $user user - * @param string $app app - * @param string $key key - * @param string $default = null, default value if the key does not exist - * @return string the value or $default - * - * This function gets a value from the preferences table. If the key does - * not exist the default value will be returned - */ - public static function getValue( $user, $app, $key, $default = null ) { - return self::$object->getValue( $user, $app, $key, $default ); - } - - /** - * @brief sets a value in the preferences - * @param string $user user - * @param string $app app - * @param string $key key - * @param string $value value - * @return bool - * - * Adds a value to the preferences. If the key did not exist before, it - * will be added automagically. - */ - public static function setValue( $user, $app, $key, $value ) { - self::$object->setValue( $user, $app, $key, $value ); - return true; - } - - /** - * @brief Deletes a key - * @param string $user user - * @param string $app app - * @param string $key key - * - * Deletes a key. - */ - public static function deleteKey( $user, $app, $key ) { - self::$object->deleteKey( $user, $app, $key ); - return true; - } - - /** - * @brief Remove app of user from preferences - * @param string $user user - * @param string $app app - * @return bool - * - * Removes all keys in preferences belonging to the app and the user. - */ - public static function deleteApp( $user, $app ) { - self::$object->deleteApp( $user, $app ); - return true; - } - - /** - * @brief Remove user from preferences - * @param string $user user - * @return bool - * - * Removes all keys in preferences belonging to the user. - */ - public static function deleteUser( $user ) { - self::$object->deleteUser( $user ); - return true; - } - - /** - * @brief Remove app from all users - * @param string $app app - * @return bool - * - * Removes all keys in preferences belonging to the app. - */ - public static function deleteAppFromAllUsers( $app ) { - self::$object->deleteAppFromAllUsers( $app ); - return true; - } -} diff --git a/lib/legacy/updater.php b/lib/legacy/updater.php deleted file mode 100644 index eea7bb129cf..00000000000 --- a/lib/legacy/updater.php +++ /dev/null @@ -1,14 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_Updater { - public static function check() { - $updater = new \OC\Updater(); - return $updater->check('http://apps.owncloud.com/updater.php'); - } -} diff --git a/lib/log.php b/lib/log.php deleted file mode 100644 index e0b9fe3c696..00000000000 --- a/lib/log.php +++ /dev/null @@ -1,136 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC; - -/** - * logging utilities - * - * This is a stand in, this should be replaced by a Psr\Log\LoggerInterface - * compatible logger. See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md - * for the full interface specification. - * - * MonoLog is an example implementing this interface. - */ - -class Log { - private $logClass; - - /** - * System is unusable. - * - * @param string $message - * @param array $context - */ - public function emergency($message, array $context = array()) { - $this->log(\OC_Log::FATAL, $message, $context); - } - - /** - * Action must be taken immediately. - * - * Example: Entire website down, database unavailable, etc. This should - * trigger the SMS alerts and wake you up. - * - * @param string $message - * @param array $context - */ - public function alert($message, array $context = array()) { - $this->log(\OC_Log::ERROR, $message, $context); - } - - /** - * Critical conditions. - * - * Example: Application component unavailable, unexpected exception. - * - * @param string $message - * @param array $context - */ - public function critical($message, array $context = array()) { - $this->log(\OC_Log::ERROR, $message, $context); - } - - /** - * Runtime errors that do not require immediate action but should typically - * be logged and monitored. - * - * @param string $message - * @param array $context - */ - public function error($message, array $context = array()) { - $this->log(\OC_Log::ERROR, $message, $context); - } - - /** - * Exceptional occurrences that are not errors. - * - * Example: Use of deprecated APIs, poor use of an API, undesirable things - * that are not necessarily wrong. - * - * @param string $message - * @param array $context - */ - public function warning($message, array $context = array()) { - $this->log(\OC_Log::WARN, $message, $context); - } - - /** - * Normal but significant events. - * - * @param string $message - * @param array $context - */ - public function notice($message, array $context = array()) { - $this->log(\OC_Log::INFO, $message, $context); - } - - /** - * Interesting events. - * - * Example: User logs in, SQL logs. - * - * @param string $message - * @param array $context - */ - public function info($message, array $context = array()) { - $this->log(\OC_Log::INFO, $message, $context); - } - - /** - * Detailed debug information. - * - * @param string $message - * @param array $context - */ - public function debug($message, array $context = array()) { - $this->log(\OC_Log::DEBUG, $message, $context); - } - - public function __construct() { - $this->logClass = 'OC_Log_'.ucfirst(\OC_Config::getValue('log_type', 'owncloud')); - call_user_func(array($this->logClass, 'init')); - } - - /** - * Logs with an arbitrary level. - * - * @param mixed $level - * @param string $message - * @param array $context - */ - public function log($level, $message, array $context = array()) { - if (isset($context['app'])) { - $app = $context['app']; - } else { - $app = 'no app in context'; - } - $logClass=$this->logClass; - $logClass::write($app, $message, $level); - } -} diff --git a/lib/log/errorhandler.php b/lib/log/errorhandler.php deleted file mode 100644 index 69cb960de91..00000000000 --- a/lib/log/errorhandler.php +++ /dev/null @@ -1,54 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Log; - -use OC\Log as LoggerInterface; - -class ErrorHandler { - /** @var LoggerInterface */ - private static $logger; - - public static function register() { - $handler = new ErrorHandler(); - - set_error_handler(array($handler, 'onError')); - register_shutdown_function(array($handler, 'onShutdown')); - set_exception_handler(array($handler, 'onException')); - } - - public static function setLogger(LoggerInterface $logger) { - self::$logger = $logger; - } - - //Fatal errors handler - public static function onShutdown() { - $error = error_get_last(); - if($error && self::$logger) { - //ob_end_clean(); - $msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line']; - self::$logger->critical($msg, array('app' => 'PHP')); - } - } - - // Uncaught exception handler - public static function onException($exception) { - $msg = $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine(); - self::$logger->critical($msg, array('app' => 'PHP')); - } - - //Recoverable errors handler - public static function onError($number, $message, $file, $line) { - if (error_reporting() === 0) { - return; - } - $msg = $message . ' at ' . $file . '#' . $line; - self::$logger->warning($msg, array('app' => 'PHP')); - - } -} diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php deleted file mode 100644 index d16b9537a16..00000000000 --- a/lib/log/owncloud.php +++ /dev/null @@ -1,112 +0,0 @@ -. - * - */ - -/** - * logging utilities - * - * Log is saved at data/owncloud.log (on default) - */ - -class OC_Log_Owncloud { - static protected $logFile; - - /** - * Init class data - */ - public static function init() { - $defaultLogFile = OC_Config::getValue("datadirectory", OC::$SERVERROOT.'/data').'/owncloud.log'; - self::$logFile = OC_Config::getValue("logfile", $defaultLogFile); - if (!file_exists(self::$logFile)) { - self::$logFile = $defaultLogFile; - } - } - - /** - * write a message in the log - * @param string $app - * @param string $message - * @param int $level - */ - public static function write($app, $message, $level) { - $minLevel=min(OC_Config::getValue( "loglevel", OC_Log::WARN ), OC_Log::ERROR); - if($level>=$minLevel) { - // default to ISO8601 - $format = OC_Config::getValue('logdateformat', 'c'); - $time = date($format, time()); - $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=> $time); - $handle = @fopen(self::$logFile, 'a'); - if ($handle) { - fwrite($handle, json_encode($entry)."\n"); - fclose($handle); - } - } - } - - /** - * get entries from the log in reverse chronological order - * @param int $limit - * @param int $offset - * @return array - */ - public static function getEntries($limit=50, $offset=0) { - self::init(); - $minLevel=OC_Config::getValue( "loglevel", OC_Log::WARN ); - $entries = array(); - $handle = @fopen(self::$logFile, 'rb'); - if ($handle) { - fseek($handle, 0, SEEK_END); - $pos = ftell($handle); - $line = ''; - $entriesCount = 0; - $lines = 0; - // Loop through each character of the file looking for new lines - while ($pos >= 0 && $entriesCount < $limit) { - fseek($handle, $pos); - $ch = fgetc($handle); - if ($ch == "\n" || $pos == 0) { - if ($line != '') { - // Add the first character if at the start of the file, - // because it doesn't hit the else in the loop - if ($pos == 0) { - $line = $ch.$line; - } - $entry = json_decode($line); - // Add the line as an entry if it is passed the offset and is equal or above the log level - if ($entry->level >= $minLevel) { - $lines++; - if ($lines > $offset) { - $entries[] = $entry; - $entriesCount++; - } - } - $line = ''; - } - } else { - $line = $ch.$line; - } - $pos--; - } - fclose($handle); - } - return $entries; - } -} diff --git a/lib/log/rotate.php b/lib/log/rotate.php deleted file mode 100644 index bf23ad588b3..00000000000 --- a/lib/log/rotate.php +++ /dev/null @@ -1,35 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Log; - -/** - * This rotates the current logfile to a new name, this way the total log usage - * will stay limited and older entries are available for a while longer. - * For more professional log management set the 'logfile' config to a different - * location and manage that with your own tools. - */ -class Rotate extends \OC\BackgroundJob\Job { - private $max_log_size; - public function run($logFile) { - $this->max_log_size = \OC_Config::getValue('log_rotate_size', false); - if ($this->max_log_size) { - $filesize = @filesize($logFile); - if ($filesize >= $this->max_log_size) { - $this->rotate($logFile); - } - } - } - - protected function rotate($logfile) { - $rotatedLogfile = $logfile.'.1'; - rename($logfile, $rotatedLogfile); - $msg = 'Log file "'.$logfile.'" was over '.$this->max_log_size.' bytes, moved to "'.$rotatedLogfile.'"'; - \OC_Log::write('OC\Log\Rotate', $msg, \OC_Log::WARN); - } -} diff --git a/lib/log/syslog.php b/lib/log/syslog.php deleted file mode 100644 index c98deab7109..00000000000 --- a/lib/log/syslog.php +++ /dev/null @@ -1,40 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_Log_Syslog { - static protected $levels = array( - OC_Log::DEBUG => LOG_DEBUG, - OC_Log::INFO => LOG_INFO, - OC_Log::WARN => LOG_WARNING, - OC_Log::ERROR => LOG_ERR, - OC_Log::FATAL => LOG_CRIT, - ); - - /** - * Init class data - */ - public static function init() { - openlog('ownCloud', LOG_PID | LOG_CONS, LOG_USER); - // Close at shutdown - register_shutdown_function('closelog'); - } - - /** - * write a message in the log - * @param string $app - * @param string $message - * @param int $level - */ - public static function write($app, $message, $level) { - $minLevel = min(OC_Config::getValue("loglevel", OC_Log::WARN), OC_Log::ERROR); - if ($level >= $minLevel) { - $syslog_level = self::$levels[$level]; - syslog($syslog_level, '{'.$app.'} '.$message); - } - } -} diff --git a/lib/mail.php b/lib/mail.php deleted file mode 100644 index b339b33e962..00000000000 --- a/lib/mail.php +++ /dev/null @@ -1,133 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * OC_Mail - * - * A class to handle mail sending. - */ - -require_once 'class.phpmailer.php'; - -class OC_Mail { - - /** - * send an email - * - * @param string $toaddress - * @param string $toname - * @param string $subject - * @param string $mailtext - * @param string $fromaddress - * @param string $fromname - * @param bool|int $html - * @param string $altbody - * @param string $ccaddress - * @param string $ccname - * @param string $bcc - * @throws Exception - */ - public static function send($toaddress, $toname, $subject, $mailtext, $fromaddress, $fromname, - $html=0, $altbody='', $ccaddress='', $ccname='', $bcc='') { - - $SMTPMODE = OC_Config::getValue( 'mail_smtpmode', 'sendmail' ); - $SMTPHOST = OC_Config::getValue( 'mail_smtphost', '127.0.0.1' ); - $SMTPPORT = OC_Config::getValue( 'mail_smtpport', 25 ); - $SMTPAUTH = OC_Config::getValue( 'mail_smtpauth', false ); - $SMTPAUTHTYPE = OC_Config::getValue( 'mail_smtpauthtype', 'LOGIN' ); - $SMTPUSERNAME = OC_Config::getValue( 'mail_smtpname', '' ); - $SMTPPASSWORD = OC_Config::getValue( 'mail_smtppassword', '' ); - $SMTPDEBUG = OC_Config::getValue( 'mail_smtpdebug', false ); - $SMTPTIMEOUT = OC_Config::getValue( 'mail_smtptimeout', 10 ); - $SMTPSECURE = OC_Config::getValue( 'mail_smtpsecure', '' ); - - - $mailo = new PHPMailer(true); - if($SMTPMODE=='sendmail') { - $mailo->IsSendmail(); - }elseif($SMTPMODE=='smtp') { - $mailo->IsSMTP(); - }elseif($SMTPMODE=='qmail') { - $mailo->IsQmail(); - }else{ - $mailo->IsMail(); - } - - - $mailo->Host = $SMTPHOST; - $mailo->Port = $SMTPPORT; - $mailo->SMTPAuth = $SMTPAUTH; - $mailo->SMTPDebug = $SMTPDEBUG; - $mailo->SMTPSecure = $SMTPSECURE; - $mailo->AuthType = $SMTPAUTHTYPE; - $mailo->Username = $SMTPUSERNAME; - $mailo->Password = $SMTPPASSWORD; - $mailo->Timeout = $SMTPTIMEOUT; - - $mailo->From = $fromaddress; - $mailo->FromName = $fromname;; - $mailo->Sender = $fromaddress; - $a=explode(' ', $toaddress); - try { - foreach($a as $ad) { - $mailo->AddAddress($ad, $toname); - } - - if($ccaddress<>'') $mailo->AddCC($ccaddress, $ccname); - if($bcc<>'') $mailo->AddBCC($bcc); - - $mailo->AddReplyTo($fromaddress, $fromname); - - $mailo->WordWrap = 50; - if($html==1) $mailo->IsHTML(true); else $mailo->IsHTML(false); - - $mailo->Subject = $subject; - if($altbody=='') { - $mailo->Body = $mailtext.OC_MAIL::getfooter(); - $mailo->AltBody = ''; - }else{ - $mailo->Body = $mailtext; - $mailo->AltBody = $altbody; - } - $mailo->CharSet = 'UTF-8'; - - $mailo->Send(); - unset($mailo); - OC_Log::write('mail', - 'Mail from '.$fromname.' ('.$fromaddress.')'.' to: '.$toname.'('.$toaddress.')'.' subject: '.$subject, - OC_Log::DEBUG); - } catch (Exception $exception) { - OC_Log::write('mail', $exception->getMessage(), OC_Log::ERROR); - throw($exception); - } - } - - /** - * return the footer for a mail - * - */ - public static function getfooter() { - - $defaults = new OC_Defaults(); - - $txt="\n--\n"; - $txt.=$defaults->getName() . "\n"; - $txt.=$defaults->getSlogan() . "\n"; - - return($txt); - - } - - /** - * @param string $emailAddress a given email address to be validated - * @return bool - */ - public static function ValidateAddress($emailAddress) { - return PHPMailer::ValidateAddress($emailAddress); - } -} diff --git a/lib/memcache/apc.php b/lib/memcache/apc.php deleted file mode 100644 index 575ee4427db..00000000000 --- a/lib/memcache/apc.php +++ /dev/null @@ -1,67 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Memcache; - -class APC extends Cache { - /** - * entries in APC gets namespaced to prevent collisions between owncloud instances and users - */ - protected function getNameSpace() { - return $this->prefix; - } - - public function get($key) { - $result = apc_fetch($this->getNamespace() . $key, $success); - if (!$success) { - return null; - } - return $result; - } - - public function set($key, $value, $ttl = 0) { - return apc_store($this->getNamespace() . $key, $value, $ttl); - } - - public function hasKey($key) { - return apc_exists($this->getNamespace() . $key); - } - - public function remove($key) { - return apc_delete($this->getNamespace() . $key); - } - - public function clear($prefix = '') { - $ns = $this->getNamespace() . $prefix; - $cache = apc_cache_info('user'); - foreach ($cache['cache_list'] as $entry) { - if (strpos($entry['info'], $ns) === 0) { - apc_delete($entry['info']); - } - } - return true; - } - - static public function isAvailable() { - if (!extension_loaded('apc')) { - return false; - } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { - return false; - } else { - return true; - } - } -} - -if (!function_exists('apc_exists')) { - function apc_exists($keys) { - $result = false; - apc_fetch($keys, $result); - return $result; - } -} diff --git a/lib/memcache/apcu.php b/lib/memcache/apcu.php deleted file mode 100644 index ccc1aa6e562..00000000000 --- a/lib/memcache/apcu.php +++ /dev/null @@ -1,28 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Memcache; - -class APCu extends APC { - public function clear($prefix = '') { - $ns = $this->getNamespace() . $prefix; - $ns = preg_quote($ns, '/'); - $iter = new \APCIterator('/^'.$ns.'/'); - return apc_delete($iter); - } - - static public function isAvailable() { - if (!extension_loaded('apcu')) { - return false; - } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { - return false; - } else { - return true; - } - } -} diff --git a/lib/memcache/cache.php b/lib/memcache/cache.php deleted file mode 100644 index 0ad1cc7ec03..00000000000 --- a/lib/memcache/cache.php +++ /dev/null @@ -1,77 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Memcache; - -abstract class Cache implements \ArrayAccess { - /** - * @var string $prefix - */ - protected $prefix; - - /** - * @param string $prefix - */ - public function __construct($prefix = '') { - $this->prefix = \OC_Util::getInstanceId() . '/' . $prefix; - } - - public function getPrefix() { - return $this->prefix; - } - - /** - * @param string $key - * @return mixed - */ - abstract public function get($key); - - /** - * @param string $key - * @param mixed $value - * @param int $ttl - * @return mixed - */ - abstract public function set($key, $value, $ttl = 0); - - /** - * @param string $key - * @return mixed - */ - abstract public function hasKey($key); - - /** - * @param string $key - * @return mixed - */ - abstract public function remove($key); - - /** - * @param string $prefix - * @return mixed - */ - abstract public function clear($prefix = ''); - - //implement the ArrayAccess interface - - public function offsetExists($offset) { - return $this->hasKey($offset); - } - - public function offsetSet($offset, $value) { - $this->set($offset, $value); - } - - public function offsetGet($offset) { - return $this->get($offset); - } - - public function offsetUnset($offset) { - $this->remove($offset); - } -} diff --git a/lib/memcache/factory.php b/lib/memcache/factory.php deleted file mode 100644 index fde7d947567..00000000000 --- a/lib/memcache/factory.php +++ /dev/null @@ -1,69 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Memcache; - -class Factory { - /** - * get a cache instance, will return null if no backend is available - * - * @param string $prefix - * @return \OC\Memcache\Cache - */ - function create($prefix = '') { - if (XCache::isAvailable()) { - return new XCache($prefix); - } elseif (APCu::isAvailable()) { - return new APCu($prefix); - } elseif (APC::isAvailable()) { - return new APC($prefix); - } elseif (Memcached::isAvailable()) { - return new Memcached($prefix); - } else { - return null; - } - } - - /** - * check if there is a memcache backend available - * - * @return bool - */ - public function isAvailable() { - return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Memcached::isAvailable(); - } - - /** - * get a in-server cache instance, will return null if no backend is available - * - * @param string $prefix - * @return \OC\Memcache\Cache - */ - public static function createLowLatency($prefix = '') { - if (XCache::isAvailable()) { - return new XCache($prefix); - } elseif (APCu::isAvailable()) { - return new APCu($prefix); - } elseif (APC::isAvailable()) { - return new APC($prefix); - } else { - return null; - } - } - - /** - * check if there is a in-server backend available - * - * @return bool - */ - public static function isAvailableLowLatency() { - return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable(); - } - - -} diff --git a/lib/memcache/memcached.php b/lib/memcache/memcached.php deleted file mode 100644 index 978e6c2eff1..00000000000 --- a/lib/memcache/memcached.php +++ /dev/null @@ -1,76 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Memcache; - -class Memcached extends Cache { - /** - * @var \Memcached $cache - */ - private static $cache = null; - - public function __construct($prefix = '') { - parent::__construct($prefix); - if (is_null(self::$cache)) { - self::$cache = new \Memcached(); - list($host, $port) = \OC_Config::getValue('memcached_server', array('localhost', 11211)); - self::$cache->addServer($host, $port); - } - } - - /** - * entries in XCache gets namespaced to prevent collisions between owncloud instances and users - */ - protected function getNameSpace() { - return $this->prefix; - } - - public function get($key) { - $result = self::$cache->get($this->getNamespace() . $key); - if ($result === false and self::$cache->getResultCode() == \Memcached::RES_NOTFOUND) { - return null; - } else { - return $result; - } - } - - public function set($key, $value, $ttl = 0) { - if ($ttl > 0) { - return self::$cache->set($this->getNamespace() . $key, $value, $ttl); - } else { - return self::$cache->set($this->getNamespace() . $key, $value); - } - } - - public function hasKey($key) { - self::$cache->get($this->getNamespace() . $key); - return self::$cache->getResultCode() !== \Memcached::RES_NOTFOUND; - } - - public function remove($key) { - return self::$cache->delete($this->getNamespace() . $key); - } - - public function clear($prefix = '') { - $prefix = $this->getNamespace() . $prefix; - $allKeys = self::$cache->getAllKeys(); - $keys = array(); - $prefixLength = strlen($prefix); - foreach ($allKeys as $key) { - if (substr($key, 0, $prefixLength) === $prefix) { - $keys[] = $key; - } - } - self::$cache->deleteMulti($keys); - return true; - } - - static public function isAvailable() { - return extension_loaded('memcached'); - } -} diff --git a/lib/memcache/xcache.php b/lib/memcache/xcache.php deleted file mode 100644 index 33de30562f9..00000000000 --- a/lib/memcache/xcache.php +++ /dev/null @@ -1,60 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Memcache; - -class XCache extends Cache { - /** - * entries in XCache gets namespaced to prevent collisions between owncloud instances and users - */ - protected function getNameSpace() { - return $this->prefix; - } - - public function get($key) { - return xcache_get($this->getNamespace().$key); - } - - public function set($key, $value, $ttl=0) { - if($ttl>0) { - return xcache_set($this->getNamespace().$key, $value, $ttl); - }else{ - return xcache_set($this->getNamespace().$key, $value); - } - } - - public function hasKey($key) { - return xcache_isset($this->getNamespace().$key); - } - - public function remove($key) { - return xcache_unset($this->getNamespace().$key); - } - - public function clear($prefix='') { - xcache_unset_by_prefix($this->getNamespace().$prefix); - return true; - } - - static public function isAvailable(){ - if (!extension_loaded('xcache')) { - return false; - } elseif (\OC::$CLI) { - return false; - }else{ - return true; - } - } -} - -if(!function_exists('xcache_unset_by_prefix')) { - function xcache_unset_by_prefix($prefix) { - // Since we can't clear targetted cache, we'll clear all. :( - xcache_clear_cache(\XC_TYPE_VAR, 0); - } -} diff --git a/lib/migrate.php b/lib/migrate.php deleted file mode 100644 index 0b319177400..00000000000 --- a/lib/migrate.php +++ /dev/null @@ -1,693 +0,0 @@ -. - * - */ - - -/** - * provides an interface to migrate users and whole ownclouds - */ -class OC_Migrate{ - - - // Array of OC_Migration_Provider objects - static private $providers=array(); - // User id of the user to import/export - static private $uid=false; - // Holds the ZipArchive object - static private $zip=false; - // Stores the type of export - static private $exporttype=false; - // Array of temp files to be deleted after zip creation - static private $tmpfiles=array(); - // Holds the db object - static private $MDB2=false; - // Schema db object - static private $schema=false; - // Path to the sqlite db - static private $dbpath=false; - // Holds the path to the zip file - static private $zippath=false; - // Holds the OC_Migration_Content object - static private $content=false; - - /** - * register a new migration provider - * @param OC_Migrate_Provider $provider - */ - public static function registerProvider($provider) { - self::$providers[]=$provider; - } - - /** - * @brief finds and loads the providers - */ - static private function findProviders() { - // Find the providers - $apps = OC_App::getAllApps(); - - foreach($apps as $app) { - $path = OC_App::getAppPath($app) . '/appinfo/migrate.php'; - if( file_exists( $path ) ) { - include $path; - } - } - } - - /** - * @brief exports a user, or owncloud instance - * @param optional $uid string user id of user to export if export type is user, defaults to current - * @param ootional $type string type of export, defualts to user - * @param otional $path string path to zip output folder - * @return false on error, path to zip on success - */ - public static function export( $uid=null, $type='user', $path=null ) { - $datadir = OC_Config::getValue( 'datadirectory' ); - // Validate export type - $types = array( 'user', 'instance', 'system', 'userfiles' ); - if( !in_array( $type, $types ) ) { - OC_Log::write( 'migration', 'Invalid export type', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - self::$exporttype = $type; - // Userid? - if( self::$exporttype == 'user' ) { - // Check user exists - self::$uid = is_null($uid) ? OC_User::getUser() : $uid; - if(!OC_User::userExists(self::$uid)) { - return json_encode( array( 'success' => false) ); - } - } - // Calculate zipname - if( self::$exporttype == 'user' ) { - $zipname = 'oc_export_' . self::$uid . '_' . date("y-m-d_H-i-s") . '.zip'; - } else { - $zipname = 'oc_export_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '.zip'; - } - // Calculate path - if( self::$exporttype == 'user' ) { - self::$zippath = $datadir . '/' . self::$uid . '/' . $zipname; - } else { - if( !is_null( $path ) ) { - // Validate custom path - if( !file_exists( $path ) || !is_writeable( $path ) ) { - OC_Log::write( 'migration', 'Path supplied is invalid.', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - self::$zippath = $path . $zipname; - } else { - // Default path - self::$zippath = get_temp_dir() . '/' . $zipname; - } - } - // Create the zip object - if( !self::createZip() ) { - return json_encode( array( 'success' => false ) ); - } - // Do the export - self::findProviders(); - $exportdata = array(); - switch( self::$exporttype ) { - case 'user': - // Connect to the db - self::$dbpath = $datadir . '/' . self::$uid . '/migration.db'; - if( !self::connectDB() ) { - return json_encode( array( 'success' => false ) ); - } - self::$content = new OC_Migration_Content( self::$zip, self::$MDB2 ); - // Export the app info - $exportdata = self::exportAppData(); - // Add the data dir to the zip - self::$content->addDir(OC_User::getHome(self::$uid), true, '/' ); - break; - case 'instance': - self::$content = new OC_Migration_Content( self::$zip ); - // Creates a zip that is compatable with the import function - $dbfile = tempnam( get_temp_dir(), "owncloud_export_data_" ); - OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL'); - - // Now add in *dbname* and *dbprefix* - $dbexport = file_get_contents( $dbfile ); - $dbnamestring = "\n\n " . OC_Config::getValue( "dbname", "owncloud" ); - $dbtableprefixstring = "\n\n " . OC_Config::getValue( "dbtableprefix", "oc_" ); - $dbexport = str_replace( $dbnamestring, "\n\n *dbname*", $dbexport ); - $dbexport = str_replace( $dbtableprefixstring, "
\n\n *dbprefix*", $dbexport ); - // Add the export to the zip - self::$content->addFromString( $dbexport, "dbexport.xml" ); - // Add user data - foreach(OC_User::getUsers() as $user) { - self::$content->addDir(OC_User::getHome($user), true, "/userdata/" ); - } - break; - case 'userfiles': - self::$content = new OC_Migration_Content( self::$zip ); - // Creates a zip with all of the users files - foreach(OC_User::getUsers() as $user) { - self::$content->addDir(OC_User::getHome($user), true, "/" ); - } - break; - case 'system': - self::$content = new OC_Migration_Content( self::$zip ); - // Creates a zip with the owncloud system files - self::$content->addDir( OC::$SERVERROOT . '/', false, '/'); - foreach (array( - ".git", - "3rdparty", - "apps", - "core", - "files", - "l10n", - "lib", - "ocs", - "search", - "settings", - "tests" - ) as $dir) { - self::$content->addDir( OC::$SERVERROOT . '/' . $dir, true, "/"); - } - break; - } - if( !$info = self::getExportInfo( $exportdata ) ) { - return json_encode( array( 'success' => false ) ); - } - // Add the export info json to the export zip - self::$content->addFromString( $info, 'export_info.json' ); - if( !self::$content->finish() ) { - return json_encode( array( 'success' => false ) ); - } - return json_encode( array( 'success' => true, 'data' => self::$zippath ) ); - } - - /** - * @brief imports a user, or owncloud instance - * @param $path string path to zip - * @param optional $type type of import (user or instance) - * @param optional $uid userid of new user - */ - public static function import( $path, $type='user', $uid=null ) { - - $datadir = OC_Config::getValue( 'datadirectory' ); - // Extract the zip - if( !$extractpath = self::extractZip( $path ) ) { - return json_encode( array( 'success' => false ) ); - } - // Get export_info.json - $scan = scandir( $extractpath ); - // Check for export_info.json - if( !in_array( 'export_info.json', $scan ) ) { - OC_Log::write( 'migration', 'Invalid import file, export_info.json not found', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - $json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) ); - if( $json->exporttype != $type ) { - OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - self::$exporttype = $type; - - $currentuser = OC_User::getUser(); - - // Have we got a user if type is user - if( self::$exporttype == 'user' ) { - self::$uid = !is_null($uid) ? $uid : $currentuser; - } - - // We need to be an admin if we are not importing our own data - if(($type == 'user' && self::$uid != $currentuser) || $type != 'user' ) { - if( !OC_User::isAdminUser($currentuser)) { - // Naughty. - OC_Log::write( 'migration', 'Import not permitted.', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - } - - // Handle export types - switch( self::$exporttype ) { - case 'user': - // Check user availability - if( !OC_User::userExists( self::$uid ) ) { - OC_Log::write( 'migration', 'User doesn\'t exist', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Check if the username is valid - if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $json->exporteduser )) { - OC_Log::write( 'migration', 'Username is not valid', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Copy data - $userfolder = $extractpath . $json->exporteduser; - $newuserfolder = $datadir . '/' . self::$uid; - foreach(scandir($userfolder) as $file){ - if($file !== '.' && $file !== '..' && is_dir($file)) { - $file = str_replace(array('/', '\\'), '', $file); - - // Then copy the folder over - OC_Helper::copyr($userfolder.'/'.$file, $newuserfolder.'/'.$file); - } - } - // Import user app data - if(file_exists($extractpath . $json->exporteduser . '/migration.db')) { - if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', - $json, - self::$uid ) ) { - return json_encode( array( 'success' => false ) ); - } - } - // All done! - if( !self::unlink_r( $extractpath ) ) { - OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR ); - } - return json_encode( array( 'success' => true, 'data' => $appsimported ) ); - break; - case 'instance': - /* - * EXPERIMENTAL - // Check for new data dir and dbexport before doing anything - // TODO - - // Delete current data folder. - OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO ); - if( !self::unlink_r( $datadir, false ) ) { - OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Copy over data - if( !self::copy_r( $extractpath . 'userdata', $datadir ) ) { - OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - - // Import the db - if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ) { - return json_encode( array( 'success' => false ) ); - } - // Done - return json_encode( array( 'success' => true ) ); - */ - break; - } - - } - - /** - * @brief recursively deletes a directory - * @param $dir string path of dir to delete - * $param optional $deleteRootToo bool delete the root directory - * @return bool - */ - private static function unlink_r( $dir, $deleteRootToo=true ) { - if( !$dh = @opendir( $dir ) ) { - return false; - } - while (false !== ($obj = readdir($dh))) { - if($obj == '.' || $obj == '..') { - continue; - } - if (!@unlink($dir . '/' . $obj)) { - self::unlink_r($dir.'/'.$obj, true); - } - } - closedir($dh); - if ( $deleteRootToo ) { - @rmdir($dir); - } - return true; - } - - /** - * @brief tries to extract the import zip - * @param $path string path to the zip - * @return string path to extract location (with a trailing slash) or false on failure - */ - static private function extractZip( $path ) { - self::$zip = new ZipArchive; - // Validate path - if( !file_exists( $path ) ) { - OC_Log::write( 'migration', 'Zip not found', OC_Log::ERROR ); - return false; - } - if ( self::$zip->open( $path ) != true ) { - OC_Log::write( 'migration', "Failed to open zip file", OC_Log::ERROR ); - return false; - } - $to = get_temp_dir() . '/oc_import_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '/'; - if( !self::$zip->extractTo( $to ) ) { - return false; - } - self::$zip->close(); - return $to; - } - - /** - * @brief connects to a MDB2 database scheme - * @returns bool - */ - static private function connectScheme() { - // We need a mdb2 database connection - self::$MDB2->loadModule( 'Manager' ); - self::$MDB2->loadModule( 'Reverse' ); - - // Connect if this did not happen before - if( !self::$schema ) { - require_once 'MDB2/Schema.php'; - self::$schema=MDB2_Schema::factory( self::$MDB2 ); - } - - return true; - } - - /** - * @brief creates a migration.db in the users data dir with their app data in - * @return bool whether operation was successfull - */ - private static function exportAppData( ) { - - $success = true; - $return = array(); - - // Foreach provider - foreach( self::$providers as $provider ) { - // Check if the app is enabled - if( OC_App::isEnabled( $provider->getID() ) ) { - $success = true; - // Does this app use the database? - if( file_exists( OC_App::getAppPath($provider->getID()).'/appinfo/database.xml' ) ) { - // Create some app tables - $tables = self::createAppTables( $provider->getID() ); - if( is_array( $tables ) ) { - // Save the table names - foreach($tables as $table) { - $return['apps'][$provider->getID()]['tables'][] = $table; - } - } else { - // It failed to create the tables - $success = false; - } - } - - // Run the export function? - if( $success ) { - // Set the provider properties - $provider->setData( self::$uid, self::$content ); - $return['apps'][$provider->getID()]['success'] = $provider->export(); - } else { - $return['apps'][$provider->getID()]['success'] = false; - $return['apps'][$provider->getID()]['message'] = 'failed to create the app tables'; - } - - // Now add some app info the the return array - $appinfo = OC_App::getAppInfo( $provider->getID() ); - $return['apps'][$provider->getID()]['version'] = OC_App::getAppVersion($provider->getID()); - } - } - - return $return; - - } - - - /** - * @brief generates json containing export info, and merges any data supplied - * @param optional $array array of data to include in the returned json - * @return bool - */ - static private function getExportInfo( $array=array() ) { - $info = array( - 'ocversion' => OC_Util::getVersion(), - 'exporttime' => time(), - 'exportedby' => OC_User::getUser(), - 'exporttype' => self::$exporttype, - 'exporteduser' => self::$uid - ); - - if( !is_array( $array ) ) { - OC_Log::write( 'migration', 'Supplied $array was not an array in getExportInfo()', OC_Log::ERROR ); - } - // Merge in other data - $info = array_merge( $info, (array)$array ); - // Create json - $json = json_encode( $info ); - return $json; - } - - /** - * @brief connects to migration.db, or creates if not found - * @param $db optional path to migration.db, defaults to user data dir - * @return bool whether the operation was successful - */ - static private function connectDB( $path=null ) { - // Has the dbpath been set? - self::$dbpath = !is_null( $path ) ? $path : self::$dbpath; - if( !self::$dbpath ) { - OC_Log::write( 'migration', 'connectDB() was called without dbpath being set', OC_Log::ERROR ); - return false; - } - // Already connected - if(!self::$MDB2) { - require_once 'MDB2.php'; - - $datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - - // DB type - if( class_exists( 'SQLite3' ) ) { - $dbtype = 'sqlite3'; - } else if( is_callable( 'sqlite_open' ) ) { - $dbtype = 'sqlite'; - } else { - OC_Log::write( 'migration', 'SQLite not found', OC_Log::ERROR ); - return false; - } - - // Prepare options array - $options = array( - 'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE), - 'log_line_break' => '
', - 'idxname_format' => '%s', - 'debug' => true, - 'quote_identifier' => true - ); - $dsn = array( - 'phptype' => $dbtype, - 'database' => self::$dbpath, - 'mode' => '0644' - ); - - // Try to establish connection - self::$MDB2 = MDB2::factory( $dsn, $options ); - // Die if we could not connect - if( PEAR::isError( self::$MDB2 ) ) { - die( self::$MDB2->getMessage() ); - OC_Log::write( 'migration', 'Failed to create/connect to migration.db', OC_Log::FATAL ); - OC_Log::write( 'migration', self::$MDB2->getUserInfo(), OC_Log::FATAL ); - OC_Log::write( 'migration', self::$MDB2->getMessage(), OC_Log::FATAL ); - return false; - } - // We always, really always want associative arrays - self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC); - } - return true; - - } - - /** - * @brief creates the tables in migration.db from an apps database.xml - * @param $appid string id of the app - * @return bool whether the operation was successful - */ - static private function createAppTables( $appid ) { - - if( !self::connectScheme() ) { - return false; - } - - // There is a database.xml file - $content = file_get_contents(OC_App::getAppPath($appid) . '/appinfo/database.xml' ); - - $file2 = 'static://db_scheme'; - // TODO get the relative path to migration.db from the data dir - // For now just cheat - $path = pathinfo( self::$dbpath ); - $content = str_replace( '*dbname*', self::$uid.'/migration', $content ); - $content = str_replace( '*dbprefix*', '', $content ); - - $xml = new SimpleXMLElement($content); - foreach($xml->table as $table) { - $tables[] = (string)$table->name; - } - - file_put_contents( $file2, $content ); - - // Try to create tables - $definition = self::$schema->parseDatabaseDefinitionFile( $file2 ); - - unlink( $file2 ); - - // Die in case something went wrong - if( $definition instanceof MDB2_Schema_Error ) { - OC_Log::write( 'migration', 'Failed to parse database.xml for: '.$appid, OC_Log::FATAL ); - OC_Log::write( 'migration', $definition->getMessage().': '.$definition->getUserInfo(), OC_Log::FATAL ); - return false; - } - - $definition['overwrite'] = true; - - $ret = self::$schema->createDatabase( $definition ); - - // Die in case something went wrong - if( $ret instanceof MDB2_Error ) { - OC_Log::write( 'migration', 'Failed to create tables for: '.$appid, OC_Log::FATAL ); - OC_Log::write( 'migration', $ret->getMessage().': '.$ret->getUserInfo(), OC_Log::FATAL ); - return false; - } - return $tables; - - } - - /** - * @brief tries to create the zip - * @param $path string path to zip destination - * @return bool - */ - static private function createZip() { - self::$zip = new ZipArchive; - // Check if properties are set - if( !self::$zippath ) { - OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR); - return false; - } - if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== true ) { - OC_Log::write('migration', - 'Failed to create the zip with error: '.self::$zip->getStatusString(), - OC_Log::ERROR); - return false; - } else { - return true; - } - } - - /** - * @brief returns an array of apps that support migration - * @return array - */ - static public function getApps() { - $allapps = OC_App::getAllApps(); - foreach($allapps as $app) { - $path = self::getAppPath($app) . '/lib/migrate.php'; - if( file_exists( $path ) ) { - $supportsmigration[] = $app; - } - } - return $supportsmigration; - } - - /** - * @brief imports a new user - * @param $db string path to migration.db - * @param $info object of migration info - * @param $uid optional uid to use - * @return array of apps with import statuses, or false on failure. - */ - public static function importAppData( $db, $info, $uid=null ) { - // Check if the db exists - if( file_exists( $db ) ) { - // Connect to the db - if(!self::connectDB( $db )) { - OC_Log::write('migration', 'Failed to connect to migration.db', OC_Log::ERROR); - return false; - } - } else { - OC_Log::write('migration', 'Migration.db not found at: '.$db, OC_Log::FATAL ); - return false; - } - - // Find providers - self::findProviders(); - - // Generate importinfo array - $importinfo = array( - 'olduid' => $info->exporteduser, - 'newuid' => self::$uid - ); - - foreach( self::$providers as $provider) { - // Is the app in the export? - $id = $provider->getID(); - if( isset( $info->apps->$id ) ) { - // Is the app installed - if( !OC_App::isEnabled( $id ) ) { - OC_Log::write( 'migration', - 'App: ' . $id . ' is not installed, can\'t import data.', - OC_Log::INFO ); - $appsstatus[$id] = 'notsupported'; - } else { - // Did it succeed on export? - if( $info->apps->$id->success ) { - // Give the provider the content object - if( !self::connectDB( $db ) ) { - return false; - } - $content = new OC_Migration_Content( self::$zip, self::$MDB2 ); - $provider->setData( self::$uid, $content, $info ); - // Then do the import - if( !$appsstatus[$id] = $provider->import( $info->apps->$id, $importinfo ) ) { - // Failed to import app - OC_Log::write( 'migration', - 'Failed to import app data for user: ' . self::$uid . ' for app: ' . $id, - OC_Log::ERROR ); - } - } else { - // Add to failed list - $appsstatus[$id] = false; - } - } - } - } - - return $appsstatus; - - } - - /* - * @brief creates a new user in the database - * @param $uid string user_id of the user to be created - * @param $hash string hash of the user to be created - * @return bool result of user creation - */ - public static function createUser( $uid, $hash ) { - - // Check if userid exists - if(OC_User::userExists( $uid )) { - return false; - } - - // Create the user - $query = OC_DB::prepare( "INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )" ); - $result = $query->execute( array( $uid, $hash)); - if( !$result ) { - OC_Log::write('migration', 'Failed to create the new user "'.$uid."", OC_Log::ERROR); - } - return $result ? true : false; - - } - -} diff --git a/lib/migration/content.php b/lib/migration/content.php deleted file mode 100644 index 4413d722731..00000000000 --- a/lib/migration/content.php +++ /dev/null @@ -1,258 +0,0 @@ -. - * - */ - - -/** - * provides methods to add and access data from the migration - */ -class OC_Migration_Content{ - - private $zip=false; - // Holds the MDB2 object - private $db=null; - // Holds an array of tmpfiles to delete after zip creation - private $tmpfiles=array(); - - /** - * @brief sets up the - * @param $zip ZipArchive object - * @param optional $db a MDB2 database object (required for exporttype user) - * @return bool - */ - public function __construct( $zip, $db=null ) { - - $this->zip = $zip; - $this->db = $db; - - } - - // @brief prepares the db - // @param $query the sql query to prepare - public function prepare( $query ) { - - // Only add database to tmpfiles if actually used - if( !is_null( $this->db ) ) { - // Get db path - $db = $this->db->getDatabase(); - if(!in_array($db, $this->tmpfiles)) { - $this->tmpfiles[] = $db; - } - } - - // Optimize the query - $query = $this->processQuery( $query ); - - // Optimize the query - $query = $this->db->prepare( $query ); - - // Die if we have an error (error means: bad query, not 0 results!) - if( PEAR::isError( $query ) ) { - $entry = 'DB Error: "'.$query->getMessage().'"
'; - $entry .= 'Offending command was: '.$query.'
'; - OC_Log::write( 'migration', $entry, OC_Log::FATAL ); - return false; - } else { - return $query; - } - - } - - /** - * @brief processes the db query - * @param $query the query to process - * @return string of processed query - */ - private function processQuery( $query ) { - $query = str_replace( '`', '\'', $query ); - $query = str_replace( 'NOW()', 'datetime(\'now\')', $query ); - $query = str_replace( 'now()', 'datetime(\'now\')', $query ); - // remove table prefixes - $query = str_replace( '*PREFIX*', '', $query ); - return $query; - } - - /** - * @brief copys rows to migration.db from the main database - * @param $options array of options. - * @return bool - */ - public function copyRows( $options ) { - if( !array_key_exists( 'table', $options ) ) { - return false; - } - - $return = array(); - - // Need to include 'where' in the query? - if( array_key_exists( 'matchval', $options ) && array_key_exists( 'matchcol', $options ) ) { - - // If only one matchval, create an array - if(!is_array($options['matchval'])) { - $options['matchval'] = array( $options['matchval'] ); - } - - foreach( $options['matchval'] as $matchval ) { - // Run the query for this match value (where x = y value) - $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '` WHERE `' . $options['matchcol'] . '` = ?'; - $query = OC_DB::prepare( $sql ); - $results = $query->execute( array( $matchval ) ); - $newreturns = $this->insertData( $results, $options ); - $return = array_merge( $return, $newreturns ); - } - - } else { - // Just get everything - $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '`'; - $query = OC_DB::prepare( $sql ); - $results = $query->execute(); - $return = $this->insertData( $results, $options ); - - } - - return $return; - - } - - /** - * @brief saves a sql data set into migration.db - * @param $data a sql data set returned from self::prepare()->query() - * @param $options array of copyRows options - * @return void - */ - private function insertData( $data, $options ) { - $return = array(); - // Foreach row of data to insert - while( $row = $data->fetchRow() ) { - // Now save all this to the migration.db - foreach($row as $field=>$value) { - $fields[] = $field; - $values[] = $value; - } - - // Generate some sql - $sql = "INSERT INTO `" . $options['table'] . '` ( `'; - $fieldssql = implode( '`, `', $fields ); - $sql .= $fieldssql . "` ) VALUES( "; - $valuessql = substr( str_repeat( '?, ', count( $fields ) ), 0, -2 ); - $sql .= $valuessql . " )"; - // Make the query - $query = $this->prepare( $sql ); - if( !$query ) { - OC_Log::write( 'migration', 'Invalid sql produced: '.$sql, OC_Log::FATAL ); - return false; - exit(); - } else { - $query->execute( $values ); - // Do we need to return some values? - if( array_key_exists( 'idcol', $options ) ) { - // Yes we do - $return[] = $row[$options['idcol']]; - } else { - // Take a guess and return the first field :) - $return[] = reset($row); - } - } - $fields = ''; - $values = ''; - } - return $return; - } - - /** - * @brief adds a directory to the zip object - * @param $dir string path of the directory to add - * @param $recursive bool - * @param $internaldir string path of folder to add dir to in zip - * @return bool - */ - public function addDir( $dir, $recursive=true, $internaldir='' ) { - $dirname = basename($dir); - $this->zip->addEmptyDir($internaldir . $dirname); - $internaldir.=$dirname.='/'; - if( !file_exists( $dir ) ) { - return false; - } - $dirhandle = opendir($dir); - if(is_resource($dirhandle)) { - while (false !== ( $file = readdir($dirhandle))) { - - if (( $file != '.' ) && ( $file != '..' )) { - - if (is_dir($dir . '/' . $file) && $recursive) { - $this->addDir($dir . '/' . $file, $recursive, $internaldir); - } elseif (is_file($dir . '/' . $file)) { - $this->zip->addFile($dir . '/' . $file, $internaldir . $file); - } - } - } - closedir($dirhandle); - } else { - OC_Log::write('admin_export', "Was not able to open directory: " . $dir, OC_Log::ERROR); - return false; - } - return true; - } - - /** - * @brief adds a file to the zip from a given string - * @param $data string of data to add - * @param $path the relative path inside of the zip to save the file to - * @return bool - */ - public function addFromString( $data, $path ) { - // Create a temp file - $file = tempnam( get_temp_dir(). '/', 'oc_export_tmp_' ); - $this->tmpfiles[] = $file; - if( !file_put_contents( $file, $data ) ) { - OC_Log::write( 'migation', 'Failed to save data to a temporary file', OC_Log::ERROR ); - return false; - } - // Add file to the zip - $this->zip->addFile( $file, $path ); - return true; - } - - /** - * @brief closes the zip, removes temp files - * @return bool - */ - public function finish() { - if( !$this->zip->close() ) { - OC_Log::write( 'migration', - 'Failed to write the zip file with error: '.$this->zip->getStatusString(), - OC_Log::ERROR ); - return false; - } - $this->cleanup(); - return true; - } - - /** - * @brief cleans up after the zip - */ - private function cleanup() { - // Delete tmp files - foreach($this->tmpfiles as $i) { - unlink( $i ); - } - } -} diff --git a/lib/migration/provider.php b/lib/migration/provider.php deleted file mode 100644 index 234ab3351f3..00000000000 --- a/lib/migration/provider.php +++ /dev/null @@ -1,52 +0,0 @@ -id = $appid; - OC_Migrate::registerProvider( $this ); - } - - /** - * @brief exports data for apps - * @return array appdata to be exported - */ - abstract function export( ); - - /** - * @brief imports data for the app - * @return void - */ - abstract function import( ); - - /** - * @brief sets the OC_Migration_Content object to $this->content - * @param $content a OC_Migration_Content object - */ - public function setData( $uid, $content, $info=null ) { - $this->content = $content; - $this->uid = $uid; - $id = $this->id; - if( !is_null( $info ) ) { - $this->olduid = $info->exporteduser; - $this->appinfo = $info->apps->$id; - } - } - - /** - * @brief returns the appid of the provider - * @return string - */ - public function getID() { - return $this->id; - } -} diff --git a/lib/mimetypes.list.php b/lib/mimetypes.list.php deleted file mode 100644 index 8ab8ac81bd8..00000000000 --- a/lib/mimetypes.list.php +++ /dev/null @@ -1,107 +0,0 @@ -. -* -*/ - -/** - * list of mimetypes by extension - */ - -return array( - 'css'=>'text/css', - 'flac'=>'audio/flac', - 'gif'=>'image/gif', - 'gzip'=>'application/x-gzip', - 'gz'=>'application/x-gzip', - 'html'=>'text/html', - 'htm'=>'text/html', - 'ics'=>'text/calendar', - 'ical'=>'text/calendar', - 'jpeg'=>'image/jpeg', - 'jpg'=>'image/jpeg', - 'js'=>'application/javascript', - 'oga'=>'audio/ogg', - 'ogg'=>'audio/ogg', - 'ogv'=>'video/ogg', - 'pdf'=>'application/pdf', - 'png'=>'image/png', - 'svg'=>'image/svg+xml', - 'tar'=>'application/x-tar', - 'tgz'=>'application/x-compressed', - 'tar.gz'=>'application/x-compressed', - 'tif'=>'image/tiff', - 'tiff'=>'image/tiff', - 'txt'=>'text/plain', - 'zip'=>'application/zip', - 'wav'=>'audio/wav', - 'odt'=>'application/vnd.oasis.opendocument.text', - 'ods'=>'application/vnd.oasis.opendocument.spreadsheet', - 'odg'=>'application/vnd.oasis.opendocument.graphics', - 'odp'=>'application/vnd.oasis.opendocument.presentation', - 'pages'=>'application/x-iwork-pages-sffpages', - 'numbers'=>'application/x-iwork-numbers-sffnumbers', - 'keynote'=>'application/x-iwork-keynote-sffkey', - 'kra'=>'application/x-krita', - 'mp3'=>'audio/mpeg', - 'doc'=>'application/msword', - 'docx'=>'application/msword', - 'xls'=>'application/msexcel', - 'xlsx'=>'application/msexcel', - 'php'=>'application/x-php', - 'exe'=>'application/x-ms-dos-executable', - 'pl'=>'application/x-pearl', - 'py'=>'application/x-python', - 'blend'=>'application/x-blender', - 'xcf'=>'application/x-gimp', - 'psd'=>'application/x-photoshop', - 'xml'=>'application/xml', - 'avi'=>'video/x-msvideo', - 'dv'=>'video/dv', - 'm2t'=>'video/mp2t', - 'mp4'=>'video/mp4', - 'm4v'=>'video/mp4', - 'mpg'=>'video/mpeg', - 'mpeg'=>'video/mpeg', - 'mov'=>'video/quicktime', - 'webm'=>'video/webm', - 'wmv'=>'video/x-ms-asf', - 'py'=>'text/x-script.phyton', - 'vcf' => 'text/vcard', - 'vcard' => 'text/vcard', - 'doc'=>'application/msword', - 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'xls'=>'application/msexcel', - 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'ppt'=>'application/mspowerpoint', - 'pptx'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'sgf' => 'application/sgf', - 'cdr' => 'application/coreldraw', - 'impress' => 'text/impress', - 'ai' => 'application/illustrator', - 'epub' => 'application/epub+zip', - 'mobi' => 'application/x-mobipocket-ebook', - 'exe' => 'application', - 'msi' => 'application', - 'md' => 'text/markdown', - 'markdown' => 'text/markdown', - 'mdown' => 'text/markdown', - 'mdwn' => 'text/markdown', - 'reveal' => 'text/reveal' -); diff --git a/lib/minimizer.php b/lib/minimizer.php deleted file mode 100644 index db522de74dc..00000000000 --- a/lib/minimizer.php +++ /dev/null @@ -1,64 +0,0 @@ -contentType); - OC_Response::enableCaching(); - $etag = $this->generateETag($files); - $cache_key .= '-'.$etag; - - $gzout = false; - $cache = OC_Cache::getGlobalCache(); - if (!OC_Request::isNoCache() && (!defined('DEBUG') || !DEBUG)) { - OC_Response::setETagHeader($etag); - $gzout = $cache->get($cache_key.'.gz'); - } - - if (!$gzout) { - $out = $this->minimizeFiles($files); - $gzout = gzencode($out); - $cache->set($cache_key.'.gz', $gzout); - OC_Response::setETagHeader($etag); - } - // on some systems (e.g. SLES 11, but not Ubuntu) mod_deflate and zlib compression will compress the output twice. - // This results in broken core.css and core.js. To avoid it, we switch off zlib compression. - // Since mod_deflate is still active, Apache will compress what needs to be compressed, i.e. no disadvantage. - if(function_exists('apache_get_modules') && ini_get('zlib.output_compression') && in_array('mod_deflate', apache_get_modules())) { - ini_set('zlib.output_compression', 'Off'); - } - if ($encoding = OC_Request::acceptGZip()) { - header('Content-Encoding: '.$encoding); - $out = $gzout; - } else { - $out = gzdecode($gzout); - } - header('Content-Length: '.strlen($out)); - echo $out; - } - - public function clearCache() { - $cache = OC_Cache::getGlobalCache(); - $cache->clear('core.css'); - $cache->clear('core.js'); - } -} - -if (!function_exists('gzdecode')) { - function gzdecode($data, $maxlength=null, &$filename='', &$error='') - { - if (strcmp(substr($data, 0, 9),"\x1f\x8b\x8\0\0\0\0\0\0")) { - return null; // Not the GZIP format we expect (See RFC 1952) - } - return gzinflate(substr($data, 10, -8)); - } -} diff --git a/lib/minimizer/css.php b/lib/minimizer/css.php deleted file mode 100644 index 8d130572e2b..00000000000 --- a/lib/minimizer/css.php +++ /dev/null @@ -1,38 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - * - */ - -namespace OC; - -/** - * Manages the ownCloud navigation - */ -class NavigationManager implements \OCP\INavigationManager { - protected $entries = array(); - protected $activeEntry; - - /** - * Creates a new navigation entry - * @param array $entry containing: id, name, order, icon and href key - */ - public function add(array $entry) { - $entry['active'] = false; - if(!isset($entry['icon'])) { - $entry['icon'] = ''; - } - $this->entries[] = $entry; - } - - /** - * @brief returns all the added Menu entries - * @return array of the added entries - */ - public function getAll() { - return $this->entries; - } - - /** - * @brief removes all the entries - */ - public function clear() { - $this->entries = array(); - } - - /** - * Sets the current navigation entry of the currently running app - * @param string $id of the app entry to activate (from added $entry) - */ - public function setActiveEntry($id) { - $this->activeEntry = $id; - } - - /** - * @brief gets the active Menu entry - * @return string id or empty string - * - * This function returns the id of the active navigation entry (set by - * setActiveEntry - */ - public function getActiveEntry() { - return $this->activeEntry; - } -} diff --git a/lib/notsquareexception.php b/lib/notsquareexception.php deleted file mode 100644 index 03dba8fb25f..00000000000 --- a/lib/notsquareexception.php +++ /dev/null @@ -1,12 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC; - -class NotSquareException extends \Exception { -} diff --git a/lib/ocs.php b/lib/ocs.php deleted file mode 100644 index 93e8931ce2e..00000000000 --- a/lib/ocs.php +++ /dev/null @@ -1,263 +0,0 @@ -. -* -*/ - -use Symfony\Component\Routing\Exception\ResourceNotFoundException; -use Symfony\Component\Routing\Exception\MethodNotAllowedException; - -/** - * Class to handle open collaboration services API requests - * - */ -class OC_OCS { - - /** - * reads input date from get/post/cookies and converts the date to a special data-type - * - * @param string HTTP method to read the key from - * @param string Parameter to read - * @param string Variable type to format data - * @param mixed Default value to return if the key is not found - * @return mixed Data or if the key is not found and no default is set it will exit with a 400 Bad request - */ - public static function readData($method, $key, $type = 'raw', $default = null) { - if ($method == 'get') { - if (isset($_GET[$key])) { - $data = $_GET[$key]; - } else if (isset($default)) { - return $default; - } else { - $data = false; - } - } else if ($method == 'post') { - if (isset($_POST[$key])) { - $data = $_POST[$key]; - } else if (isset($default)) { - return $default; - } else { - $data = false; - } - } - if ($data === false) { - echo self::generateXml('', 'fail', 400, 'Bad request. Please provide a valid '.$key); - exit(); - } else { - // NOTE: Is the raw type necessary? It might be a little risky without sanitization - if ($type == 'raw') return $data; - elseif ($type == 'text') return OC_Util::sanitizeHTML($data); - elseif ($type == 'int') return (int) $data; - elseif ($type == 'float') return (float) $data; - elseif ($type == 'array') return OC_Util::sanitizeHTML($data); - else return OC_Util::sanitizeHTML($data); - } - } - - public static function notFound() { - if($_SERVER['REQUEST_METHOD'] == 'GET') { - $method='get'; - }elseif($_SERVER['REQUEST_METHOD'] == 'PUT') { - $method='put'; - parse_str(file_get_contents("php://input"), $put_vars); - }elseif($_SERVER['REQUEST_METHOD'] == 'POST') { - $method='post'; - }else{ - echo('internal server error: method not supported'); - exit(); - } - - $format = self::readData($method, 'format', 'text', ''); - $txt='Invalid query, please check the syntax. API specifications are here:' - .' http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n"; - $txt.=OC_OCS::getDebugOutput(); - echo(OC_OCS::generateXml($format, 'failed', 999, $txt)); - - } - - /** - * generated some debug information to make it easier to find faild API calls - * @return debug data string - */ - private static function getDebugOutput() { - $txt=''; - $txt.="debug output:\n"; - if(isset($_SERVER['REQUEST_METHOD'])) $txt.='http request method: '.$_SERVER['REQUEST_METHOD']."\n"; - if(isset($_SERVER['REQUEST_URI'])) $txt.='http request uri: '.$_SERVER['REQUEST_URI']."\n"; - if(isset($_GET)) foreach($_GET as $key=>$value) $txt.='get parameter: '.$key.'->'.$value."\n"; - if(isset($_POST)) foreach($_POST as $key=>$value) $txt.='post parameter: '.$key.'->'.$value."\n"; - return($txt); - } - - - /** - * generates the xml or json response for the API call from an multidimenional data array. - * @param string $format - * @param string $status - * @param string $statuscode - * @param string $message - * @param array $data - * @param string $tag - * @param string $tagattribute - * @param int $dimension - * @param int $itemscount - * @param int $itemsperpage - * @return string xml/json - */ - private static function generateXml($format, $status, $statuscode, - $message, $data=array(), $tag='', $tagattribute='', $dimension=-1, $itemscount='', $itemsperpage='') { - if($format=='json') { - $json=array(); - $json['status']=$status; - $json['statuscode']=$statuscode; - $json['message']=$message; - $json['totalitems']=$itemscount; - $json['itemsperpage']=$itemsperpage; - $json['data']=$data; - return(json_encode($json)); - }else{ - $txt=''; - $writer = xmlwriter_open_memory(); - xmlwriter_set_indent( $writer, 2 ); - xmlwriter_start_document($writer ); - xmlwriter_start_element($writer, 'ocs'); - xmlwriter_start_element($writer, 'meta'); - xmlwriter_write_element($writer, 'status', $status); - xmlwriter_write_element($writer, 'statuscode', $statuscode); - xmlwriter_write_element($writer, 'message', $message); - if($itemscount<>'') xmlwriter_write_element($writer, 'totalitems', $itemscount); - if(!empty($itemsperpage)) xmlwriter_write_element($writer, 'itemsperpage', $itemsperpage); - xmlwriter_end_element($writer); - if($dimension=='0') { - // 0 dimensions - xmlwriter_write_element($writer, 'data', $data); - - }elseif($dimension=='1') { - xmlwriter_start_element($writer, 'data'); - foreach($data as $key=>$entry) { - xmlwriter_write_element($writer, $key, $entry); - } - xmlwriter_end_element($writer); - - }elseif($dimension=='2') { - xmlwriter_start_element($writer, 'data'); - foreach($data as $entry) { - xmlwriter_start_element($writer, $tag); - if(!empty($tagattribute)) { - xmlwriter_write_attribute($writer, 'details', $tagattribute); - } - foreach($entry as $key=>$value) { - if(is_array($value)) { - foreach($value as $k=>$v) { - xmlwriter_write_element($writer, $k, $v); - } - } else { - xmlwriter_write_element($writer, $key, $value); - } - } - xmlwriter_end_element($writer); - } - xmlwriter_end_element($writer); - - }elseif($dimension=='3') { - xmlwriter_start_element($writer, 'data'); - foreach($data as $entrykey=>$entry) { - xmlwriter_start_element($writer, $tag); - if(!empty($tagattribute)) { - xmlwriter_write_attribute($writer, 'details', $tagattribute); - } - foreach($entry as $key=>$value) { - if(is_array($value)) { - xmlwriter_start_element($writer, $entrykey); - foreach($value as $k=>$v) { - xmlwriter_write_element($writer, $k, $v); - } - xmlwriter_end_element($writer); - } else { - xmlwriter_write_element($writer, $key, $value); - } - } - xmlwriter_end_element($writer); - } - xmlwriter_end_element($writer); - }elseif($dimension=='dynamic') { - xmlwriter_start_element($writer, 'data'); - OC_OCS::toxml($writer, $data, 'comment'); - xmlwriter_end_element($writer); - } - - xmlwriter_end_element($writer); - - xmlwriter_end_document( $writer ); - $txt.=xmlwriter_output_memory( $writer ); - unset($writer); - return($txt); - } - } - - public static function toXml($writer, $data, $node) { - foreach($data as $key => $value) { - if (is_numeric($key)) { - $key = $node; - } - if (is_array($value)) { - xmlwriter_start_element($writer, $key); - OC_OCS::toxml($writer, $value, $node); - xmlwriter_end_element($writer); - }else{ - xmlwriter_write_element($writer, $key, $value); - } - } - } - - /** - * get private data - * @param string $user - * @param string $app - * @param string $key - * @param bool $like use LIKE instead of = when comparing keys - * @return array - */ - public static function getData($user, $app="", $key="") { - if($app) { - $apps=array($app); - }else{ - $apps=OC_Preferences::getApps($user); - } - if($key) { - $keys=array($key); - }else{ - foreach($apps as $app) { - $keys=OC_Preferences::getKeys($user, $app); - } - } - $result=array(); - foreach($apps as $app) { - foreach($keys as $key) { - $value=OC_Preferences::getValue($user, $app, $key); - $result[]=array('app'=>$app, 'key'=>$key, 'value'=>$value); - } - } - return $result; - } - -} diff --git a/lib/ocs/cloud.php b/lib/ocs/cloud.php deleted file mode 100644 index 2dd99319057..00000000000 --- a/lib/ocs/cloud.php +++ /dev/null @@ -1,108 +0,0 @@ -. -* -*/ - -class OC_OCS_Cloud { - - public static function getCapabilities($parameters) { - $result = array(); - list($major, $minor, $micro) = OC_Util::getVersion(); - $result['version'] = array( - 'major' => $major, - 'minor' => $minor, - 'micro' => $micro, - 'string' => OC_Util::getVersionString(), - 'edition' => OC_Util::getEditionString(), - ); - - $result['capabilities'] = array( - 'core' => array( - 'pollinterval' => OC_Config::getValue('pollinterval', 60), - ), - ); - - return new OC_OCS_Result($result); - } - - /** - * gets user info - * - * exposes the quota of an user: - * - * - * 1234 - * 4321 - * 5555 - * 0.78 - * - * - * - * @param $parameters object should contain parameter 'userid' which identifies - * the user from whom the information will be returned - */ - public static function getUser($parameters) { - // Check if they are viewing information on themselves - if($parameters['userid'] === OC_User::getUser()) { - // Self lookup - $quota = array(); - $storage = OC_Helper::getStorageInfo(); - $quota = array( - 'free' => $storage['free'], - 'used' => $storage['used'], - 'total' => $storage['total'], - 'relative' => $storage['relative'], - ); - return new OC_OCS_Result(array('quota' => $quota)); - } else { - // No permission to view this user data - return new OC_OCS_Result(null, 997); - } - } - - public static function getUserPublickey($parameters) { - - if(OC_User::userExists($parameters['user'])) { - // calculate the disc space - // TODO - return new OC_OCS_Result(array()); - } else { - return new OC_OCS_Result(null, 300); - } - } - - public static function getUserPrivatekey($parameters) { - $user = OC_User::getUser(); - if(OC_User::isAdminUser($user) or ($user==$parameters['user'])) { - - if(OC_User::userExists($user)) { - // calculate the disc space - $txt = 'this is the private key of '.$parameters['user']; - echo($txt); - } else { - return new OC_OCS_Result(null, 300, 'User does not exist'); - } - } else { - return new OC_OCS_Result('null', 300, 'You don´t have permission to access this ressource.'); - } - } -} diff --git a/lib/ocs/config.php b/lib/ocs/config.php deleted file mode 100644 index f19121f4b2b..00000000000 --- a/lib/ocs/config.php +++ /dev/null @@ -1,36 +0,0 @@ -. -* -*/ - -class OC_OCS_Config { - - public static function apiConfig($parameters) { - $xml['version'] = '1.7'; - $xml['website'] = 'ownCloud'; - $xml['host'] = OCP\Util::getServerHost(); - $xml['contact'] = ''; - $xml['ssl'] = 'false'; - return new OC_OCS_Result($xml); - } - -} diff --git a/lib/ocs/person.php b/lib/ocs/person.php deleted file mode 100644 index 1c8210d0825..00000000000 --- a/lib/ocs/person.php +++ /dev/null @@ -1,42 +0,0 @@ -. -* -*/ - -class OC_OCS_Person { - - public static function check($parameters) { - $login = isset($_POST['login']) ? $_POST['login'] : false; - $password = isset($_POST['password']) ? $_POST['password'] : false; - if($login && $password) { - if(OC_User::checkPassword($login, $password)) { - $xml['person']['personid'] = $login; - return new OC_OCS_Result($xml); - } else { - return new OC_OCS_Result(null, 102); - } - } else { - return new OC_OCS_Result(null, 101); - } - } - -} diff --git a/lib/ocs/privatedata.php b/lib/ocs/privatedata.php deleted file mode 100644 index 4dfd0a6e66e..00000000000 --- a/lib/ocs/privatedata.php +++ /dev/null @@ -1,66 +0,0 @@ -. -* -*/ - -class OC_OCS_Privatedata { - - public static function get($parameters) { - OC_Util::checkLoggedIn(); - $user = OC_User::getUser(); - $app = addslashes(strip_tags($parameters['app'])); - $key = addslashes(strip_tags($parameters['key'])); - $result = OC_OCS::getData($user, $app, $key); - $xml = array(); - foreach($result as $i=>$log) { - $xml[$i]['key']=$log['key']; - $xml[$i]['app']=$log['app']; - $xml[$i]['value']=$log['value']; - } - return new OC_OCS_Result($xml); - //TODO: replace 'privatedata' with 'attribute' once a new libattice has been released that works with it - } - - public static function set($parameters) { - OC_Util::checkLoggedIn(); - $user = OC_User::getUser(); - $app = addslashes(strip_tags($parameters['app'])); - $key = addslashes(strip_tags($parameters['key'])); - $value = OC_OCS::readData('post', 'value', 'text'); - if(OC_Preferences::setValue($user, $app, $key, $value)) { - return new OC_OCS_Result(null, 100); - } - } - - public static function delete($parameters) { - OC_Util::checkLoggedIn(); - $user = OC_User::getUser(); - $app = addslashes(strip_tags($parameters['app'])); - $key = addslashes(strip_tags($parameters['key'])); - if($key==="" or $app==="") { - return new OC_OCS_Result(null, 101); //key and app are NOT optional here - } - if(OC_Preferences::deleteKey($user, $app, $key)) { - return new OC_OCS_Result(null, 100); - } - } -} diff --git a/lib/ocs/result.php b/lib/ocs/result.php deleted file mode 100644 index 84f06fa01c7..00000000000 --- a/lib/ocs/result.php +++ /dev/null @@ -1,97 +0,0 @@ -. -* -*/ - -class OC_OCS_Result{ - - protected $data, $message, $statusCode, $items, $perPage; - - /** - * create the OCS_Result object - * @param $data mixed the data to return - */ - public function __construct($data=null, $code=100, $message=null) { - $this->data = $data; - $this->statusCode = $code; - $this->message = $message; - } - - /** - * optionally set the total number of items available - * @param $items int - */ - public function setTotalItems(int $items) { - $this->items = $items; - } - - /** - * optionally set the the number of items per page - * @param $items int - */ - public function setItemsPerPage(int $items) { - $this->perPage = $items; - } - - /** - * get the status code - * @return int - */ - public function getStatusCode() { - return $this->statusCode; - } - - /** - * get the meta data for the result - * @return array - */ - public function getMeta() { - $meta = array(); - $meta['status'] = ($this->statusCode === 100) ? 'ok' : 'failure'; - $meta['statuscode'] = $this->statusCode; - $meta['message'] = $this->message; - if(isset($this->items)) { - $meta['totalitems'] = $this->items; - } - if(isset($this->perPage)) { - $meta['itemsperpage'] = $this->perPage; - } - return $meta; - - } - - /** - * get the result data - * @return array|string|int - */ - public function getData() { - return $this->data; - } - - /** - * return bool if the method succedded - * @return bool - */ - public function succeeded() { - return (substr($this->statusCode, 0, 1) === '1'); - } - - -} diff --git a/lib/ocsclient.php b/lib/ocsclient.php deleted file mode 100644 index 58636f806be..00000000000 --- a/lib/ocsclient.php +++ /dev/null @@ -1,208 +0,0 @@ -. - * - */ - -/** - * This class provides an easy way for apps to store config values in the - * database. - */ - -class OC_OCSClient{ - - /** - * @brief Get the url of the OCS AppStore server. - * @returns string of the AppStore server - * - * This function returns the url of the OCS AppStore server. It´s possible - * to set it in the config file or it will fallback to the default - */ - private static function getAppStoreURL() { - $url = OC_Config::getValue('appstoreurl', 'http://api.apps.owncloud.com/v1'); - return($url); - } - - - /** - * @brief Get the content of an OCS url call. - * @returns string of the response - * This function calls an OCS server and returns the response. It also sets a sane timeout - */ - private static function getOCSresponse($url) { - $data = \OC_Util::getUrlContent($url); - return($data); - } - - /** - * @brief Get all the categories from the OCS server - * @returns array with category ids - * @note returns NULL if config value appstoreenabled is set to false - * This function returns a list of all the application categories on the OCS server - */ - public static function getCategories() { - if(OC_Config::getValue('appstoreenabled', true)==false) { - return null; - } - $url=OC_OCSClient::getAppStoreURL().'/content/categories'; - $xml=OC_OCSClient::getOCSresponse($url); - if($xml==false) { - return null; - } - $data=simplexml_load_string($xml); - - $tmp=$data->data; - $cats=array(); - - foreach($tmp->category as $value) { - - $id= (int) $value->id; - $name= (string) $value->name; - $cats[$id]=$name; - - } - - return $cats; - } - - /** - * @brief Get all the applications from the OCS server - * @returns array with application data - * - * This function returns a list of all the applications on the OCS server - */ - public static function getApplications($categories, $page, $filter) { - if(OC_Config::getValue('appstoreenabled', true)==false) { - return(array()); - } - - if(is_array($categories)) { - $categoriesstring=implode('x', $categories); - }else{ - $categoriesstring=$categories; - } - - $version='&version='.implode('x', \OC_Util::getVersion()); - $filterurl='&filter='.urlencode($filter); - $url=OC_OCSClient::getAppStoreURL().'/content/data?categories='.urlencode($categoriesstring) - .'&sortmode=new&page='.urlencode($page).'&pagesize=100'.$filterurl.$version; - $apps=array(); - $xml=OC_OCSClient::getOCSresponse($url); - - if($xml==false) { - return null; - } - $data=simplexml_load_string($xml); - - $tmp=$data->data->content; - for($i = 0; $i < count($tmp); $i++) { - $app=array(); - $app['id']=(string)$tmp[$i]->id; - $app['name']=(string)$tmp[$i]->name; - $app['label']=(string)$tmp[$i]->label; - $app['version']=(string)$tmp[$i]->version; - $app['type']=(string)$tmp[$i]->typeid; - $app['typename']=(string)$tmp[$i]->typename; - $app['personid']=(string)$tmp[$i]->personid; - $app['license']=(string)$tmp[$i]->license; - $app['detailpage']=(string)$tmp[$i]->detailpage; - $app['preview']=(string)$tmp[$i]->smallpreviewpic1; - $app['changed']=strtotime($tmp[$i]->changed); - $app['description']=(string)$tmp[$i]->description; - $app['score']=(string)$tmp[$i]->score; - - $apps[]=$app; - } - return $apps; - } - - - /** - * @brief Get an the applications from the OCS server - * @returns array with application data - * - * This function returns an applications from the OCS server - */ - public static function getApplication($id) { - if(OC_Config::getValue('appstoreenabled', true)==false) { - return null; - } - $url=OC_OCSClient::getAppStoreURL().'/content/data/'.urlencode($id); - $xml=OC_OCSClient::getOCSresponse($url); - - if($xml==false) { - OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); - return null; - } - $data=simplexml_load_string($xml); - - $tmp=$data->data->content; - $app=array(); - $app['id']=$tmp->id; - $app['name']=$tmp->name; - $app['version']=$tmp->version; - $app['type']=$tmp->typeid; - $app['label']=$tmp->label; - $app['typename']=$tmp->typename; - $app['personid']=$tmp->personid; - $app['detailpage']=$tmp->detailpage; - $app['preview1']=$tmp->smallpreviewpic1; - $app['preview2']=$tmp->smallpreviewpic2; - $app['preview3']=$tmp->smallpreviewpic3; - $app['changed']=strtotime($tmp->changed); - $app['description']=$tmp->description; - $app['detailpage']=$tmp->detailpage; - $app['score']=$tmp->score; - - return $app; - } - - /** - * @brief Get the download url for an application from the OCS server - * @returns array with application data - * - * This function returns an download url for an applications from the OCS server - */ - public static function getApplicationDownload($id, $item) { - if(OC_Config::getValue('appstoreenabled', true)==false) { - return null; - } - $url=OC_OCSClient::getAppStoreURL().'/content/download/'.urlencode($id).'/'.urlencode($item); - $xml=OC_OCSClient::getOCSresponse($url); - - if($xml==false) { - OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); - return null; - } - $data=simplexml_load_string($xml); - - $tmp=$data->data->content; - $app=array(); - if(isset($tmp->downloadlink)) { - $app['downloadlink']=$tmp->downloadlink; - }else{ - $app['downloadlink']=''; - } - return $app; - } - - - -} diff --git a/lib/preferences.php b/lib/preferences.php deleted file mode 100644 index 359d9a83589..00000000000 --- a/lib/preferences.php +++ /dev/null @@ -1,232 +0,0 @@ -. - * - */ -/* - * - * The following SQL statement is just a help for developers and will not be - * executed! - * - * CREATE TABLE `preferences` ( - * `userid` VARCHAR( 255 ) NOT NULL , - * `appid` VARCHAR( 255 ) NOT NULL , - * `configkey` VARCHAR( 255 ) NOT NULL , - * `configvalue` VARCHAR( 255 ) NOT NULL - * ) - * - */ - -namespace OC; - -use \OC\DB\Connection; - - -/** - * This class provides an easy way for storing user preferences. - */ -class Preferences { - protected $conn; - - public function __construct(Connection $conn) { - $this->conn = $conn; - } - - /** - * @brief Get all users using the preferences - * @return array with user ids - * - * This function returns a list of all users that have at least one entry - * in the preferences table. - */ - public function getUsers() { - $query = 'SELECT DISTINCT `userid` FROM `*PREFIX*preferences`'; - $result = $this->conn->executeQuery( $query ); - - $users = array(); - while( $userid = $result->fetchColumn()) { - $users[] = $userid; - } - - return $users; - } - - /** - * @brief Get all apps of an user - * @param string $user user - * @return array with app ids - * - * This function returns a list of all apps of the user that have at least - * one entry in the preferences table. - */ - public function getApps( $user ) { - $query = 'SELECT DISTINCT `appid` FROM `*PREFIX*preferences` WHERE `userid` = ?'; - $result = $this->conn->executeQuery( $query, array( $user ) ); - - $apps = array(); - while( $appid = $result->fetchColumn()) { - $apps[] = $appid; - } - - return $apps; - } - - /** - * @brief Get the available keys for an app - * @param string $user user - * @param string $app the app we are looking for - * @return array with key names - * - * This function gets all keys of an app of an user. Please note that the - * values are not returned. - */ - public function getKeys( $user, $app ) { - $query = 'SELECT `configkey` FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ?'; - $result = $this->conn->executeQuery( $query, array( $user, $app )); - - $keys = array(); - while( $key = $result->fetchColumn()) { - $keys[] = $key; - } - - return $keys; - } - - /** - * @brief Gets the preference - * @param string $user user - * @param string $app app - * @param string $key key - * @param string $default = null, default value if the key does not exist - * @return string the value or $default - * - * This function gets a value from the preferences table. If the key does - * not exist the default value will be returned - */ - public function getValue( $user, $app, $key, $default = null ) { - // Try to fetch the value, return default if not exists. - $query = 'SELECT `configvalue` FROM `*PREFIX*preferences`' - .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?'; - $row = $this->conn->fetchAssoc( $query, array( $user, $app, $key )); - if($row) { - return $row["configvalue"]; - } else { - return $default; - } - } - - /** - * @brief sets a value in the preferences - * @param string $user user - * @param string $app app - * @param string $key key - * @param string $value value - * - * Adds a value to the preferences. If the key did not exist before, it - * will be added automagically. - */ - public function setValue( $user, $app, $key, $value ) { - // Check if the key does exist - $query = 'SELECT COUNT(*) FROM `*PREFIX*preferences`' - .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?'; - $count = $this->conn->fetchColumn( $query, array( $user, $app, $key )); - $exists = $count > 0; - - if( !$exists ) { - $data = array( - 'userid' => $user, - 'appid' => $app, - 'configkey' => $key, - 'configvalue' => $value, - ); - $this->conn->insert('*PREFIX*preferences', $data); - } else { - $data = array( - 'configvalue' => $value, - ); - $where = array( - 'userid' => $user, - 'appid' => $app, - 'configkey' => $key, - ); - $this->conn->update('*PREFIX*preferences', $data, $where); - } - } - - /** - * @brief Deletes a key - * @param string $user user - * @param string $app app - * @param string $key key - * - * Deletes a key. - */ - public function deleteKey( $user, $app, $key ) { - $where = array( - 'userid' => $user, - 'appid' => $app, - 'configkey' => $key, - ); - $this->conn->delete('*PREFIX*preferences', $where); - } - - /** - * @brief Remove app of user from preferences - * @param string $user user - * @param string $app app - * - * Removes all keys in preferences belonging to the app and the user. - */ - public function deleteApp( $user, $app ) { - $where = array( - 'userid' => $user, - 'appid' => $app, - ); - $this->conn->delete('*PREFIX*preferences', $where); - } - - /** - * @brief Remove user from preferences - * @param string $user user - * - * Removes all keys in preferences belonging to the user. - */ - public function deleteUser( $user ) { - $where = array( - 'userid' => $user, - ); - $this->conn->delete('*PREFIX*preferences', $where); - } - - /** - * @brief Remove app from all users - * @param string $app app - * - * Removes all keys in preferences belonging to the app. - */ - public function deleteAppFromAllUsers( $app ) { - $where = array( - 'appid' => $app, - ); - $this->conn->delete('*PREFIX*preferences', $where); - } -} - -require_once __DIR__.'/legacy/'.basename(__FILE__); diff --git a/lib/preview.php b/lib/preview.php deleted file mode 100755 index 266f7795f12..00000000000 --- a/lib/preview.php +++ /dev/null @@ -1,630 +0,0 @@ -configMaxX = \OC_Config::getValue('preview_max_x', null); - $this->configMaxY = \OC_Config::getValue('preview_max_y', null); - $this->maxScaleFactor = \OC_Config::getValue('preview_max_scale_factor', 2); - - //save parameters - $this->setFile($file); - $this->setMaxX($maxX); - $this->setMaxY($maxY); - $this->setScalingUp($scalingUp); - - //init fileviews - if($user === ''){ - $user = \OC_User::getUser(); - } - $this->fileView = new \OC\Files\View('/' . $user . '/' . $root); - $this->userView = new \OC\Files\View('/' . $user); - - $this->preview = null; - - //check if there are preview backends - if(empty(self::$providers)) { - self::initProviders(); - } - - if(empty(self::$providers)) { - \OC_Log::write('core', 'No preview providers exist', \OC_Log::ERROR); - throw new \Exception('No preview providers'); - } - } - - /** - * @brief returns the path of the file you want a thumbnail from - * @return string - */ - public function getFile() { - return $this->file; - } - - /** - * @brief returns the max width of the preview - * @return integer - */ - public function getMaxX() { - return $this->maxX; - } - - /** - * @brief returns the max height of the preview - * @return integer - */ - public function getMaxY() { - return $this->maxY; - } - - /** - * @brief returns whether or not scalingup is enabled - * @return bool - */ - public function getScalingUp() { - return $this->scalingup; - } - - /** - * @brief returns the name of the thumbnailfolder - * @return string - */ - public function getThumbnailsFolder() { - return self::THUMBNAILS_FOLDER; - } - - /** - * @brief returns the max scale factor - * @return integer - */ - public function getMaxScaleFactor() { - return $this->maxScaleFactor; - } - - /** - * @brief returns the max width set in ownCloud's config - * @return integer - */ - public function getConfigMaxX() { - return $this->configMaxX; - } - - /** - * @brief returns the max height set in ownCloud's config - * @return integer - */ - public function getConfigMaxY() { - return $this->configMaxY; - } - - /** - * @brief set the path of the file you want a thumbnail from - * @param string $file - * @return $this - */ - public function setFile($file) { - $this->file = $file; - return $this; - } - - /** - * @brief set the the max width of the preview - * @param int $maxX - * @return $this - */ - public function setMaxX($maxX=1) { - if($maxX <= 0) { - throw new \Exception('Cannot set width of 0 or smaller!'); - } - $configMaxX = $this->getConfigMaxX(); - if(!is_null($configMaxX)) { - if($maxX > $configMaxX) { - \OC_Log::write('core', 'maxX reduced from ' . $maxX . ' to ' . $configMaxX, \OC_Log::DEBUG); - $maxX = $configMaxX; - } - } - $this->maxX = $maxX; - return $this; - } - - /** - * @brief set the the max height of the preview - * @param int $maxY - * @return $this - */ - public function setMaxY($maxY=1) { - if($maxY <= 0) { - throw new \Exception('Cannot set height of 0 or smaller!'); - } - $configMaxY = $this->getConfigMaxY(); - if(!is_null($configMaxY)) { - if($maxY > $configMaxY) { - \OC_Log::write('core', 'maxX reduced from ' . $maxY . ' to ' . $configMaxY, \OC_Log::DEBUG); - $maxY = $configMaxY; - } - } - $this->maxY = $maxY; - return $this; - } - - /** - * @brief set whether or not scalingup is enabled - * @param bool $scalingUp - * @return $this - */ - public function setScalingup($scalingUp) { - if($this->getMaxScaleFactor() === 1) { - $scalingUp = false; - } - $this->scalingup = $scalingUp; - return $this; - } - - /** - * @brief check if all parameters are valid - * @return bool - */ - public function isFileValid() { - $file = $this->getFile(); - if($file === '') { - \OC_Log::write('core', 'No filename passed', \OC_Log::DEBUG); - return false; - } - - if(!$this->fileView->file_exists($file)) { - \OC_Log::write('core', 'File:"' . $file . '" not found', \OC_Log::DEBUG); - return false; - } - - return true; - } - - /** - * @brief deletes previews of a file with specific x and y - * @return bool - */ - public function deletePreview() { - $file = $this->getFile(); - - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; - - $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/' . $this->getMaxX() . '-' . $this->getMaxY() . '.png'; - $this->userView->unlink($previewPath); - return !$this->userView->file_exists($previewPath); - } - - /** - * @brief deletes all previews of a file - * @return bool - */ - public function deleteAllPreviews() { - $file = $this->getFile(); - - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; - - $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; - $this->userView->deleteAll($previewPath); - $this->userView->rmdir($previewPath); - return !$this->userView->is_dir($previewPath); - } - - /** - * @brief check if thumbnail or bigger version of thumbnail of file is cached - * @return mixed (bool / string) - * false if thumbnail does not exist - * path to thumbnail if thumbnail exists - */ - private function isCached() { - $file = $this->getFile(); - $maxX = $this->getMaxX(); - $maxY = $this->getMaxY(); - $scalingUp = $this->getScalingUp(); - $maxScaleFactor = $this->getMaxScaleFactor(); - - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; - - if(is_null($fileId)) { - return false; - } - - $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; - if(!$this->userView->is_dir($previewPath)) { - return false; - } - - //does a preview with the wanted height and width already exist? - if($this->userView->file_exists($previewPath . $maxX . '-' . $maxY . '.png')) { - return $previewPath . $maxX . '-' . $maxY . '.png'; - } - - $wantedAspectRatio = (float) ($maxX / $maxY); - - //array for usable cached thumbnails - $possibleThumbnails = array(); - - $allThumbnails = $this->userView->getDirectoryContent($previewPath); - foreach($allThumbnails as $thumbnail) { - $name = rtrim($thumbnail['name'], '.png'); - $size = explode('-', $name); - $x = (int) $size[0]; - $y = (int) $size[1]; - - $aspectRatio = (float) ($x / $y); - if($aspectRatio !== $wantedAspectRatio) { - continue; - } - - if($x < $maxX || $y < $maxY) { - if($scalingUp) { - $scalefactor = $maxX / $x; - if($scalefactor > $maxScaleFactor) { - continue; - } - }else{ - continue; - } - } - $possibleThumbnails[$x] = $thumbnail['path']; - } - - if(count($possibleThumbnails) === 0) { - return false; - } - - if(count($possibleThumbnails) === 1) { - return current($possibleThumbnails); - } - - ksort($possibleThumbnails); - - if(key(reset($possibleThumbnails)) > $maxX) { - return current(reset($possibleThumbnails)); - } - - if(key(end($possibleThumbnails)) < $maxX) { - return current(end($possibleThumbnails)); - } - - foreach($possibleThumbnails as $width => $path) { - if($width < $maxX) { - continue; - }else{ - return $path; - } - } - } - - /** - * @brief return a preview of a file - * @return \OC_Image - */ - public function getPreview() { - if(!is_null($this->preview) && $this->preview->valid()){ - return $this->preview; - } - - $this->preview = null; - $file = $this->getFile(); - $maxX = $this->getMaxX(); - $maxY = $this->getMaxY(); - $scalingUp = $this->getScalingUp(); - - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; - - $cached = $this->isCached(); - - if($cached) { - $image = new \OC_Image($this->userView->file_get_contents($cached, 'r')); - $this->preview = $image->valid() ? $image : null; - $this->resizeAndCrop(); - } - - if(is_null($this->preview)) { - $mimetype = $this->fileView->getMimeType($file); - $preview = null; - - foreach(self::$providers as $supportedMimetype => $provider) { - if(!preg_match($supportedMimetype, $mimetype)) { - continue; - } - - \OC_Log::write('core', 'Generating preview for "' . $file . '" with "' . get_class($provider) . '"', \OC_Log::DEBUG); - - $preview = $provider->getThumbnail($file, $maxX, $maxY, $scalingUp, $this->fileView); - - if(!($preview instanceof \OC_Image)) { - continue; - } - - $this->preview = $preview; - $this->resizeAndCrop(); - - $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; - $cachePath = $previewPath . $maxX . '-' . $maxY . '.png'; - - if($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) { - $this->userView->mkdir($this->getThumbnailsFolder() . '/'); - } - - if($this->userView->is_dir($previewPath) === false) { - $this->userView->mkdir($previewPath); - } - - $this->userView->file_put_contents($cachePath, $preview->data()); - - break; - } - } - - if(is_null($this->preview)) { - $this->preview = new \OC_Image(); - } - - return $this->preview; - } - - /** - * @brief show preview - * @return void - */ - public function showPreview() { - \OCP\Response::enableCaching(3600 * 24); // 24 hours - if(is_null($this->preview)) { - $this->getPreview(); - } - $this->preview->show(); - return; - } - - /** - * @brief show preview - * @return void - */ - public function show() { - $this->showPreview(); - return; - } - - /** - * @brief resize, crop and fix orientation - * @return void - */ - private function resizeAndCrop() { - $image = $this->preview; - $x = $this->getMaxX(); - $y = $this->getMaxY(); - $scalingUp = $this->getScalingUp(); - $maxscalefactor = $this->getMaxScaleFactor(); - - if(!($image instanceof \OC_Image)) { - \OC_Log::write('core', '$this->preview is not an instance of OC_Image', \OC_Log::DEBUG); - return; - } - - $image->fixOrientation(); - - $realx = (int) $image->width(); - $realy = (int) $image->height(); - - if($x === $realx && $y === $realy) { - $this->preview = $image; - return; - } - - $factorX = $x / $realx; - $factorY = $y / $realy; - - if($factorX >= $factorY) { - $factor = $factorX; - }else{ - $factor = $factorY; - } - - if($scalingUp === false) { - if($factor > 1) { - $factor = 1; - } - } - - if(!is_null($maxscalefactor)) { - if($factor > $maxscalefactor) { - \OC_Log::write('core', 'scalefactor reduced from ' . $factor . ' to ' . $maxscalefactor, \OC_Log::DEBUG); - $factor = $maxscalefactor; - } - } - - $newXsize = (int) ($realx * $factor); - $newYsize = (int) ($realy * $factor); - - $image->preciseResize($newXsize, $newYsize); - - if($newXsize === $x && $newYsize === $y) { - $this->preview = $image; - return; - } - - if($newXsize >= $x && $newYsize >= $y) { - $cropX = floor(abs($x - $newXsize) * 0.5); - //don't crop previews on the Y axis, this sucks if it's a document. - //$cropY = floor(abs($y - $newYsize) * 0.5); - $cropY = 0; - - $image->crop($cropX, $cropY, $x, $y); - - $this->preview = $image; - return; - } - - if($newXsize < $x || $newYsize < $y) { - if($newXsize > $x) { - $cropX = floor(($newXsize - $x) * 0.5); - $image->crop($cropX, 0, $x, $newYsize); - } - - if($newYsize > $y) { - $cropY = floor(($newYsize - $y) * 0.5); - $image->crop(0, $cropY, $newXsize, $y); - } - - $newXsize = (int) $image->width(); - $newYsize = (int) $image->height(); - - //create transparent background layer - $backgroundlayer = imagecreatetruecolor($x, $y); - $white = imagecolorallocate($backgroundlayer, 255, 255, 255); - imagefill($backgroundlayer, 0, 0, $white); - - $image = $image->resource(); - - $mergeX = floor(abs($x - $newXsize) * 0.5); - $mergeY = floor(abs($y - $newYsize) * 0.5); - - imagecopy($backgroundlayer, $image, $mergeX, $mergeY, 0, 0, $newXsize, $newYsize); - - //$black = imagecolorallocate(0,0,0); - //imagecolortransparent($transparentlayer, $black); - - $image = new \OC_Image($backgroundlayer); - - $this->preview = $image; - return; - } - } - - /** - * @brief register a new preview provider to be used - * @param string $provider class name of a Preview_Provider - * @param array $options - * @return void - */ - public static function registerProvider($class, $options=array()) { - self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); - } - - /** - * @brief create instances of all the registered preview providers - * @return void - */ - private static function initProviders() { - if(!\OC_Config::getValue('enable_previews', true)) { - $provider = new Preview\Unknown(array()); - self::$providers = array($provider->getMimeType() => $provider); - return; - } - - if(count(self::$providers)>0) { - return; - } - - foreach(self::$registeredProviders as $provider) { - $class=$provider['class']; - $options=$provider['options']; - - $object = new $class($options); - - self::$providers[$object->getMimeType()] = $object; - } - - $keys = array_map('strlen', array_keys(self::$providers)); - array_multisort($keys, SORT_DESC, self::$providers); - } - - public static function post_write($args) { - self::post_delete($args); - } - - public static function post_delete($args) { - $path = $args['path']; - if(substr($path, 0, 1) === '/') { - $path = substr($path, 1); - } - $preview = new Preview(\OC_User::getUser(), 'files/', $path); - $preview->deleteAllPreviews(); - } - - public static function isMimeSupported($mimetype) { - if(!\OC_Config::getValue('enable_previews', true)) { - return false; - } - - //check if there are preview backends - if(empty(self::$providers)) { - self::initProviders(); - } - - //remove last element because it has the mimetype * - $providers = array_slice(self::$providers, 0, -1); - foreach($providers as $supportedMimetype => $provider) { - if(preg_match($supportedMimetype, $mimetype)) { - return true; - } - } - return false; - } -} diff --git a/lib/preview/image.php b/lib/preview/image.php deleted file mode 100644 index 9aec967282d..00000000000 --- a/lib/preview/image.php +++ /dev/null @@ -1,36 +0,0 @@ -getFileInfo($path); - if(!$fileInfo) { - return false; - } - - //check if file is encrypted - if($fileInfo['encrypted'] === true) { - $image = new \OC_Image(stream_get_contents($fileview->fopen($path, 'r'))); - }else{ - $image = new \OC_Image(); - $image->loadFromFile($fileview->getLocalFile($path)); - } - - return $image->valid() ? $image : false; - } -} - -\OC\Preview::registerProvider('OC\Preview\Image'); \ No newline at end of file diff --git a/lib/preview/movies.php b/lib/preview/movies.php deleted file mode 100644 index c318137ff0e..00000000000 --- a/lib/preview/movies.php +++ /dev/null @@ -1,47 +0,0 @@ -fopen($path, 'rb'); - - $firstmb = stream_get_contents($handle, 1048576); //1024 * 1024 = 1048576 - file_put_contents($absPath, $firstmb); - - //$cmd = 'ffmpeg -y -i ' . escapeshellarg($absPath) . ' -f mjpeg -vframes 1 -ss 1 -s ' . escapeshellarg($maxX) . 'x' . escapeshellarg($maxY) . ' ' . $tmpPath; - $cmd = 'avconv -an -y -ss 1 -i ' . escapeshellarg($absPath) . ' -f mjpeg -vframes 1 ' . escapeshellarg($tmpPath); - - shell_exec($cmd); - - $image = new \OC_Image($tmpPath); - - unlink($absPath); - unlink($tmpPath); - - return $image->valid() ? $image : false; - } - } - - \OC\Preview::registerProvider('OC\Preview\Movie'); -} \ No newline at end of file diff --git a/lib/preview/mp3.php b/lib/preview/mp3.php deleted file mode 100644 index 1eed566315c..00000000000 --- a/lib/preview/mp3.php +++ /dev/null @@ -1,48 +0,0 @@ -toTmpFile($path); - - $tags = $getID3->analyze($tmpPath); - \getid3_lib::CopyTagsToComments($tags); - if(isset($tags['id3v2']['APIC'][0]['data'])) { - $picture = @$tags['id3v2']['APIC'][0]['data']; - unlink($tmpPath); - $image = new \OC_Image($picture); - return $image->valid() ? $image : $this->getNoCoverThumbnail(); - } - - return $this->getNoCoverThumbnail(); - } - - private function getNoCoverThumbnail() { - $icon = \OC::$SERVERROOT . '/core/img/filetypes/audio.png'; - - if(!file_exists($icon)) { - return false; - } - - $image = new \OC_Image($icon); - return $image->valid() ? $image : false; - } - -} - -\OC\Preview::registerProvider('OC\Preview\MP3'); \ No newline at end of file diff --git a/lib/preview/office-cl.php b/lib/preview/office-cl.php deleted file mode 100644 index 112909d6523..00000000000 --- a/lib/preview/office-cl.php +++ /dev/null @@ -1,134 +0,0 @@ -initCmd(); - if(is_null($this->cmd)) { - return false; - } - - $absPath = $fileview->toTmpFile($path); - - $tmpDir = get_temp_dir(); - - $defaultParameters = ' --headless --nologo --nofirststartwizard --invisible --norestore -convert-to pdf -outdir '; - $clParameters = \OCP\Config::getSystemValue('preview_office_cl_parameters', $defaultParameters); - - $exec = $this->cmd . $clParameters . escapeshellarg($tmpDir) . ' ' . escapeshellarg($absPath); - $export = 'export HOME=/' . $tmpDir; - - shell_exec($export . "\n" . $exec); - - //create imagick object from pdf - try{ - $pdf = new \imagick($absPath . '.pdf' . '[0]'); - $pdf->setImageFormat('jpg'); - } catch (\Exception $e) { - unlink($absPath); - unlink($absPath . '.pdf'); - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; - } - - $image = new \OC_Image($pdf); - - unlink($absPath); - unlink($absPath . '.pdf'); - - return $image->valid() ? $image : false; - } - - private function initCmd() { - $cmd = ''; - - if(is_string(\OC_Config::getValue('preview_libreoffice_path', null))) { - $cmd = \OC_Config::getValue('preview_libreoffice_path', null); - } - - $whichLibreOffice = shell_exec('which libreoffice'); - if($cmd === '' && !empty($whichLibreOffice)) { - $cmd = 'libreoffice'; - } - - $whichOpenOffice = shell_exec('which openoffice'); - if($cmd === '' && !empty($whichOpenOffice)) { - $cmd = 'openoffice'; - } - - if($cmd === '') { - $cmd = null; - } - - $this->cmd = $cmd; - } -} - -//.doc, .dot -class MSOfficeDoc extends Office { - - public function getMimeType() { - return '/application\/msword/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\MSOfficeDoc'); - -//.docm, .dotm, .xls(m), .xlt(m), .xla(m), .ppt(m), .pot(m), .pps(m), .ppa(m) -class MSOffice2003 extends Office { - - public function getMimeType() { - return '/application\/vnd.ms-.*/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\MSOffice2003'); - -//.docx, .dotx, .xlsx, .xltx, .pptx, .potx, .ppsx -class MSOffice2007 extends Office { - - public function getMimeType() { - return '/application\/vnd.openxmlformats-officedocument.*/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\MSOffice2007'); - -//.odt, .ott, .oth, .odm, .odg, .otg, .odp, .otp, .ods, .ots, .odc, .odf, .odb, .odi, .oxt -class OpenDocument extends Office { - - public function getMimeType() { - return '/application\/vnd.oasis.opendocument.*/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\OpenDocument'); - -//.sxw, .stw, .sxc, .stc, .sxd, .std, .sxi, .sti, .sxg, .sxm -class StarOffice extends Office { - - public function getMimeType() { - return '/application\/vnd.sun.xml.*/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\StarOffice'); \ No newline at end of file diff --git a/lib/preview/office-fallback.php b/lib/preview/office-fallback.php deleted file mode 100644 index e69ab0ab8cb..00000000000 --- a/lib/preview/office-fallback.php +++ /dev/null @@ -1,142 +0,0 @@ -toTmpFile($path); - - $transformdoc = new \TransformDoc(); - $transformdoc->setStrFile($tmpDoc); - $transformdoc->generatePDF($tmpDoc); - - $pdf = new \imagick($tmpDoc . '[0]'); - $pdf->setImageFormat('jpg'); - - unlink($tmpDoc); - - $image = new \OC_Image($pdf); - - return $image->valid() ? $image : false; - } - -} - -\OC\Preview::registerProvider('OC\Preview\DOCX'); - -class MSOfficeExcel extends Provider { - - public function getMimeType() { - return null; - } - - public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - require_once('PHPExcel/Classes/PHPExcel.php'); - require_once('PHPExcel/Classes/PHPExcel/IOFactory.php'); - - $absPath = $fileview->toTmpFile($path); - $tmpPath = \OC_Helper::tmpFile(); - - $rendererName = \PHPExcel_Settings::PDF_RENDERER_DOMPDF; - $rendererLibraryPath = \OC::$THIRDPARTYROOT . '/3rdparty/dompdf'; - - \PHPExcel_Settings::setPdfRenderer($rendererName, $rendererLibraryPath); - - $phpexcel = new \PHPExcel($absPath); - $excel = \PHPExcel_IOFactory::createWriter($phpexcel, 'PDF'); - $excel->save($tmpPath); - - $pdf = new \imagick($tmpPath . '[0]'); - $pdf->setImageFormat('jpg'); - - unlink($absPath); - unlink($tmpPath); - - $image = new \OC_Image($pdf); - - return $image->valid() ? $image : false; - } - -} - -class XLS extends MSOfficeExcel { - - public function getMimeType() { - return '/application\/vnd.ms-excel/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\XLS'); - -class XLSX extends MSOfficeExcel { - - public function getMimeType() { - return '/application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\XLSX'); - -/* //There is no (good) php-only solution for converting powerpoint documents to pdfs / pngs ... -class MSOfficePowerPoint extends Provider { - - public function getMimeType() { - return null; - } - - public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - return false; - } - -} - -class PPT extends MSOfficePowerPoint { - - public function getMimeType() { - return '/application\/vnd.ms-powerpoint/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\PPT'); - -class PPTX extends MSOfficePowerPoint { - - public function getMimeType() { - return '/application\/vnd.openxmlformats-officedocument.presentationml.presentation/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\PPTX'); -*/ \ No newline at end of file diff --git a/lib/preview/office.php b/lib/preview/office.php deleted file mode 100644 index 5287bbd6ac1..00000000000 --- a/lib/preview/office.php +++ /dev/null @@ -1,22 +0,0 @@ -toTmpFile($path); - - //create imagick object from pdf - try{ - $pdf = new \imagick($tmpPath . '[0]'); - $pdf->setImageFormat('jpg'); - } catch (\Exception $e) { - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; - } - - unlink($tmpPath); - - //new image object - $image = new \OC_Image($pdf); - //check if image object is valid - return $image->valid() ? $image : false; - } - } - - \OC\Preview::registerProvider('OC\Preview\PDF'); -} diff --git a/lib/preview/provider.php b/lib/preview/provider.php deleted file mode 100644 index e4a730bafc8..00000000000 --- a/lib/preview/provider.php +++ /dev/null @@ -1,19 +0,0 @@ -options=$options; - } - - abstract public function getMimeType(); - - /** - * search for $query - * @param string $query - * @return - */ - abstract public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview); -} diff --git a/lib/preview/svg.php b/lib/preview/svg.php deleted file mode 100644 index b49e51720fa..00000000000 --- a/lib/preview/svg.php +++ /dev/null @@ -1,46 +0,0 @@ -setBackgroundColor(new \ImagickPixel('transparent')); - - $content = stream_get_contents($fileview->fopen($path, 'r')); - if(substr($content, 0, 5) !== '' . $content; - } - - $svg->readImageBlob($content); - $svg->setImageFormat('png32'); - } catch (\Exception $e) { - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; - } - - - //new image object - $image = new \OC_Image(); - $image->loadFromData($svg); - //check if image object is valid - return $image->valid() ? $image : false; - } - } - - \OC\Preview::registerProvider('OC\Preview\SVG'); - -} \ No newline at end of file diff --git a/lib/preview/txt.php b/lib/preview/txt.php deleted file mode 100644 index 77e728eb364..00000000000 --- a/lib/preview/txt.php +++ /dev/null @@ -1,83 +0,0 @@ -getMimeType($path); - if(in_array($mimetype, self::$blacklist)) { - return false; - } - - $content = $fileview->fopen($path, 'r'); - $content = stream_get_contents($content); - - //don't create previews of empty text files - if(trim($content) === '') { - return false; - } - - $lines = preg_split("/\r\n|\n|\r/", $content); - - $fontSize = 5; //5px - $lineSize = ceil($fontSize * 1.25); - - $image = imagecreate($maxX, $maxY); - imagecolorallocate($image, 255, 255, 255); - $textColor = imagecolorallocate($image, 0, 0, 0); - - foreach($lines as $index => $line) { - $index = $index + 1; - - $x = (int) 1; - $y = (int) ($index * $lineSize) - $fontSize; - - imagestring($image, 1, $x, $y, $line, $textColor); - - if(($index * $lineSize) >= $maxY) { - break; - } - } - - $image = new \OC_Image($image); - - return $image->valid() ? $image : false; - } -} - -\OC\Preview::registerProvider('OC\Preview\TXT'); - -class PHP extends TXT { - - public function getMimeType() { - return '/application\/x-php/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\PHP'); - -class JavaScript extends TXT { - - public function getMimeType() { - return '/application\/javascript/'; - } - -} - -\OC\Preview::registerProvider('OC\Preview\JavaScript'); \ No newline at end of file diff --git a/lib/preview/unknown.php b/lib/preview/unknown.php deleted file mode 100644 index 9e6cd68d401..00000000000 --- a/lib/preview/unknown.php +++ /dev/null @@ -1,27 +0,0 @@ -getMimeType($path); - - $path = \OC_Helper::mimetypeIcon($mimetype); - $path = \OC::$SERVERROOT . substr($path, strlen(\OC::$WEBROOT)); - - return new \OC_Image($path); - } -} - -\OC\Preview::registerProvider('OC\Preview\Unknown'); \ No newline at end of file diff --git a/lib/previewmanager.php b/lib/previewmanager.php deleted file mode 100755 index ac9a866a75b..00000000000 --- a/lib/previewmanager.php +++ /dev/null @@ -1,38 +0,0 @@ -getPreview(); - } - - /** - * @brief returns true if the passed mime type is supported - * @param string $mimeType - * @return boolean - */ - function isMimeSupported($mimeType = '*') - { - return \OC\Preview::isMimeSupported($mimeType); - } -} diff --git a/lib/private/allconfig.php b/lib/private/allconfig.php new file mode 100644 index 00000000000..72aabf60793 --- /dev/null +++ b/lib/private/allconfig.php @@ -0,0 +1,77 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OC; + +/** + * Class to combine all the configuration options ownCloud offers + */ +class AllConfig implements \OCP\IConfig { + /** + * Sets a new system wide value + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + * @todo need a use case for this + */ +// public function setSystemValue($key, $value) { +// \OCP\Config::setSystemValue($key, $value); +// } + + /** + * Looks up a system wide defined value + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getSystemValue($key) { + return \OCP\Config::getSystemValue($key, ''); + } + + + /** + * Writes a new app wide value + * @param string $appName the appName that we want to store the value under + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + */ + public function setAppValue($appName, $key, $value) { + \OCP\Config::setAppValue($appName, $key, $value); + } + + /** + * Looks up an app wide defined value + * @param string $appName the appName that we stored the value under + * @param string $key the key of the value, under which it was saved + * @return string the saved value + */ + public function getAppValue($appName, $key) { + return \OCP\Config::getAppValue($appName, $key, ''); + } + + + /** + * Set a user defined value + * @param string $userId the userId of the user that we want to store the value under + * @param string $appName the appName that we want to store the value under + * @param string $key the key under which the value is being stored + * @param string $value the value that you want to store + */ + public function setUserValue($userId, $appName, $key, $value) { + \OCP\Config::setUserValue($userId, $appName, $key, $value); + } + + /** + * Shortcut for getting a user defined value + * @param string $userId the userId of the user that we want to store the value under + * @param string $appName the appName that we stored the value under + * @param string $key the key under which the value is being stored + */ + public function getUserValue($userId, $appName, $key){ + return \OCP\Config::getUserValue($userId, $appName, $key); + } +} diff --git a/lib/private/api.php b/lib/private/api.php new file mode 100644 index 00000000000..31f3f968d9b --- /dev/null +++ b/lib/private/api.php @@ -0,0 +1,293 @@ +. +* +*/ + +class OC_API { + + /** + * API authentication levels + */ + const GUEST_AUTH = 0; + const USER_AUTH = 1; + const SUBADMIN_AUTH = 2; + const ADMIN_AUTH = 3; + + /** + * API Response Codes + */ + const RESPOND_UNAUTHORISED = 997; + const RESPOND_SERVER_ERROR = 996; + const RESPOND_NOT_FOUND = 998; + const RESPOND_UNKNOWN_ERROR = 999; + + /** + * api actions + */ + protected static $actions = array(); + + /** + * registers an api call + * @param string $method the http method + * @param string $url the url to match + * @param callable $action the function to run + * @param string $app the id of the app registering the call + * @param int $authLevel the level of authentication required for the call + * @param array $defaults + * @param array $requirements + */ + public static function register($method, $url, $action, $app, + $authLevel = OC_API::USER_AUTH, + $defaults = array(), + $requirements = array()) { + $name = strtolower($method).$url; + $name = str_replace(array('/', '{', '}'), '_', $name); + if(!isset(self::$actions[$name])) { + OC::getRouter()->useCollection('ocs'); + OC::getRouter()->create($name, $url) + ->method($method) + ->defaults($defaults) + ->requirements($requirements) + ->action('OC_API', 'call'); + self::$actions[$name] = array(); + } + self::$actions[$name][] = array('app' => $app, 'action' => $action, 'authlevel' => $authLevel); + } + + /** + * handles an api call + * @param array $parameters + */ + public static function call($parameters) { + // Prepare the request variables + if($_SERVER['REQUEST_METHOD'] == 'PUT') { + parse_str(file_get_contents("php://input"), $parameters['_put']); + } else if($_SERVER['REQUEST_METHOD'] == 'DELETE') { + parse_str(file_get_contents("php://input"), $parameters['_delete']); + } + $name = $parameters['_route']; + // Foreach registered action + $responses = array(); + foreach(self::$actions[$name] as $action) { + // Check authentication and availability + if(!self::isAuthorised($action)) { + $responses[] = array( + 'app' => $action['app'], + 'response' => new OC_OCS_Result(null, OC_API::RESPOND_UNAUTHORISED, 'Unauthorised'), + ); + continue; + } + if(!is_callable($action['action'])) { + $responses[] = array( + 'app' => $action['app'], + 'response' => new OC_OCS_Result(null, OC_API::RESPOND_NOT_FOUND, 'Api method not found'), + ); + continue; + } + // Run the action + $responses[] = array( + 'app' => $action['app'], + 'response' => call_user_func($action['action'], $parameters), + ); + } + $response = self::mergeResponses($responses); + $formats = array('json', 'xml'); + + $format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml'; + OC_User::logout(); + + self::respond($response, $format); + } + + /** + * merge the returned result objects into one response + * @param array $responses + */ + private static function mergeResponses($responses) { + $response = array(); + // Sort into shipped and thirdparty + $shipped = array( + 'succeeded' => array(), + 'failed' => array(), + ); + $thirdparty = array( + 'succeeded' => array(), + 'failed' => array(), + ); + + foreach($responses as $response) { + if(OC_App::isShipped($response['app']) || ($response['app'] === 'core')) { + if($response['response']->succeeded()) { + $shipped['succeeded'][$response['app']] = $response['response']; + } else { + $shipped['failed'][$response['app']] = $response['response']; + } + } else { + if($response['response']->succeeded()) { + $thirdparty['succeeded'][$response['app']] = $response['response']; + } else { + $thirdparty['failed'][$response['app']] = $response['response']; + } + } + } + + // Remove any error responses if there is one shipped response that succeeded + if(!empty($shipped['succeeded'])) { + $responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']); + } else if(!empty($shipped['failed'])) { + // Which shipped response do we use if they all failed? + // They may have failed for different reasons (different status codes) + // Which reponse code should we return? + // Maybe any that are not OC_API::RESPOND_SERVER_ERROR + $response = reset($shipped['failed']); + return $response; + } elseif(!empty($thirdparty['failed'])) { + // Return the third party failure result + $response = reset($thirdparty['failed']); + return $response; + } else { + $responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']); + } + // Merge the successful responses + $meta = array(); + $data = array(); + + foreach($responses as $app => $response) { + if(OC_App::isShipped($app)) { + $data = array_merge_recursive($response->getData(), $data); + } else { + $data = array_merge_recursive($data, $response->getData()); + } + } + $result = new OC_OCS_Result($data, 100); + return $result; + } + + /** + * authenticate the api call + * @param array $action the action details as supplied to OC_API::register() + * @return bool + */ + private static function isAuthorised($action) { + $level = $action['authlevel']; + switch($level) { + case OC_API::GUEST_AUTH: + // Anyone can access + return true; + break; + case OC_API::USER_AUTH: + // User required + return self::loginUser(); + break; + case OC_API::SUBADMIN_AUTH: + // Check for subadmin + $user = self::loginUser(); + if(!$user) { + return false; + } else { + $subAdmin = OC_SubAdmin::isSubAdmin($user); + $admin = OC_User::isAdminUser($user); + if($subAdmin || $admin) { + return true; + } else { + return false; + } + } + break; + case OC_API::ADMIN_AUTH: + // Check for admin + $user = self::loginUser(); + if(!$user) { + return false; + } else { + return OC_User::isAdminUser($user); + } + break; + default: + // oops looks like invalid level supplied + return false; + break; + } + } + + /** + * http basic auth + * @return string|false (username, or false on failure) + */ + private static function loginUser(){ + $authUser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : ''; + $authPw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; + return OC_User::login($authUser, $authPw) ? $authUser : false; + } + + /** + * respond to a call + * @param OC_OCS_Result $result + * @param string $format the format xml|json + */ + private static function respond($result, $format='xml') { + // Send 401 headers if unauthorised + if($result->getStatusCode() === self::RESPOND_UNAUTHORISED) { + header('WWW-Authenticate: Basic realm="Authorisation Required"'); + header('HTTP/1.0 401 Unauthorized'); + } + $response = array( + 'ocs' => array( + 'meta' => $result->getMeta(), + 'data' => $result->getData(), + ), + ); + if ($format == 'json') { + OC_JSON::encodedPrint($response); + } else if ($format == 'xml') { + header('Content-type: text/xml; charset=UTF-8'); + $writer = new XMLWriter(); + $writer->openMemory(); + $writer->setIndent( true ); + $writer->startDocument(); + self::toXML($response, $writer); + $writer->endDocument(); + echo $writer->outputMemory(true); + } + } + + private static function toXML($array, $writer) { + foreach($array as $k => $v) { + if ($k[0] === '@') { + $writer->writeAttribute(substr($k, 1), $v); + continue; + } else if (is_numeric($k)) { + $k = 'element'; + } + if(is_array($v)) { + $writer->startElement($k); + self::toXML($v, $writer); + $writer->endElement(); + } else { + $writer->writeElement($k, $v); + } + } + } + +} diff --git a/lib/private/app.php b/lib/private/app.php new file mode 100644 index 00000000000..0ab1ee57f63 --- /dev/null +++ b/lib/private/app.php @@ -0,0 +1,967 @@ +. + * + */ + +/** + * This class manages the apps. It allows them to register and integrate in the + * owncloud ecosystem. Furthermore, this class is responsible for installing, + * upgrading and removing apps. + */ +class OC_App{ + static private $settingsForms = array(); + static private $adminForms = array(); + static private $personalForms = array(); + static private $appInfo = array(); + static private $appTypes = array(); + static private $loadedApps = array(); + static private $checkedApps = array(); + static private $altLogin = array(); + + /** + * @brief clean the appid + * @param $app Appid that needs to be cleaned + * @return string + */ + public static function cleanAppId($app) { + return str_replace(array('\0', '/', '\\', '..'), '', $app); + } + + /** + * @brief loads all apps + * @param array $types + * @return bool + * + * This function walks through the owncloud directory and loads all apps + * it can find. A directory contains an app if the file /appinfo/app.php + * exists. + * + * if $types is set, only apps of those types will be loaded + */ + public static function loadApps($types=null) { + // Load the enabled apps here + $apps = self::getEnabledApps(); + // prevent app.php from printing output + ob_start(); + foreach( $apps as $app ) { + if((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) { + self::loadApp($app); + self::$loadedApps[] = $app; + } + } + ob_end_clean(); + + if (!defined('DEBUG') || !DEBUG) { + if (is_null($types) + && empty(OC_Util::$coreScripts) + && empty(OC_Util::$coreStyles)) { + OC_Util::$coreScripts = OC_Util::$scripts; + OC_Util::$scripts = array(); + OC_Util::$coreStyles = OC_Util::$styles; + OC_Util::$styles = array(); + } + } + // return + return true; + } + + /** + * load a single app + * @param string $app + */ + public static function loadApp($app) { + if(is_file(self::getAppPath($app).'/appinfo/app.php')) { + self::checkUpgrade($app); + require_once $app.'/appinfo/app.php'; + } + } + + /** + * check if an app is of a specific type + * @param string $app + * @param string/array $types + * @return bool + */ + public static function isType($app, $types) { + if(is_string($types)) { + $types=array($types); + } + $appTypes=self::getAppTypes($app); + foreach($types as $type) { + if(array_search($type, $appTypes)!==false) { + return true; + } + } + return false; + } + + /** + * get the types of an app + * @param string $app + * @return array + */ + private static function getAppTypes($app) { + //load the cache + if(count(self::$appTypes)==0) { + self::$appTypes=OC_Appconfig::getValues(false, 'types'); + } + + if(isset(self::$appTypes[$app])) { + return explode(',', self::$appTypes[$app]); + }else{ + return array(); + } + } + + /** + * read app types from info.xml and cache them in the database + */ + public static function setAppTypes($app) { + $appData=self::getAppInfo($app); + + if(isset($appData['types'])) { + $appTypes=implode(',', $appData['types']); + }else{ + $appTypes=''; + } + + OC_Appconfig::setValue($app, 'types', $appTypes); + } + + /** + * check if app is shipped + * @param string $appid the id of the app to check + * @return bool + * + * Check if an app that is installed is a shipped app or installed from the appstore. + */ + public static function isShipped($appid){ + $info = self::getAppInfo($appid); + if(isset($info['shipped']) && $info['shipped']=='true') { + return true; + } else { + return false; + } + } + + /** + * get all enabled apps + */ + public static function getEnabledApps() { + if(!OC_Config::getValue('installed', false)) { + return array(); + } + $apps=array('files'); + $sql = 'SELECT `appid` FROM `*PREFIX*appconfig`' + .' WHERE `configkey` = \'enabled\' AND `configvalue`=\'yes\''; + if (OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') { + //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison + $sql = 'SELECT `appid` FROM `*PREFIX*appconfig`' + .' WHERE `configkey` = \'enabled\' AND to_char(`configvalue`)=\'yes\''; + } + $query = OC_DB::prepare( $sql ); + $result=$query->execute(); + if( \OC_DB::isError($result)) { + throw new DatabaseException($result->getMessage(), $query); + } + while($row=$result->fetchRow()) { + if(array_search($row['appid'], $apps)===false) { + $apps[]=$row['appid']; + } + } + return $apps; + } + + /** + * @brief checks whether or not an app is enabled + * @param string $app app + * @return bool + * + * This function checks whether or not an app is enabled. + */ + public static function isEnabled( $app ) { + if( 'files'==$app or ('yes' == OC_Appconfig::getValue( $app, 'enabled' ))) { + return true; + } + + return false; + } + + /** + * @brief enables an app + * @param mixed $app app + * @throws \Exception + * @return void + * + * This function set an app as enabled in appconfig. + */ + public static function enable( $app ) { + if(!OC_Installer::isInstalled($app)) { + // check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string + if(!is_numeric($app)) { + $app = OC_Installer::installShippedApp($app); + }else{ + $appdata=OC_OCSClient::getApplication($app); + $download=OC_OCSClient::getApplicationDownload($app, 1); + if(isset($download['downloadlink']) and $download['downloadlink']!='') { + $info = array('source'=>'http', 'href'=>$download['downloadlink'], 'appdata'=>$appdata); + $app=OC_Installer::installApp($info); + } + } + } + $l = OC_L10N::get('core'); + if($app!==false) { + // check if the app is compatible with this version of ownCloud + $info=OC_App::getAppInfo($app); + $version=OC_Util::getVersion(); + if(!isset($info['require']) or !self::isAppVersionCompatible($version, $info['require'])) { + throw new \Exception( + $l->t("App \"%s\" can't be installed because it is not compatible with this version of ownCloud.", + array($info['name']) + ) + ); + }else{ + OC_Appconfig::setValue( $app, 'enabled', 'yes' ); + if(isset($appdata['id'])) { + OC_Appconfig::setValue( $app, 'ocsid', $appdata['id'] ); + } + } + }else{ + throw new \Exception($l->t("No app name specified")); + } + } + + /** + * @brief disables an app + * @param string $app app + * @return bool + * + * This function set an app as disabled in appconfig. + */ + public static function disable( $app ) { + // check if app is a shipped app or not. if not delete + \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app)); + OC_Appconfig::setValue( $app, 'enabled', 'no' ); + + // check if app is a shipped app or not. if not delete + if(!OC_App::isShipped( $app )) { + OC_Installer::removeApp( $app ); + } + } + + /** + * @brief adds an entry to the navigation + * @param array $data array containing the data + * @return bool + * + * This function adds a new entry to the navigation visible to users. $data + * is an associative array. + * The following keys are required: + * - id: unique id for this entry ('addressbook_index') + * - href: link to the page + * - name: Human readable name ('Addressbook') + * + * The following keys are optional: + * - icon: path to the icon of the app + * - order: integer, that influences the position of your application in + * the navigation. Lower values come first. + */ + public static function addNavigationEntry( $data ) { + OC::$server->getNavigationManager()->add($data); + return true; + } + + /** + * @brief marks a navigation entry as active + * @param string $id id of the entry + * @return bool + * + * This function sets a navigation entry as active and removes the 'active' + * property from all other entries. The templates can use this for + * highlighting the current position of the user. + */ + public static function setActiveNavigationEntry( $id ) { + OC::$server->getNavigationManager()->setActiveEntry($id); + return true; + } + + /** + * @brief Get the navigation entries for the $app + * @param string $app app + * @return array of the $data added with addNavigationEntry + * + * Warning: destroys the existing entries + */ + public static function getAppNavigationEntries($app) { + if(is_file(self::getAppPath($app).'/appinfo/app.php')) { + OC::$server->getNavigationManager()->clear(); + require $app.'/appinfo/app.php'; + return OC::$server->getNavigationManager()->getAll(); + } + return array(); + } + + /** + * @brief gets the active Menu entry + * @return string id or empty string + * + * This function returns the id of the active navigation entry (set by + * setActiveNavigationEntry + */ + public static function getActiveNavigationEntry() { + return OC::$server->getNavigationManager()->getActiveEntry(); + } + + /** + * @brief Returns the Settings Navigation + * @return array + * + * This function returns an array containing all settings pages added. The + * entries are sorted by the key 'order' ascending. + */ + public static function getSettingsNavigation() { + $l=OC_L10N::get('lib'); + + $settings = array(); + // by default, settings only contain the help menu + if(OC_Util::getEditionString() === '' && + OC_Config::getValue('knowledgebaseenabled', true)==true) { + $settings = array( + array( + "id" => "help", + "order" => 1000, + "href" => OC_Helper::linkToRoute( "settings_help" ), + "name" => $l->t("Help"), + "icon" => OC_Helper::imagePath( "settings", "help.svg" ) + ) + ); + } + + // if the user is logged-in + if (OC_User::isLoggedIn()) { + // personal menu + $settings[] = array( + "id" => "personal", + "order" => 1, + "href" => OC_Helper::linkToRoute( "settings_personal" ), + "name" => $l->t("Personal"), + "icon" => OC_Helper::imagePath( "settings", "personal.svg" ) + ); + + // if there are some settings forms + if(!empty(self::$settingsForms)) { + // settings menu + $settings[]=array( + "id" => "settings", + "order" => 1000, + "href" => OC_Helper::linkToRoute( "settings_settings" ), + "name" => $l->t("Settings"), + "icon" => OC_Helper::imagePath( "settings", "settings.svg" ) + ); + } + + //SubAdmins are also allowed to access user management + if(OC_SubAdmin::isSubAdmin(OC_User::getUser())) { + // admin users menu + $settings[] = array( + "id" => "core_users", + "order" => 2, + "href" => OC_Helper::linkToRoute( "settings_users" ), + "name" => $l->t("Users"), + "icon" => OC_Helper::imagePath( "settings", "users.svg" ) + ); + } + + + // if the user is an admin + if(OC_User::isAdminUser(OC_User::getUser())) { + // admin settings + $settings[]=array( + "id" => "admin", + "order" => 1000, + "href" => OC_Helper::linkToRoute( "settings_admin" ), + "name" => $l->t("Admin"), + "icon" => OC_Helper::imagePath( "settings", "admin.svg" ) + ); + } + } + + $navigation = self::proceedNavigation($settings); + return $navigation; + } + + // This is private as well. It simply works, so don't ask for more details + private static function proceedNavigation( $list ) { + $activeapp = OC::$server->getNavigationManager()->getActiveEntry(); + foreach( $list as &$naventry ) { + if( $naventry['id'] == $activeapp ) { + $naventry['active'] = true; + } + else{ + $naventry['active'] = false; + } + } unset( $naventry ); + + usort( $list, create_function( '$a, $b', 'if( $a["order"] == $b["order"] ) {return 0;}elseif( $a["order"] < $b["order"] ) {return -1;}else{return 1;}' )); + + return $list; + } + + /** + * Get the path where to install apps + */ + public static function getInstallPath() { + if(OC_Config::getValue('appstoreenabled', true)==false) { + return false; + } + + foreach(OC::$APPSROOTS as $dir) { + if(isset($dir['writable']) && $dir['writable']===true) { + return $dir['path']; + } + } + + OC_Log::write('core', 'No application directories are marked as writable.', OC_Log::ERROR); + return null; + } + + + protected static function findAppInDirectories($appid) { + static $app_dir = array(); + if (isset($app_dir[$appid])) { + return $app_dir[$appid]; + } + foreach(OC::$APPSROOTS as $dir) { + if(file_exists($dir['path'].'/'.$appid)) { + return $app_dir[$appid]=$dir; + } + } + return false; + } + /** + * Get the directory for the given app. + * If the app is defined in multiple directories, the first one is taken. (false if not found) + */ + public static function getAppPath($appid) { + if( ($dir = self::findAppInDirectories($appid)) != false) { + return $dir['path'].'/'.$appid; + } + return false; + } + + /** + * Get the path for the given app on the access + * If the app is defined in multiple directories, the first one is taken. (false if not found) + */ + public static function getAppWebPath($appid) { + if( ($dir = self::findAppInDirectories($appid)) != false) { + return OC::$WEBROOT.$dir['url'].'/'.$appid; + } + return false; + } + + /** + * get the last version of the app, either from appinfo/version or from appinfo/info.xml + */ + public static function getAppVersion($appid) { + $file= self::getAppPath($appid).'/appinfo/version'; + if(is_file($file) && $version = trim(file_get_contents($file))) { + return $version; + }else{ + $appData=self::getAppInfo($appid); + return isset($appData['version'])? $appData['version'] : ''; + } + } + + /** + * @brief Read all app metadata from the info.xml file + * @param string $appid id of the app or the path of the info.xml file + * @param boolean $path (optional) + * @return array + * @note all data is read from info.xml, not just pre-defined fields + */ + public static function getAppInfo($appid, $path=false) { + if($path) { + $file=$appid; + }else{ + if(isset(self::$appInfo[$appid])) { + return self::$appInfo[$appid]; + } + $file= self::getAppPath($appid).'/appinfo/info.xml'; + } + $data=array(); + $content=@file_get_contents($file); + if(!$content) { + return null; + } + $xml = new SimpleXMLElement($content); + $data['info']=array(); + $data['remote']=array(); + $data['public']=array(); + foreach($xml->children() as $child) { + /** + * @var $child SimpleXMLElement + */ + if($child->getName()=='remote') { + foreach($child->children() as $remote) { + /** + * @var $remote SimpleXMLElement + */ + $data['remote'][$remote->getName()]=(string)$remote; + } + }elseif($child->getName()=='public') { + foreach($child->children() as $public) { + /** + * @var $public SimpleXMLElement + */ + $data['public'][$public->getName()]=(string)$public; + } + }elseif($child->getName()=='types') { + $data['types']=array(); + foreach($child->children() as $type) { + /** + * @var $type SimpleXMLElement + */ + $data['types'][]=$type->getName(); + } + }elseif($child->getName()=='description') { + $xml=(string)$child->asXML(); + $data[$child->getName()]=substr($xml, 13, -14);//script tags + }else{ + $data[$child->getName()]=(string)$child; + } + } + self::$appInfo[$appid]=$data; + + return $data; + } + + /** + * @brief Returns the navigation + * @return array + * + * This function returns an array containing all entries added. The + * entries are sorted by the key 'order' ascending. Additional to the keys + * given for each app the following keys exist: + * - active: boolean, signals if the user is on this navigation entry + */ + public static function getNavigation() { + $entries = OC::$server->getNavigationManager()->getAll(); + $navigation = self::proceedNavigation( $entries ); + return $navigation; + } + + /** + * get the id of loaded app + * @return string + */ + public static function getCurrentApp() { + $script=substr(OC_Request::scriptName(), strlen(OC::$WEBROOT)+1); + $topFolder=substr($script, 0, strpos($script, '/')); + if (empty($topFolder)) { + $path_info = OC_Request::getPathInfo(); + if ($path_info) { + $topFolder=substr($path_info, 1, strpos($path_info, '/', 1)-1); + } + } + if($topFolder=='apps') { + $length=strlen($topFolder); + return substr($script, $length+1, strpos($script, '/', $length+1)-$length-1); + }else{ + return $topFolder; + } + } + + + /** + * get the forms for either settings, admin or personal + */ + public static function getForms($type) { + $forms=array(); + switch($type) { + case 'settings': + $source=self::$settingsForms; + break; + case 'admin': + $source=self::$adminForms; + break; + case 'personal': + $source=self::$personalForms; + break; + default: + return array(); + } + foreach($source as $form) { + $forms[]=include $form; + } + return $forms; + } + + /** + * register a settings form to be shown + */ + public static function registerSettings($app, $page) { + self::$settingsForms[]= $app.'/'.$page.'.php'; + } + + /** + * register an admin form to be shown + */ + public static function registerAdmin($app, $page) { + self::$adminForms[]= $app.'/'.$page.'.php'; + } + + /** + * register a personal form to be shown + */ + public static function registerPersonal($app, $page) { + self::$personalForms[]= $app.'/'.$page.'.php'; + } + + public static function registerLogIn($entry) { + self::$altLogin[] = $entry; + } + + public static function getAlternativeLogIns() { + return self::$altLogin; + } + + /** + * @brief: get a list of all apps in the apps folder + * @return array or app names (string IDs) + * @todo: change the name of this method to getInstalledApps, which is more accurate + */ + public static function getAllApps() { + + $apps=array(); + + foreach ( OC::$APPSROOTS as $apps_dir ) { + if(! is_readable($apps_dir['path'])) { + OC_Log::write('core', 'unable to read app folder : ' .$apps_dir['path'], OC_Log::WARN); + continue; + } + $dh = opendir( $apps_dir['path'] ); + + if(is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + + if ($file[0] != '.' and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php')) { + + $apps[] = $file; + + } + + } + } + + } + + return $apps; + } + + /** + * @brief: Lists all apps, this is used in apps.php + * @return array + */ + public static function listAllApps() { + $installedApps = OC_App::getAllApps(); + + //TODO which apps do we want to blacklist and how do we integrate + // blacklisting with the multi apps folder feature? + + $blacklist = array('files');//we dont want to show configuration for these + $appList = array(); + + foreach ( $installedApps as $app ) { + if ( array_search( $app, $blacklist ) === false ) { + + $info=OC_App::getAppInfo($app); + + if (!isset($info['name'])) { + OC_Log::write('core', 'App id "'.$app.'" has no name in appinfo', OC_Log::ERROR); + continue; + } + + if ( OC_Appconfig::getValue( $app, 'enabled', 'no') == 'yes' ) { + $active = true; + } else { + $active = false; + } + + $info['active'] = $active; + + if(isset($info['shipped']) and ($info['shipped']=='true')) { + $info['internal']=true; + $info['internallabel']='Internal App'; + $info['internalclass']=''; + $info['update']=false; + } else { + $info['internal']=false; + $info['internallabel']='3rd Party'; + $info['internalclass']='externalapp'; + $info['update']=OC_Installer::isUpdateAvailable($app); + } + + $info['preview'] = OC_Helper::imagePath('settings', 'trans.png'); + $info['version'] = OC_App::getAppVersion($app); + $appList[] = $info; + } + } + $remoteApps = OC_App::getAppstoreApps(); + if ( $remoteApps ) { + // Remove duplicates + foreach ( $appList as $app ) { + foreach ( $remoteApps AS $key => $remote ) { + if ( + $app['name'] == $remote['name'] + // To set duplicate detection to use OCS ID instead of string name, + // enable this code, remove the line of code above, + // and add [ID] to info.xml of each 3rd party app: + // OR $app['ocs_id'] == $remote['ocs_id'] + ) { + unset( $remoteApps[$key]); + } + } + } + $combinedApps = array_merge( $appList, $remoteApps ); + } else { + $combinedApps = $appList; + } + return $combinedApps; + } + + /** + * @brief: get a list of all apps on apps.owncloud.com + * @return array, multi-dimensional array of apps. + * Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description + */ + public static function getAppstoreApps( $filter = 'approved' ) { + $categoryNames = OC_OCSClient::getCategories(); + if ( is_array( $categoryNames ) ) { + // Check that categories of apps were retrieved correctly + if ( ! $categories = array_keys( $categoryNames ) ) { + return false; + } + + $page = 0; + $remoteApps = OC_OCSClient::getApplications( $categories, $page, $filter ); + $app1 = array(); + $i = 0; + foreach ( $remoteApps as $app ) { + $app1[$i] = $app; + $app1[$i]['author'] = $app['personid']; + $app1[$i]['ocs_id'] = $app['id']; + $app1[$i]['internal'] = $app1[$i]['active'] = 0; + $app1[$i]['update'] = false; + if($app['label']=='recommended') { + $app1[$i]['internallabel'] = 'Recommended'; + $app1[$i]['internalclass'] = 'recommendedapp'; + }else{ + $app1[$i]['internallabel'] = '3rd Party'; + $app1[$i]['internalclass'] = 'externalapp'; + } + + + // rating img + if($app['score']>=0 and $app['score']<5) $img=OC_Helper::imagePath( "core", "rating/s1.png" ); + elseif($app['score']>=5 and $app['score']<15) $img=OC_Helper::imagePath( "core", "rating/s2.png" ); + elseif($app['score']>=15 and $app['score']<25) $img=OC_Helper::imagePath( "core", "rating/s3.png" ); + elseif($app['score']>=25 and $app['score']<35) $img=OC_Helper::imagePath( "core", "rating/s4.png" ); + elseif($app['score']>=35 and $app['score']<45) $img=OC_Helper::imagePath( "core", "rating/s5.png" ); + elseif($app['score']>=45 and $app['score']<55) $img=OC_Helper::imagePath( "core", "rating/s6.png" ); + elseif($app['score']>=55 and $app['score']<65) $img=OC_Helper::imagePath( "core", "rating/s7.png" ); + elseif($app['score']>=65 and $app['score']<75) $img=OC_Helper::imagePath( "core", "rating/s8.png" ); + elseif($app['score']>=75 and $app['score']<85) $img=OC_Helper::imagePath( "core", "rating/s9.png" ); + elseif($app['score']>=85 and $app['score']<95) $img=OC_Helper::imagePath( "core", "rating/s10.png" ); + elseif($app['score']>=95 and $app['score']<100) $img=OC_Helper::imagePath( "core", "rating/s11.png" ); + + $app1[$i]['score'] = ' Score: '.$app['score'].'%'; + $i++; + } + } + + if ( empty( $app1 ) ) { + return false; + } else { + return $app1; + } + } + + /** + * check if the app needs updating and update when needed + */ + public static function checkUpgrade($app) { + if (in_array($app, self::$checkedApps)) { + return; + } + self::$checkedApps[] = $app; + $versions = self::getAppVersions(); + $currentVersion=OC_App::getAppVersion($app); + if ($currentVersion) { + $installedVersion = $versions[$app]; + if (version_compare($currentVersion, $installedVersion, '>')) { + $info = self::getAppInfo($app); + OC_Log::write($app, + 'starting app upgrade from '.$installedVersion.' to '.$currentVersion, + OC_Log::DEBUG); + try { + OC_App::updateApp($app); + OC_Hook::emit('update', 'success', 'Updated '.$info['name'].' app'); + } + catch (Exception $e) { + OC_Hook::emit('update', 'failure', 'Failed to update '.$info['name'].' app: '.$e->getMessage()); + $l = OC_L10N::get('lib'); + throw new RuntimeException($l->t('Failed to upgrade "%s".', array($app)), 0, $e); + } + OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app)); + } + } + } + + /** + * check if the current enabled apps are compatible with the current + * ownCloud version. disable them if not. + * This is important if you upgrade ownCloud and have non ported 3rd + * party apps installed. + */ + public static function checkAppsRequirements($apps = array()) { + if (empty($apps)) { + $apps = OC_App::getEnabledApps(); + } + $version = OC_Util::getVersion(); + foreach($apps as $app) { + // check if the app is compatible with this version of ownCloud + $info = OC_App::getAppInfo($app); + if(!isset($info['require']) or !self::isAppVersionCompatible($version, $info['require'])) { + OC_Log::write('core', + 'App "'.$info['name'].'" ('.$app.') can\'t be used because it is' + .' not compatible with this version of ownCloud', + OC_Log::ERROR); + OC_App::disable( $app ); + OC_Hook::emit('update', 'success', 'Disabled '.$info['name'].' app because it is not compatible'); + } + } + } + + + /** + * Compares the app version with the owncloud version to see if the app + * requires a newer version than the currently active one + * @param array $owncloudVersions array with 3 entries: major minor bugfix + * @param string $appRequired the required version from the xml + * major.minor.bugfix + * @return boolean true if compatible, otherwise false + */ + public static function isAppVersionCompatible($owncloudVersions, $appRequired){ + $appVersions = explode('.', $appRequired); + + for($i=0; $i $appVersion) { + return true; + } + } + + return true; + } + + + /** + * get the installed version of all apps + */ + public static function getAppVersions() { + static $versions; + if (isset($versions)) { // simple cache, needs to be fixed + return $versions; // when function is used besides in checkUpgrade + } + $versions=array(); + $query = OC_DB::prepare( 'SELECT `appid`, `configvalue` FROM `*PREFIX*appconfig`' + .' WHERE `configkey` = \'installed_version\'' ); + $result = $query->execute(); + while($row = $result->fetchRow()) { + $versions[$row['appid']]=$row['configvalue']; + } + return $versions; + } + + /** + * update the database for the app and call the update script + * @param string $appid + */ + public static function updateApp($appid) { + if(file_exists(self::getAppPath($appid).'/appinfo/preupdate.php')) { + self::loadApp($appid); + include self::getAppPath($appid).'/appinfo/preupdate.php'; + } + if(file_exists(self::getAppPath($appid).'/appinfo/database.xml')) { + OC_DB::updateDbFromStructure(self::getAppPath($appid).'/appinfo/database.xml'); + } + if(!self::isEnabled($appid)) { + return; + } + if(file_exists(self::getAppPath($appid).'/appinfo/update.php')) { + self::loadApp($appid); + include self::getAppPath($appid).'/appinfo/update.php'; + } + + //set remote/public handlers + $appData=self::getAppInfo($appid); + foreach($appData['remote'] as $name=>$path) { + OCP\CONFIG::setAppValue('core', 'remote_'.$name, $appid.'/'.$path); + } + foreach($appData['public'] as $name=>$path) { + OCP\CONFIG::setAppValue('core', 'public_'.$name, $appid.'/'.$path); + } + + self::setAppTypes($appid); + } + + /** + * @param string $appid + * @return \OC\Files\View + */ + public static function getStorage($appid) { + if(OC_App::isEnabled($appid)) {//sanity check + if(OC_User::isLoggedIn()) { + $view = new \OC\Files\View('/'.OC_User::getUser()); + if(!$view->file_exists($appid)) { + $view->mkdir($appid); + } + return new \OC\Files\View('/'.OC_User::getUser().'/'.$appid); + }else{ + OC_Log::write('core', 'Can\'t get app storage, app '.$appid.', user not logged in', OC_Log::ERROR); + return false; + } + }else{ + OC_Log::write('core', 'Can\'t get app storage, app '.$appid.' not enabled', OC_Log::ERROR); + return false; + } + } +} diff --git a/lib/private/appconfig.php b/lib/private/appconfig.php new file mode 100644 index 00000000000..e615d838173 --- /dev/null +++ b/lib/private/appconfig.php @@ -0,0 +1,203 @@ +. + * + */ +/* + * + * The following SQL statement is just a help for developers and will not be + * executed! + * + * CREATE TABLE `appconfig` ( + * `appid` VARCHAR( 255 ) NOT NULL , + * `configkey` VARCHAR( 255 ) NOT NULL , + * `configvalue` VARCHAR( 255 ) NOT NULL + * ) + * + */ + +/** + * This class provides an easy way for apps to store config values in the + * database. + */ +class OC_Appconfig{ + /** + * @brief Get all apps using the config + * @return array with app ids + * + * This function returns a list of all apps that have at least one + * entry in the appconfig table. + */ + public static function getApps() { + // No magic in here! + $query = OC_DB::prepare( 'SELECT DISTINCT `appid` FROM `*PREFIX*appconfig`' ); + $result = $query->execute(); + + $apps = array(); + while( $row = $result->fetchRow()) { + $apps[] = $row["appid"]; + } + + return $apps; + } + + /** + * @brief Get the available keys for an app + * @param string $app the app we are looking for + * @return array with key names + * + * This function gets all keys of an app. Please note that the values are + * not returned. + */ + public static function getKeys( $app ) { + // No magic in here as well + $query = OC_DB::prepare( 'SELECT `configkey` FROM `*PREFIX*appconfig` WHERE `appid` = ?' ); + $result = $query->execute( array( $app )); + + $keys = array(); + while( $row = $result->fetchRow()) { + $keys[] = $row["configkey"]; + } + + return $keys; + } + + /** + * @brief Gets the config value + * @param string $app app + * @param string $key key + * @param string $default = null, default value if the key does not exist + * @return string the value or $default + * + * This function gets a value from the appconfig table. If the key does + * not exist the default value will be returned + */ + public static function getValue( $app, $key, $default = null ) { + // At least some magic in here :-) + $query = OC_DB::prepare( 'SELECT `configvalue` FROM `*PREFIX*appconfig`' + .' WHERE `appid` = ? AND `configkey` = ?' ); + $result = $query->execute( array( $app, $key )); + $row = $result->fetchRow(); + if($row) { + return $row["configvalue"]; + }else{ + return $default; + } + } + + /** + * @brief check if a key is set in the appconfig + * @param string $app + * @param string $key + * @return bool + */ + public static function hasKey($app, $key) { + $exists = self::getKeys( $app ); + return in_array( $key, $exists ); + } + + /** + * @brief sets a value in the appconfig + * @param string $app app + * @param string $key key + * @param string $value value + * @return bool + * + * Sets a value. If the key did not exist before it will be created. + */ + public static function setValue( $app, $key, $value ) { + // Does the key exist? yes: update. No: insert + if(! self::hasKey($app, $key)) { + $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*appconfig` ( `appid`, `configkey`, `configvalue` )' + .' VALUES( ?, ?, ? )' ); + $query->execute( array( $app, $key, $value )); + } + else{ + $query = OC_DB::prepare( 'UPDATE `*PREFIX*appconfig` SET `configvalue` = ?' + .' WHERE `appid` = ? AND `configkey` = ?' ); + $query->execute( array( $value, $app, $key )); + } + } + + /** + * @brief Deletes a key + * @param string $app app + * @param string $key key + * @return bool + * + * Deletes a key. + */ + public static function deleteKey( $app, $key ) { + // Boring! + $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*appconfig` WHERE `appid` = ? AND `configkey` = ?' ); + $query->execute( array( $app, $key )); + + return true; + } + + /** + * @brief Remove app from appconfig + * @param string $app app + * @return bool + * + * Removes all keys in appconfig belonging to the app. + */ + public static function deleteApp( $app ) { + // Nothing special + $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*appconfig` WHERE `appid` = ?' ); + $query->execute( array( $app )); + + return true; + } + + /** + * get multiply values, either the app or key can be used as wildcard by setting it to false + * @param app + * @param key + * @return array + */ + public static function getValues($app, $key) { + if($app!==false and $key!==false) { + return false; + } + $fields='`configvalue`'; + $where='WHERE'; + $params=array(); + if($app!==false) { + $fields.=', `configkey`'; + $where.=' `appid` = ?'; + $params[]=$app; + $key='configkey'; + }else{ + $fields.=', `appid`'; + $where.=' `configkey` = ?'; + $params[]=$key; + $key='appid'; + } + $queryString='SELECT '.$fields.' FROM `*PREFIX*appconfig` '.$where; + $query=OC_DB::prepare($queryString); + $result=$query->execute($params); + $values=array(); + while($row=$result->fetchRow()) { + $values[$row[$key]]=$row['configvalue']; + } + return $values; + } +} diff --git a/lib/private/appframework/app.php b/lib/private/appframework/app.php new file mode 100644 index 00000000000..7ff55bb809d --- /dev/null +++ b/lib/private/appframework/app.php @@ -0,0 +1,98 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\DependencyInjection\DIContainer; +use OCP\AppFramework\IAppContainer; + + +/** + * Entry point for every request in your app. You can consider this as your + * public static void main() method + * + * Handles all the dependency injection, controllers and output flow + */ +class App { + + + /** + * Shortcut for calling a controller method and printing the result + * @param string $controllerName the name of the controller under which it is + * stored in the DI container + * @param string $methodName the method that you want to call + * @param array $urlParams an array with variables extracted from the routes + * @param DIContainer $container an instance of a pimple container. + */ + public static function main($controllerName, $methodName, array $urlParams, + IAppContainer $container) { + $container['urlParams'] = $urlParams; + $controller = $container[$controllerName]; + + // initialize the dispatcher and run all the middleware before the controller + $dispatcher = $container['Dispatcher']; + + list($httpHeaders, $responseHeaders, $output) = + $dispatcher->dispatch($controller, $methodName); + + if(!is_null($httpHeaders)) { + header($httpHeaders); + } + + foreach($responseHeaders as $name => $value) { + header($name . ': ' . $value); + } + + if(!is_null($output)) { + header('Content-Length: ' . strlen($output)); + print($output); + } + + } + + /** + * Shortcut for calling a controller method and printing the result. + * Similar to App:main except that no headers will be sent. + * This should be used for example when registering sections via + * \OC\AppFramework\Core\API::registerAdmin() + * + * @param string $controllerName the name of the controller under which it is + * stored in the DI container + * @param string $methodName the method that you want to call + * @param array $urlParams an array with variables extracted from the routes + * @param DIContainer $container an instance of a pimple container. + */ + public static function part($controllerName, $methodName, array $urlParams, + DIContainer $container){ + + $container['urlParams'] = $urlParams; + $controller = $container[$controllerName]; + + $dispatcher = $container['Dispatcher']; + + list(, , $output) = $dispatcher->dispatch($controller, $methodName); + return $output; + } + +} diff --git a/lib/private/appframework/controller/controller.php b/lib/private/appframework/controller/controller.php new file mode 100644 index 00000000000..0ea0a38cc09 --- /dev/null +++ b/lib/private/appframework/controller/controller.php @@ -0,0 +1,142 @@ +. + * + */ + + +namespace OC\AppFramework\Controller; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Core\API; +use OCP\AppFramework\Http\TemplateResponse; + + +/** + * Base class to inherit your controllers from + */ +abstract class Controller { + + /** + * @var API instance of the api layer + */ + protected $api; + + protected $request; + + /** + * @param API $api an api wrapper instance + * @param Request $request an instance of the request + */ + public function __construct(API $api, Request $request){ + $this->api = $api; + $this->request = $request; + } + + + /** + * Lets you access post and get parameters by the index + * @param string $key the key which you want to access in the URL Parameter + * placeholder, $_POST or $_GET array. + * The priority how they're returned is the following: + * 1. URL parameters + * 2. POST parameters + * 3. GET parameters + * @param mixed $default If the key is not found, this value will be returned + * @return mixed the content of the array + */ + public function params($key, $default=null){ + return $this->request->getParam($key, $default); + } + + + /** + * Returns all params that were received, be it from the request + * (as GET or POST) or throuh the URL by the route + * @return array the array with all parameters + */ + public function getParams() { + return $this->request->getParams(); + } + + + /** + * Returns the method of the request + * @return string the method of the request (POST, GET, etc) + */ + public function method() { + return $this->request->getMethod(); + } + + + /** + * Shortcut for accessing an uploaded file through the $_FILES array + * @param string $key the key that will be taken from the $_FILES array + * @return array the file in the $_FILES element + */ + public function getUploadedFile($key) { + return $this->request->getUploadedFile($key); + } + + + /** + * Shortcut for getting env variables + * @param string $key the key that will be taken from the $_ENV array + * @return array the value in the $_ENV element + */ + public function env($key) { + return $this->request->getEnv($key); + } + + + /** + * Shortcut for getting cookie variables + * @param string $key the key that will be taken from the $_COOKIE array + * @return array the value in the $_COOKIE element + */ + public function cookie($key) { + return $this->request->getCookie($key); + } + + + /** + * Shortcut for rendering a template + * @param string $templateName the name of the template + * @param array $params the template parameters in key => value structure + * @param string $renderAs user renders a full page, blank only your template + * admin an entry in the admin settings + * @param array $headers set additional headers in name/value pairs + * @return \OCP\AppFramework\Http\TemplateResponse containing the page + */ + public function render($templateName, array $params=array(), + $renderAs='user', array $headers=array()){ + $response = new TemplateResponse($this->api, $templateName); + $response->setParams($params); + $response->renderAs($renderAs); + + foreach($headers as $name => $value){ + $response->addHeader($name, $value); + } + + return $response; + } + + +} diff --git a/lib/private/appframework/core/api.php b/lib/private/appframework/core/api.php new file mode 100644 index 00000000000..39522ee3dd5 --- /dev/null +++ b/lib/private/appframework/core/api.php @@ -0,0 +1,348 @@ +. + * + */ + + +namespace OC\AppFramework\Core; +use OCP\AppFramework\IApi; + + +/** + * This is used to wrap the owncloud static api calls into an object to make the + * code better abstractable for use in the dependency injection container + * + * Should you find yourself in need for more methods, simply inherit from this + * class and add your methods + */ +class API implements IApi{ + + private $appName; + + /** + * constructor + * @param string $appName the name of your application + */ + public function __construct($appName){ + $this->appName = $appName; + } + + + /** + * Gets the userid of the current user + * @return string the user id of the current user + */ + public function getUserId(){ + return \OCP\User::getUser(); + } + + + /** + * Adds a new javascript file + * @param string $scriptName the name of the javascript in js/ without the suffix + * @param string $appName the name of the app, defaults to the current one + */ + public function addScript($scriptName, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + \OCP\Util::addScript($appName, $scriptName); + } + + + /** + * Adds a new css file + * @param string $styleName the name of the css file in css/without the suffix + * @param string $appName the name of the app, defaults to the current one + */ + public function addStyle($styleName, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + \OCP\Util::addStyle($appName, $styleName); + } + + + /** + * shorthand for addScript for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + */ + public function add3rdPartyScript($name){ + \OCP\Util::addScript($this->appName . '/3rdparty', $name); + } + + + /** + * shorthand for addStyle for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + */ + public function add3rdPartyStyle($name){ + \OCP\Util::addStyle($this->appName . '/3rdparty', $name); + } + + + /** + * Returns the translation object + * @return \OC_L10N the translation object + */ + public function getTrans(){ + # TODO: use public api + return \OC_L10N::get($this->appName); + } + + + /** + * Returns the URL for a route + * @param string $routeName the name of the route + * @param array $arguments an array with arguments which will be filled into the url + * @return string the url + */ + public function linkToRoute($routeName, $arguments=array()){ + return \OCP\Util::linkToRoute($routeName, $arguments); + } + + + /** + * Returns an URL for an image or file + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + */ + public function linkTo($file, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Util::linkTo($appName, $file); + } + + + /** + * Returns the link to an image, like link to but only with prepending img/ + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + */ + public function imagePath($file, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Util::imagePath($appName, $file); + } + + + /** + * Makes an URL absolute + * @param string $url the url + * @return string the absolute url + */ + public function getAbsoluteURL($url){ + # TODO: use public api + return \OC_Helper::makeURLAbsolute($url); + } + + + /** + * links to a file + * @param string $file the name of the file + * @param string $appName the name of the app, defaults to the current one + * @deprecated replaced with linkToRoute() + * @return string the url + */ + public function linkToAbsolute($file, $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + return \OCP\Util::linkToAbsolute($appName, $file); + } + + + /** + * Checks if the CSRF check was correct + * @return bool true if CSRF check passed + */ + public function passesCSRFCheck(){ + # TODO: use public api + return \OC_Util::isCallRegistered(); + } + + + /** + * Checks if an app is enabled + * @param string $appName the name of an app + * @return bool true if app is enabled + */ + public function isAppEnabled($appName){ + return \OCP\App::isEnabled($appName); + } + + + /** + * Writes a function into the error log + * @param string $msg the error message to be logged + * @param int $level the error level + */ + public function log($msg, $level=null){ + switch($level){ + case 'debug': + $level = \OCP\Util::DEBUG; + break; + case 'info': + $level = \OCP\Util::INFO; + break; + case 'warn': + $level = \OCP\Util::WARN; + break; + case 'fatal': + $level = \OCP\Util::FATAL; + break; + default: + $level = \OCP\Util::ERROR; + break; + } + \OCP\Util::writeLog($this->appName, $msg, $level); + } + + + /** + * turns an owncloud path into a path on the filesystem + * @param string path the path to the file on the oc filesystem + * @return string the filepath in the filesystem + */ + public function getLocalFilePath($path){ + # TODO: use public api + return \OC_Filesystem::getLocalFile($path); + } + + + /** + * used to return and open a new eventsource + * @return \OC_EventSource a new open EventSource class + */ + public function openEventSource(){ + # TODO: use public api + return new \OC_EventSource(); + } + + /** + * @brief connects a function to a hook + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param string $slotClass class name of slot + * @param string $slotName name of slot, in another word, this is the + * name of the method that will be called when registered + * signal is emitted. + * @return bool, always true + */ + public function connectHook($signalClass, $signalName, $slotClass, $slotName) { + return \OCP\Util::connectHook($signalClass, $signalName, $slotClass, $slotName); + } + + /** + * @brief Emits a signal. To get data from the slot use references! + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param array $params defautl: array() array with additional data + * @return bool, true if slots exists or false if not + */ + public function emitHook($signalClass, $signalName, $params = array()) { + return \OCP\Util::emitHook($signalClass, $signalName, $params); + } + + /** + * @brief clear hooks + * @param string $signalClass + * @param string $signalName + */ + public function clearHook($signalClass=false, $signalName=false) { + if ($signalClass) { + \OC_Hook::clear($signalClass, $signalName); + } + } + + /** + * Gets the content of an URL by using CURL or a fallback if it is not + * installed + * @param string $url the url that should be fetched + * @return string the content of the webpage + */ + public function getUrlContent($url) { + return \OC_Util::getUrlContent($url); + } + + /** + * Register a backgroundjob task + * @param string $className full namespace and class name of the class + * @param string $methodName the name of the static method that should be + * called + */ + public function addRegularTask($className, $methodName) { + \OCP\Backgroundjob::addRegularTask($className, $methodName); + } + + /** + * Returns a template + * @param string $templateName the name of the template + * @param string $renderAs how it should be rendered + * @param string $appName the name of the app + * @return \OCP\Template a new template + */ + public function getTemplate($templateName, $renderAs='user', $appName=null){ + if($appName === null){ + $appName = $this->appName; + } + + if($renderAs === 'blank'){ + return new \OCP\Template($appName, $templateName); + } else { + return new \OCP\Template($appName, $templateName, $renderAs); + } + } + + + /** + * Tells ownCloud to include a template in the admin overview + * @param string $mainPath the path to the main php file without the php + * suffix, relative to your apps directory! not the template directory + * @param string $appName the name of the app, defaults to the current one + */ + public function registerAdmin($mainPath, $appName=null) { + if($appName === null){ + $appName = $this->appName; + } + + \OCP\App::registerAdmin($appName, $mainPath); + } + + + /** + * get the filesystem info + * + * @param string $path + * @return array with the following keys: + * - size + * - mtime + * - mimetype + * - encrypted + * - versioned + */ + public function getFileInfo($path) { + return \OC\Files\Filesystem::getFileInfo($path); + } + +} diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php new file mode 100644 index 00000000000..3755d45fa09 --- /dev/null +++ b/lib/private/appframework/dependencyinjection/dicontainer.php @@ -0,0 +1,146 @@ +. + * + */ + + +namespace OC\AppFramework\DependencyInjection; + +use OC\AppFramework\Http\Http; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\Dispatcher; +use OC\AppFramework\Core\API; +use OC\AppFramework\Middleware\MiddlewareDispatcher; +use OC\AppFramework\Middleware\Security\SecurityMiddleware; +use OC\AppFramework\Utility\SimpleContainer; +use OC\AppFramework\Utility\TimeFactory; +use OCP\AppFramework\IApi; +use OCP\AppFramework\IAppContainer; +use OCP\AppFramework\IMiddleWare; +use OCP\IServerContainer; + + +class DIContainer extends SimpleContainer implements IAppContainer{ + + /** + * @var array + */ + private $middleWares = array(); + + /** + * Put your class dependencies in here + * @param string $appName the name of the app + */ + public function __construct($appName){ + + $this['AppName'] = $appName; + + $this->registerParameter('ServerContainer', \OC::$server); + + $this['API'] = $this->share(function($c){ + return new API($c['AppName']); + }); + + /** + * Http + */ + $this['Request'] = $this->share(function($c) { + /** @var $c SimpleContainer */ + /** @var $server IServerContainer */ + $server = $c->query('ServerContainer'); + return $server->getRequest(); + }); + + $this['Protocol'] = $this->share(function($c){ + if(isset($_SERVER['SERVER_PROTOCOL'])) { + return new Http($_SERVER, $_SERVER['SERVER_PROTOCOL']); + } else { + return new Http($_SERVER); + } + }); + + $this['Dispatcher'] = $this->share(function($c) { + return new Dispatcher($c['Protocol'], $c['MiddlewareDispatcher']); + }); + + + /** + * Middleware + */ + $this['SecurityMiddleware'] = $this->share(function($c){ + return new SecurityMiddleware($c['API'], $c['Request']); + }); + + $this['MiddlewareDispatcher'] = $this->share(function($c){ + $dispatcher = new MiddlewareDispatcher(); + $dispatcher->registerMiddleware($c['SecurityMiddleware']); + + foreach($this->middleWares as $middleWare) { + $dispatcher->registerMiddleware($middleWare); + } + + return $dispatcher; + }); + + + /** + * Utilities + */ + $this['TimeFactory'] = $this->share(function($c){ + return new TimeFactory(); + }); + + + } + + + /** + * @return IApi + */ + function getCoreApi() + { + return $this->query('API'); + } + + /** + * @return \OCP\IServerContainer + */ + function getServer() + { + return $this->query('ServerContainer'); + } + + /** + * @param IMiddleWare $middleWare + * @return boolean + */ + function registerMiddleWare(IMiddleWare $middleWare) { + array_push($this->middleWares, $middleWare); + } + + /** + * used to return the appname of the set application + * @return string the name of your application + */ + function getAppName() { + return $this->query('AppName'); + } +} diff --git a/lib/private/appframework/http/dispatcher.php b/lib/private/appframework/http/dispatcher.php new file mode 100644 index 00000000000..ea57a6860cc --- /dev/null +++ b/lib/private/appframework/http/dispatcher.php @@ -0,0 +1,100 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use \OC\AppFramework\Controller\Controller; +use \OC\AppFramework\Middleware\MiddlewareDispatcher; + + +/** + * Class to dispatch the request to the middleware dispatcher + */ +class Dispatcher { + + private $middlewareDispatcher; + private $protocol; + + + /** + * @param Http $protocol the http protocol with contains all status headers + * @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which + * runs the middleware + */ + public function __construct(Http $protocol, + MiddlewareDispatcher $middlewareDispatcher) { + $this->protocol = $protocol; + $this->middlewareDispatcher = $middlewareDispatcher; + } + + + /** + * Handles a request and calls the dispatcher on the controller + * @param Controller $controller the controller which will be called + * @param string $methodName the method name which will be called on + * the controller + * @return array $array[0] contains a string with the http main header, + * $array[1] contains headers in the form: $key => value, $array[2] contains + * the response output + */ + public function dispatch(Controller $controller, $methodName) { + $out = array(null, array(), null); + + try { + + $this->middlewareDispatcher->beforeController($controller, + $methodName); + $response = $controller->$methodName(); + + // if an exception appears, the middleware checks if it can handle the + // exception and creates a response. If no response is created, it is + // assumed that theres no middleware who can handle it and the error is + // thrown again + } catch(\Exception $exception){ + $response = $this->middlewareDispatcher->afterException( + $controller, $methodName, $exception); + if (is_null($response)) { + throw $exception; + } + } + + $response = $this->middlewareDispatcher->afterController( + $controller, $methodName, $response); + + // get the output which should be printed and run the after output + // middleware to modify the response + $output = $response->render(); + $out[2] = $this->middlewareDispatcher->beforeOutput( + $controller, $methodName, $output); + + // depending on the cache object the headers need to be changed + $out[0] = $this->protocol->getStatusHeader($response->getStatus(), + $response->getLastModified(), $response->getETag()); + $out[1] = $response->getHeaders(); + + return $out; + } + + +} diff --git a/lib/private/appframework/http/downloadresponse.php b/lib/private/appframework/http/downloadresponse.php new file mode 100644 index 00000000000..67b9542dba6 --- /dev/null +++ b/lib/private/appframework/http/downloadresponse.php @@ -0,0 +1,50 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +/** + * Prompts the user to download the a file + */ +class DownloadResponse extends \OCP\AppFramework\Http\Response { + + private $filename; + private $contentType; + + /** + * Creates a response that prompts the user to download the file + * @param string $filename the name that the downloaded file should have + * @param string $contentType the mimetype that the downloaded file should have + */ + public function __construct($filename, $contentType) { + $this->filename = $filename; + $this->contentType = $contentType; + + $this->addHeader('Content-Disposition', 'attachment; filename="' . $filename . '"'); + $this->addHeader('Content-Type', $contentType); + } + + +} diff --git a/lib/private/appframework/http/http.php b/lib/private/appframework/http/http.php new file mode 100644 index 00000000000..e00dc9cdc4a --- /dev/null +++ b/lib/private/appframework/http/http.php @@ -0,0 +1,148 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +class Http extends \OCP\AppFramework\Http\Http{ + + private $server; + private $protocolVersion; + protected $headers; + + /** + * @param $_SERVER $server + * @param string $protocolVersion the http version to use defaults to HTTP/1.1 + */ + public function __construct($server, $protocolVersion='HTTP/1.1') { + $this->server = $server; + $this->protocolVersion = $protocolVersion; + + $this->headers = array( + self::STATUS_CONTINUE => 'Continue', + self::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols', + self::STATUS_PROCESSING => 'Processing', + self::STATUS_OK => 'OK', + self::STATUS_CREATED => 'Created', + self::STATUS_ACCEPTED => 'Accepted', + self::STATUS_NON_AUTHORATIVE_INFORMATION => 'Non-Authorative Information', + self::STATUS_NO_CONTENT => 'No Content', + self::STATUS_RESET_CONTENT => 'Reset Content', + self::STATUS_PARTIAL_CONTENT => 'Partial Content', + self::STATUS_MULTI_STATUS => 'Multi-Status', // RFC 4918 + self::STATUS_ALREADY_REPORTED => 'Already Reported', // RFC 5842 + self::STATUS_IM_USED => 'IM Used', // RFC 3229 + self::STATUS_MULTIPLE_CHOICES => 'Multiple Choices', + self::STATUS_MOVED_PERMANENTLY => 'Moved Permanently', + self::STATUS_FOUND => 'Found', + self::STATUS_SEE_OTHER => 'See Other', + self::STATUS_NOT_MODIFIED => 'Not Modified', + self::STATUS_USE_PROXY => 'Use Proxy', + self::STATUS_RESERVED => 'Reserved', + self::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect', + self::STATUS_BAD_REQUEST => 'Bad request', + self::STATUS_UNAUTHORIZED => 'Unauthorized', + self::STATUS_PAYMENT_REQUIRED => 'Payment Required', + self::STATUS_FORBIDDEN => 'Forbidden', + self::STATUS_NOT_FOUND => 'Not Found', + self::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed', + self::STATUS_NOT_ACCEPTABLE => 'Not Acceptable', + self::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required', + self::STATUS_REQUEST_TIMEOUT => 'Request Timeout', + self::STATUS_CONFLICT => 'Conflict', + self::STATUS_GONE => 'Gone', + self::STATUS_LENGTH_REQUIRED => 'Length Required', + self::STATUS_PRECONDITION_FAILED => 'Precondition failed', + self::STATUS_REQUEST_ENTITY_TOO_LARGE => 'Request Entity Too Large', + self::STATUS_REQUEST_URI_TOO_LONG => 'Request-URI Too Long', + self::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type', + self::STATUS_REQUEST_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable', + self::STATUS_EXPECTATION_FAILED => 'Expectation Failed', + self::STATUS_IM_A_TEAPOT => 'I\'m a teapot', // RFC 2324 + self::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', // RFC 4918 + self::STATUS_LOCKED => 'Locked', // RFC 4918 + self::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', // RFC 4918 + self::STATUS_UPGRADE_REQUIRED => 'Upgrade required', + self::STATUS_PRECONDITION_REQUIRED => 'Precondition required', // draft-nottingham-http-new-status + self::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', // draft-nottingham-http-new-status + self::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', // draft-nottingham-http-new-status + self::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error', + self::STATUS_NOT_IMPLEMENTED => 'Not Implemented', + self::STATUS_BAD_GATEWAY => 'Bad Gateway', + self::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable', + self::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout', + self::STATUS_HTTP_VERSION_NOT_SUPPORTED => 'HTTP Version not supported', + self::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates', + self::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', // RFC 4918 + self::STATUS_LOOP_DETECTED => 'Loop Detected', // RFC 5842 + self::STATUS_BANDWIDTH_LIMIT_EXCEEDED => 'Bandwidth Limit Exceeded', // non-standard + self::STATUS_NOT_EXTENDED => 'Not extended', + self::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', // draft-nottingham-http-new-status + ); + } + + + /** + * Gets the correct header + * @param Http::CONSTANT $status the constant from the Http class + * @param \DateTime $lastModified formatted last modified date + * @param string $Etag the etag + */ + public function getStatusHeader($status, \DateTime $lastModified=null, + $ETag=null) { + + if(!is_null($lastModified)) { + $lastModified = $lastModified->format(\DateTime::RFC2822); + } + + // if etag or lastmodified have not changed, return a not modified + if ((isset($this->server['HTTP_IF_NONE_MATCH']) + && trim($this->server['HTTP_IF_NONE_MATCH']) === $ETag) + + || + + (isset($this->server['HTTP_IF_MODIFIED_SINCE']) + && trim($this->server['HTTP_IF_MODIFIED_SINCE']) === + $lastModified)) { + + $status = self::STATUS_NOT_MODIFIED; + } + + // we have one change currently for the http 1.0 header that differs + // from 1.1: STATUS_TEMPORARY_REDIRECT should be STATUS_FOUND + // if this differs any more, we want to create childclasses for this + if($status === self::STATUS_TEMPORARY_REDIRECT + && $this->protocolVersion === 'HTTP/1.0') { + + $status = self::STATUS_FOUND; + } + + return $this->protocolVersion . ' ' . $status . ' ' . + $this->headers[$status]; + } + + +} + + diff --git a/lib/private/appframework/http/redirectresponse.php b/lib/private/appframework/http/redirectresponse.php new file mode 100644 index 00000000000..688447f1618 --- /dev/null +++ b/lib/private/appframework/http/redirectresponse.php @@ -0,0 +1,56 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use OCP\AppFramework\Http\Response; + + +/** + * Redirects to a different URL + */ +class RedirectResponse extends Response { + + private $redirectURL; + + /** + * Creates a response that redirects to a url + * @param string $redirectURL the url to redirect to + */ + public function __construct($redirectURL) { + $this->redirectURL = $redirectURL; + $this->setStatus(Http::STATUS_TEMPORARY_REDIRECT); + $this->addHeader('Location', $redirectURL); + } + + + /** + * @return string the url to redirect + */ + public function getRedirectURL() { + return $this->redirectURL; + } + + +} diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php new file mode 100644 index 00000000000..34605acdfea --- /dev/null +++ b/lib/private/appframework/http/request.php @@ -0,0 +1,307 @@ +. + * + */ + +namespace OC\AppFramework\Http; + +use OCP\IRequest; + +/** + * Class for accessing variables in the request. + * This class provides an immutable object with request variables. + */ + +class Request implements \ArrayAccess, \Countable, IRequest { + + protected $items = array(); + protected $allowedKeys = array( + 'get', + 'post', + 'files', + 'server', + 'env', + 'cookies', + 'urlParams', + 'params', + 'parameters', + 'method' + ); + + /** + * @param array $vars An associative array with the following optional values: + * @param array 'params' the parsed json array + * @param array 'urlParams' the parameters which were matched from the URL + * @param array 'get' the $_GET array + * @param array 'post' the $_POST array + * @param array 'files' the $_FILES array + * @param array 'server' the $_SERVER array + * @param array 'env' the $_ENV array + * @param array 'session' the $_SESSION array + * @param array 'cookies' the $_COOKIE array + * @param string 'method' the request method (GET, POST etc) + * @see http://www.php.net/manual/en/reserved.variables.php + */ + public function __construct(array $vars=array()) { + + foreach($this->allowedKeys as $name) { + $this->items[$name] = isset($vars[$name]) + ? $vars[$name] + : array(); + } + + $this->items['parameters'] = array_merge( + $this->items['params'], + $this->items['get'], + $this->items['post'], + $this->items['urlParams'] + ); + + } + + // Countable method. + public function count() { + return count(array_keys($this->items['parameters'])); + } + + /** + * ArrayAccess methods + * + * Gives access to the combined GET, POST and urlParams arrays + * + * Examples: + * + * $var = $request['myvar']; + * + * or + * + * if(!isset($request['myvar']) { + * // Do something + * } + * + * $request['myvar'] = 'something'; // This throws an exception. + * + * @param string $offset The key to lookup + * @return string|null + */ + public function offsetExists($offset) { + return isset($this->items['parameters'][$offset]); + } + + /** + * @see offsetExists + */ + public function offsetGet($offset) { + return isset($this->items['parameters'][$offset]) + ? $this->items['parameters'][$offset] + : null; + } + + /** + * @see offsetExists + */ + public function offsetSet($offset, $value) { + throw new \RuntimeException('You cannot change the contents of the request object'); + } + + /** + * @see offsetExists + */ + public function offsetUnset($offset) { + throw new \RuntimeException('You cannot change the contents of the request object'); + } + + // Magic property accessors + public function __set($name, $value) { + throw new \RuntimeException('You cannot change the contents of the request object'); + } + + /** + * Access request variables by method and name. + * Examples: + * + * $request->post['myvar']; // Only look for POST variables + * $request->myvar; or $request->{'myvar'}; or $request->{$myvar} + * Looks in the combined GET, POST and urlParams array. + * + * if($request->method !== 'POST') { + * throw new Exception('This function can only be invoked using POST'); + * } + * + * @param string $name The key to look for. + * @return mixed|null + */ + public function __get($name) { + switch($name) { + case 'get': + case 'post': + case 'files': + case 'server': + case 'env': + case 'cookies': + case 'parameters': + case 'params': + case 'urlParams': + return isset($this->items[$name]) + ? $this->items[$name] + : null; + break; + case 'method': + return $this->items['method']; + break; + default; + return isset($this[$name]) + ? $this[$name] + : null; + break; + } + } + + + public function __isset($name) { + return isset($this->items['parameters'][$name]); + } + + + public function __unset($id) { + throw new \RunTimeException('You cannot change the contents of the request object'); + } + + /** + * Returns the value for a specific http header. + * + * This method returns null if the header did not exist. + * + * @param string $name + * @return string + */ + public function getHeader($name) { + + $name = strtoupper(str_replace(array('-'),array('_'),$name)); + if (isset($this->server['HTTP_' . $name])) { + return $this->server['HTTP_' . $name]; + } + + // There's a few headers that seem to end up in the top-level + // server array. + switch($name) { + case 'CONTENT_TYPE' : + case 'CONTENT_LENGTH' : + if (isset($this->server[$name])) { + return $this->server[$name]; + } + break; + + } + + return null; + } + + /** + * Lets you access post and get parameters by the index + * In case of json requests the encoded json body is accessed + * + * @param string $key the key which you want to access in the URL Parameter + * placeholder, $_POST or $_GET array. + * The priority how they're returned is the following: + * 1. URL parameters + * 2. POST parameters + * 3. GET parameters + * @param mixed $default If the key is not found, this value will be returned + * @return mixed the content of the array + */ + public function getParam($key, $default = null) { + return isset($this->parameters[$key]) + ? $this->parameters[$key] + : $default; + } + + /** + * Returns all params that were received, be it from the request + * (as GET or POST) or throuh the URL by the route + * @return array the array with all parameters + */ + public function getParams() { + return $this->parameters; + } + + /** + * Returns the method of the request + * @return string the method of the request (POST, GET, etc) + */ + public function getMethod() { + return $this->method; + } + + /** + * Shortcut for accessing an uploaded file through the $_FILES array + * @param string $key the key that will be taken from the $_FILES array + * @return array the file in the $_FILES element + */ + public function getUploadedFile($key) { + return isset($this->files[$key]) ? $this->files[$key] : null; + } + + /** + * Shortcut for getting env variables + * @param string $key the key that will be taken from the $_ENV array + * @return array the value in the $_ENV element + */ + public function getEnv($key) { + return isset($this->env[$key]) ? $this->env[$key] : null; + } + + /** + * Shortcut for getting cookie variables + * @param string $key the key that will be taken from the $_COOKIE array + * @return array the value in the $_COOKIE element + */ + function getCookie($key) { + return isset($this->cookies[$key]) ? $this->cookies[$key] : null; + } + + /** + * Returns the request body content. + * + * @param Boolean $asResource If true, a resource will be returned + * + * @return string|resource The request body content or a resource to read the body stream. + * + * @throws \LogicException + */ + function getContent($asResource = false) { + return null; +// if (false === $this->content || (true === $asResource && null !== $this->content)) { +// throw new \LogicException('getContent() can only be called once when using the resource return type.'); +// } +// +// if (true === $asResource) { +// $this->content = false; +// +// return fopen('php://input', 'rb'); +// } +// +// if (null === $this->content) { +// $this->content = file_get_contents('php://input'); +// } +// +// return $this->content; + } +} diff --git a/lib/private/appframework/middleware/middleware.php b/lib/private/appframework/middleware/middleware.php new file mode 100644 index 00000000000..b12c03c3eb8 --- /dev/null +++ b/lib/private/appframework/middleware/middleware.php @@ -0,0 +1,100 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware; + +use OCP\AppFramework\Http\Response; + + +/** + * Middleware is used to provide hooks before or after controller methods and + * deal with possible exceptions raised in the controller methods. + * They're modeled after Django's middleware system: + * https://docs.djangoproject.com/en/dev/topics/http/middleware/ + */ +abstract class Middleware { + + + /** + * This is being run in normal order before the controller is being + * called which allows several modifications and checks + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + */ + public function beforeController($controller, $methodName){ + + } + + + /** + * This is being run when either the beforeController method or the + * controller method itself is throwing an exception. The middleware is + * asked in reverse order to handle the exception and to return a response. + * If the response is null, it is assumed that the exception could not be + * handled and the error will be thrown again + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param \Exception $exception the thrown exception + * @throws \Exception the passed in exception if it cant handle it + * @return Response a Response object in case that the exception was handled + */ + public function afterException($controller, $methodName, \Exception $exception){ + throw $exception; + } + + + /** + * This is being run after a successful controllermethod call and allows + * the manipulation of a Response object. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param Response $response the generated response from the controller + * @return Response a Response object + */ + public function afterController($controller, $methodName, Response $response){ + return $response; + } + + + /** + * This is being run after the response object has been rendered and + * allows the manipulation of the output. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param string $output the generated output from a response + * @return string the output that should be printed + */ + public function beforeOutput($controller, $methodName, $output){ + return $output; + } + +} diff --git a/lib/private/appframework/middleware/middlewaredispatcher.php b/lib/private/appframework/middleware/middlewaredispatcher.php new file mode 100644 index 00000000000..70ab108e6b8 --- /dev/null +++ b/lib/private/appframework/middleware/middlewaredispatcher.php @@ -0,0 +1,159 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware; + +use OC\AppFramework\Controller\Controller; +use OCP\AppFramework\Http\Response; + + +/** + * This class is used to store and run all the middleware in correct order + */ +class MiddlewareDispatcher { + + /** + * @var array array containing all the middlewares + */ + private $middlewares; + + /** + * @var int counter which tells us what middlware was executed once an + * exception occurs + */ + private $middlewareCounter; + + + /** + * Constructor + */ + public function __construct(){ + $this->middlewares = array(); + $this->middlewareCounter = 0; + } + + + /** + * Adds a new middleware + * @param Middleware $middleware the middleware which will be added + */ + public function registerMiddleware(Middleware $middleWare){ + array_push($this->middlewares, $middleWare); + } + + + /** + * returns an array with all middleware elements + * @return array the middlewares + */ + public function getMiddlewares(){ + return $this->middlewares; + } + + + /** + * This is being run in normal order before the controller is being + * called which allows several modifications and checks + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + */ + public function beforeController(Controller $controller, $methodName){ + // we need to count so that we know which middlewares we have to ask in + // case theres an exception + for($i=0; $imiddlewares); $i++){ + $this->middlewareCounter++; + $middleware = $this->middlewares[$i]; + $middleware->beforeController($controller, $methodName); + } + } + + + /** + * This is being run when either the beforeController method or the + * controller method itself is throwing an exception. The middleware is asked + * in reverse order to handle the exception and to return a response. + * If the response is null, it is assumed that the exception could not be + * handled and the error will be thrown again + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param \Exception $exception the thrown exception + * @return Response a Response object if the middleware can handle the + * exception + * @throws \Exception the passed in exception if it cant handle it + */ + public function afterException(Controller $controller, $methodName, \Exception $exception){ + for($i=$this->middlewareCounter-1; $i>=0; $i--){ + $middleware = $this->middlewares[$i]; + try { + return $middleware->afterException($controller, $methodName, $exception); + } catch(\Exception $exception){ + continue; + } + } + throw $exception; + } + + + /** + * This is being run after a successful controllermethod call and allows + * the manipulation of a Response object. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param Response $response the generated response from the controller + * @return Response a Response object + */ + public function afterController(Controller $controller, $methodName, Response $response){ + for($i=count($this->middlewares)-1; $i>=0; $i--){ + $middleware = $this->middlewares[$i]; + $response = $middleware->afterController($controller, $methodName, $response); + } + return $response; + } + + + /** + * This is being run after the response object has been rendered and + * allows the manipulation of the output. The middleware is run in reverse order + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param string $output the generated output from a response + * @return string the output that should be printed + */ + public function beforeOutput(Controller $controller, $methodName, $output){ + for($i=count($this->middlewares)-1; $i>=0; $i--){ + $middleware = $this->middlewares[$i]; + $output = $middleware->beforeOutput($controller, $methodName, $output); + } + return $output; + } + +} diff --git a/lib/private/appframework/middleware/security/securityexception.php b/lib/private/appframework/middleware/security/securityexception.php new file mode 100644 index 00000000000..b32a2769ff5 --- /dev/null +++ b/lib/private/appframework/middleware/security/securityexception.php @@ -0,0 +1,41 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware\Security; + + +/** + * Thrown when the security middleware encounters a security problem + */ +class SecurityException extends \Exception { + + /** + * @param string $msg the security error message + * @param bool $ajax true if it resulted because of an ajax request + */ + public function __construct($msg, $code = 0) { + parent::__construct($msg, $code); + } + +} diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php new file mode 100644 index 00000000000..4f1447e1afb --- /dev/null +++ b/lib/private/appframework/middleware/security/securitymiddleware.php @@ -0,0 +1,136 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware\Security; + +use OC\AppFramework\Controller\Controller; +use OC\AppFramework\Http\Http; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\RedirectResponse; +use OC\AppFramework\Utility\MethodAnnotationReader; +use OC\AppFramework\Middleware\Middleware; +use OC\AppFramework\Core\API; +use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http\JSONResponse; + + +/** + * Used to do all the authentication and checking stuff for a controller method + * It reads out the annotations of a controller method and checks which if + * security things should be checked and also handles errors in case a security + * check fails + */ +class SecurityMiddleware extends Middleware { + + private $api; + + /** + * @var \OC\AppFramework\Http\Request + */ + private $request; + + /** + * @param API $api an instance of the api + */ + public function __construct(API $api, Request $request){ + $this->api = $api; + $this->request = $request; + } + + + /** + * This runs all the security checks before a method call. The + * security checks are determined by inspecting the controller method + * annotations + * @param string/Controller $controller the controllername or string + * @param string $methodName the name of the method + * @throws SecurityException when a security check fails + */ + public function beforeController($controller, $methodName){ + + // get annotations from comments + $annotationReader = new MethodAnnotationReader($controller, $methodName); + + // this will set the current navigation entry of the app, use this only + // for normal HTML requests and not for AJAX requests + $this->api->activateNavigationEntry(); + + // security checks + $isPublicPage = $annotationReader->hasAnnotation('PublicPage'); + if(!$isPublicPage) { + if(!$this->api->isLoggedIn()) { + throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); + } + + if(!$annotationReader->hasAnnotation('NoAdminRequired')) { + if(!$this->api->isAdminUser($this->api->getUserId())) { + throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); + } + } + } + + if(!$annotationReader->hasAnnotation('NoCSRFRequired')) { + if(!$this->api->passesCSRFCheck()) { + throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); + } + } + + } + + + /** + * If an SecurityException is being caught, ajax requests return a JSON error + * response and non ajax requests redirect to the index + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @param \Exception $exception the thrown exception + * @throws \Exception the passed in exception if it cant handle it + * @return Response a Response object or null in case that the exception could not be handled + */ + public function afterException($controller, $methodName, \Exception $exception){ + if($exception instanceof SecurityException){ + + if (stripos($this->request->getHeader('Accept'),'html')===false) { + + $response = new JSONResponse( + array('message' => $exception->getMessage()), + $exception->getCode() + ); + $this->api->log($exception->getMessage(), 'debug'); + } else { + + $url = $this->api->linkToAbsolute('index.php', ''); // TODO: replace with link to route + $response = new RedirectResponse($url); + $this->api->log($exception->getMessage(), 'debug'); + } + + return $response; + + } + + throw $exception; + } + +} diff --git a/lib/private/appframework/routing/routeactionhandler.php b/lib/private/appframework/routing/routeactionhandler.php new file mode 100644 index 00000000000..7fb56f14eab --- /dev/null +++ b/lib/private/appframework/routing/routeactionhandler.php @@ -0,0 +1,42 @@ +. + * + */ + +namespace OC\AppFramework\routing; + +use \OC\AppFramework\App; +use \OC\AppFramework\DependencyInjection\DIContainer; + +class RouteActionHandler { + private $controllerName; + private $actionName; + private $container; + + public function __construct(DIContainer $container, $controllerName, $actionName) { + $this->controllerName = $controllerName; + $this->actionName = $actionName; + $this->container = $container; + } + + public function __invoke($params) { + App::main($this->controllerName, $this->actionName, $params, $this->container); + } +} diff --git a/lib/private/appframework/routing/routeconfig.php b/lib/private/appframework/routing/routeconfig.php new file mode 100644 index 00000000000..53ab11bf2f5 --- /dev/null +++ b/lib/private/appframework/routing/routeconfig.php @@ -0,0 +1,186 @@ +. + * + */ + +namespace OC\AppFramework\routing; + +use OC\AppFramework\DependencyInjection\DIContainer; + +/** + * Class RouteConfig + * @package OC\AppFramework\routing + */ +class RouteConfig { + private $container; + private $router; + private $routes; + private $appName; + + /** + * @param \OC\AppFramework\DependencyInjection\DIContainer $container + * @param \OC_Router $router + * @param string $pathToYml + * @internal param $appName + */ + public function __construct(DIContainer $container, \OC_Router $router, $routes) { + $this->routes = $routes; + $this->container = $container; + $this->router = $router; + $this->appName = $container['AppName']; + } + + /** + * The routes and resource will be registered to the \OC_Router + */ + public function register() { + + // parse simple + $this->processSimpleRoutes($this->routes); + + // parse resources + $this->processResources($this->routes); + } + + /** + * Creates one route base on the give configuration + * @param $routes + * @throws \UnexpectedValueException + */ + private function processSimpleRoutes($routes) + { + $simpleRoutes = isset($routes['routes']) ? $routes['routes'] : array(); + foreach ($simpleRoutes as $simpleRoute) { + $name = $simpleRoute['name']; + $url = $simpleRoute['url']; + $verb = isset($simpleRoute['verb']) ? strtoupper($simpleRoute['verb']) : 'GET'; + + $split = explode('#', $name, 2); + if (count($split) != 2) { + throw new \UnexpectedValueException('Invalid route name'); + } + $controller = $split[0]; + $action = $split[1]; + + $controllerName = $this->buildControllerName($controller); + $actionName = $this->buildActionName($action); + + // register the route + $handler = new RouteActionHandler($this->container, $controllerName, $actionName); + $this->router->create($this->appName.'.'.$controller.'.'.$action, $url)->method($verb)->action($handler); + } + } + + /** + * For a given name and url restful routes are created: + * - index + * - show + * - new + * - create + * - update + * - destroy + * + * @param $routes + */ + private function processResources($routes) + { + // declaration of all restful actions + $actions = array( + array('name' => 'index', 'verb' => 'GET', 'on-collection' => true), + array('name' => 'show', 'verb' => 'GET'), + array('name' => 'create', 'verb' => 'POST', 'on-collection' => true), + array('name' => 'update', 'verb' => 'PUT'), + array('name' => 'destroy', 'verb' => 'DELETE'), + ); + + $resources = isset($routes['resources']) ? $routes['resources'] : array(); + foreach ($resources as $resource => $config) { + + // the url parameter used as id to the resource + $resourceId = $this->buildResourceId($resource); + foreach($actions as $action) { + $url = $config['url']; + $method = $action['name']; + $verb = isset($action['verb']) ? strtoupper($action['verb']) : 'GET'; + $collectionAction = isset($action['on-collection']) ? $action['on-collection'] : false; + if (!$collectionAction) { + $url = $url . '/' . $resourceId; + } + if (isset($action['url-postfix'])) { + $url = $url . '/' . $action['url-postfix']; + } + + $controller = $resource; + + $controllerName = $this->buildControllerName($controller); + $actionName = $this->buildActionName($method); + + $routeName = $this->appName . '.' . strtolower($resource) . '.' . strtolower($method); + + $this->router->create($routeName, $url)->method($verb)->action( + new RouteActionHandler($this->container, $controllerName, $actionName) + ); + } + } + } + + /** + * Based on a given route name the controller name is generated + * @param $controller + * @return string + */ + private function buildControllerName($controller) + { + return $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller'; + } + + /** + * Based on the action part of the route name the controller method name is generated + * @param $action + * @return string + */ + private function buildActionName($action) { + return $this->underScoreToCamelCase($action); + } + + /** + * Generates the id used in the url part o the route url + * @param $resource + * @return string + */ + private function buildResourceId($resource) { + return '{'.$this->underScoreToCamelCase(rtrim($resource, 's')).'Id}'; + } + + /** + * Underscored strings are converted to camel case strings + * @param $str string + * @return string + */ + private function underScoreToCamelCase($str) { + $pattern = "/_[a-z]?/"; + return preg_replace_callback( + $pattern, + function ($matches) { + return strtoupper(ltrim($matches[0], "_")); + }, + $str); + } +} diff --git a/lib/private/appframework/utility/methodannotationreader.php b/lib/private/appframework/utility/methodannotationreader.php new file mode 100644 index 00000000000..42060a08529 --- /dev/null +++ b/lib/private/appframework/utility/methodannotationreader.php @@ -0,0 +1,61 @@ +. + * + */ + + +namespace OC\AppFramework\Utility; + + +/** + * Reads and parses annotations from doc comments + */ +class MethodAnnotationReader { + + private $annotations; + + /** + * @param object $object an object or classname + * @param string $method the method which we want to inspect for annotations + */ + public function __construct($object, $method){ + $this->annotations = array(); + + $reflection = new \ReflectionMethod($object, $method); + $docs = $reflection->getDocComment(); + + // extract everything prefixed by @ and first letter uppercase + preg_match_all('/@([A-Z]\w+)/', $docs, $matches); + $this->annotations = $matches[1]; + } + + + /** + * Check if a method contains an annotation + * @param string $name the name of the annotation + * @return bool true if the annotation is found + */ + public function hasAnnotation($name){ + return in_array($name, $this->annotations); + } + + +} diff --git a/lib/private/appframework/utility/simplecontainer.php b/lib/private/appframework/utility/simplecontainer.php new file mode 100644 index 00000000000..7e4db63bde5 --- /dev/null +++ b/lib/private/appframework/utility/simplecontainer.php @@ -0,0 +1,44 @@ +offsetGet($name); + } + + function registerParameter($name, $value) + { + $this[$name] = $value; + } + + /** + * The given closure is call the first time the given service is queried. + * The closure has to return the instance for the given service. + * Created instance will be cached in case $shared is true. + * + * @param string $name name of the service to register another backend for + * @param callable $closure the closure to be called on service creation + */ + function registerService($name, \Closure $closure, $shared = true) + { + if ($shared) { + $this[$name] = \Pimple::share($closure); + } else { + $this[$name] = $closure; + } + } +} diff --git a/lib/private/appframework/utility/timefactory.php b/lib/private/appframework/utility/timefactory.php new file mode 100644 index 00000000000..2c3dd6cf5e3 --- /dev/null +++ b/lib/private/appframework/utility/timefactory.php @@ -0,0 +1,42 @@ +. + * + */ + + +namespace OC\AppFramework\Utility; + + +/** + * Needed to mock calls to time() + */ +class TimeFactory { + + + /** + * @return int the result of a call to time() + */ + public function getTime() { + return time(); + } + + +} diff --git a/lib/private/archive.php b/lib/private/archive.php new file mode 100644 index 00000000000..85bfae57295 --- /dev/null +++ b/lib/private/archive.php @@ -0,0 +1,137 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +abstract class OC_Archive{ + /** + * open any of the supported archive types + * @param string path + * @return OC_Archive + */ + public static function open($path) { + $ext=substr($path, strrpos($path, '.')); + switch($ext) { + case '.zip': + return new OC_Archive_ZIP($path); + case '.gz': + case '.bz': + case '.bz2': + if(strpos($path, '.tar.')) { + return new OC_Archive_TAR($path); + } + break; + case '.tgz': + return new OC_Archive_TAR($path); + } + } + + abstract function __construct($source); + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + abstract function addFolder($path); + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + abstract function addFile($path, $source=''); + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + abstract function rename($source, $dest); + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + abstract function filesize($path); + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + abstract function mtime($path); + /** + * get the files in a folder + * @param path + * @return array + */ + abstract function getFolder($path); + /** + * get all files in the archive + * @return array + */ + abstract function getFiles(); + /** + * get the content of a file + * @param string path + * @return string + */ + abstract function getFile($path); + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + abstract function extractFile($path, $dest); + /** + * extract the archive + * @param string path + * @param string dest + * @return bool + */ + abstract function extract($dest); + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + abstract function fileExists($path); + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + abstract function remove($path); + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + abstract function getStream($path, $mode); + /** + * add a folder and all its content + * @param string $path + * @param string source + * @return bool + */ + function addRecursive($path, $source) { + $dh = opendir($source); + if(is_resource($dh)) { + $this->addFolder($path); + while (($file = readdir($dh)) !== false) { + if($file=='.' or $file=='..') { + continue; + } + if(is_dir($source.'/'.$file)) { + $this->addRecursive($path.'/'.$file, $source.'/'.$file); + }else{ + $this->addFile($path.'/'.$file, $source.'/'.$file); + } + } + } + } +} diff --git a/lib/private/archive/tar.php b/lib/private/archive/tar.php new file mode 100644 index 00000000000..a1c0535b1c3 --- /dev/null +++ b/lib/private/archive/tar.php @@ -0,0 +1,339 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once OC::$THIRDPARTYROOT . '/3rdparty/Archive/Tar.php'; + +class OC_Archive_TAR extends OC_Archive{ + const PLAIN=0; + const GZIP=1; + const BZIP=2; + + private $fileList; + private $cachedHeaders; + + /** + * @var Archive_Tar tar + */ + private $tar=null; + private $path; + + function __construct($source) { + $types=array(null, 'gz', 'bz'); + $this->path=$source; + $this->tar=new Archive_Tar($source, $types[self::getTarType($source)]); + } + + /** + * try to detect the type of tar compression + * @param string file + * @return str + */ + static public function getTarType($file) { + if(strpos($file, '.')) { + $extension=substr($file, strrpos($file, '.')); + switch($extension) { + case 'gz': + case 'tgz': + return self::GZIP; + case 'bz': + case 'bz2': + return self::BZIP; + default: + return self::PLAIN; + } + }else{ + return self::PLAIN; + } + } + + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + function addFolder($path) { + $tmpBase=OC_Helper::tmpFolder(); + if(substr($path, -1, 1)!='/') { + $path.='/'; + } + if($this->fileExists($path)) { + return false; + } + $parts=explode('/', $path); + $folder=$tmpBase; + foreach($parts as $part) { + $folder.='/'.$part; + if(!is_dir($folder)) { + mkdir($folder); + } + } + $result=$this->tar->addModify(array($tmpBase.$path), '', $tmpBase); + rmdir($tmpBase.$path); + $this->fileList=false; + $this->cachedHeaders=false; + return $result; + } + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + function addFile($path, $source='') { + if($this->fileExists($path)) { + $this->remove($path); + } + if($source and $source[0]=='/' and file_exists($source)) { + $header=array(); + $dummy=''; + $this->tar->_openAppend(); + $result=$this->tar->_addfile($source, $header, $dummy, $dummy, $path); + }else{ + $result=$this->tar->addString($path, $source); + } + $this->fileList=false; + $this->cachedHeaders=false; + return $result; + } + + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + function rename($source, $dest) { + //no proper way to delete, rename entire archive, rename file and remake archive + $tmp=OCP\Files::tmpFolder(); + $this->tar->extract($tmp); + rename($tmp.$source, $tmp.$dest); + $this->tar=null; + unlink($this->path); + $types=array(null, 'gz', 'bz'); + $this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]); + $this->tar->createModify(array($tmp), '', $tmp.'/'); + $this->fileList=false; + $this->cachedHeaders=false; + return true; + } + + private function getHeader($file) { + if ( ! $this->cachedHeaders ) { + $this->cachedHeaders = $this->tar->listContent(); + } + foreach($this->cachedHeaders as $header) { + if( $file == $header['filename'] + or $file.'/' == $header['filename'] + or '/'.$file.'/' == $header['filename'] + or '/'.$file == $header['filename']) { + return $header; + } + } + return null; + } + + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + function filesize($path) { + $stat=$this->getHeader($path); + return $stat['size']; + } + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + function mtime($path) { + $stat=$this->getHeader($path); + return $stat['mtime']; + } + + /** + * get the files in a folder + * @param path + * @return array + */ + function getFolder($path) { + $files=$this->getFiles(); + $folderContent=array(); + $pathLength=strlen($path); + foreach($files as $file) { + if($file[0]=='/') { + $file=substr($file, 1); + } + if(substr($file, 0, $pathLength)==$path and $file!=$path) { + $result=substr($file, $pathLength); + if($pos=strpos($result, '/')) { + $result=substr($result, 0, $pos+1); + } + if(array_search($result, $folderContent)===false) { + $folderContent[]=$result; + } + } + } + return $folderContent; + } + /** + * get all files in the archive + * @return array + */ + function getFiles() { + if($this->fileList) { + return $this->fileList; + } + if ( ! $this->cachedHeaders ) { + $this->cachedHeaders = $this->tar->listContent(); + } + $files=array(); + foreach($this->cachedHeaders as $header) { + $files[]=$header['filename']; + } + $this->fileList=$files; + return $files; + } + /** + * get the content of a file + * @param string path + * @return string + */ + function getFile($path) { + return $this->tar->extractInString($path); + } + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + function extractFile($path, $dest) { + $tmp=OCP\Files::tmpFolder(); + if(!$this->fileExists($path)) { + return false; + } + if($this->fileExists('/'.$path)) { + $success=$this->tar->extractList(array('/'.$path), $tmp); + }else{ + $success=$this->tar->extractList(array($path), $tmp); + } + if($success) { + rename($tmp.$path, $dest); + } + OCP\Files::rmdirr($tmp); + return $success; + } + /** + * extract the archive + * @param string path + * @param string dest + * @return bool + */ + function extract($dest) { + return $this->tar->extract($dest); + } + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + function fileExists($path) { + $files=$this->getFiles(); + if((array_search($path, $files)!==false) or (array_search($path.'/', $files)!==false)) { + return true; + }else{ + $folderPath=$path; + if(substr($folderPath, -1, 1)!='/') { + $folderPath.='/'; + } + $pathLength=strlen($folderPath); + foreach($files as $file) { + if(strlen($file)>$pathLength and substr($file, 0, $pathLength)==$folderPath) { + return true; + } + } + } + if($path[0]!='/') {//not all programs agree on the use of a leading / + return $this->fileExists('/'.$path); + }else{ + return false; + } + } + + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + function remove($path) { + if(!$this->fileExists($path)) { + return false; + } + $this->fileList=false; + $this->cachedHeaders=false; + //no proper way to delete, extract entire archive, delete file and remake archive + $tmp=OCP\Files::tmpFolder(); + $this->tar->extract($tmp); + OCP\Files::rmdirr($tmp.$path); + $this->tar=null; + unlink($this->path); + $this->reopen(); + $this->tar->createModify(array($tmp), '', $tmp); + return true; + } + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + function getStream($path, $mode) { + if(strrpos($path, '.')!==false) { + $ext=substr($path, strrpos($path, '.')); + }else{ + $ext=''; + } + $tmpFile=OCP\Files::tmpFile($ext); + if($this->fileExists($path)) { + $this->extractFile($path, $tmpFile); + }elseif($mode=='r' or $mode=='rb') { + return false; + } + if($mode=='r' or $mode=='rb') { + return fopen($tmpFile, $mode); + }else{ + \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile, $mode); + } + } + + private static $tempFiles=array(); + /** + * write back temporary files + */ + function writeBack($tmpFile) { + if(isset(self::$tempFiles[$tmpFile])) { + $this->addFile(self::$tempFiles[$tmpFile], $tmpFile); + unlink($tmpFile); + } + } + + /** + * reopen the archive to ensure everything is written + */ + private function reopen() { + if($this->tar) { + $this->tar->_close(); + $this->tar=null; + } + $types=array(null, 'gz', 'bz'); + $this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]); + } +} diff --git a/lib/private/archive/zip.php b/lib/private/archive/zip.php new file mode 100644 index 00000000000..8a866716a79 --- /dev/null +++ b/lib/private/archive/zip.php @@ -0,0 +1,201 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Archive_ZIP extends OC_Archive{ + /** + * @var ZipArchive zip + */ + private $zip=null; + private $path; + + function __construct($source) { + $this->path=$source; + $this->zip=new ZipArchive(); + if($this->zip->open($source, ZipArchive::CREATE)) { + }else{ + OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, OCP\Util::WARN); + } + } + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + function addFolder($path) { + return $this->zip->addEmptyDir($path); + } + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + function addFile($path, $source='') { + if($source and $source[0]=='/' and file_exists($source)) { + $result=$this->zip->addFile($source, $path); + }else{ + $result=$this->zip->addFromString($path, $source); + } + if($result) { + $this->zip->close();//close and reopen to save the zip + $this->zip->open($this->path); + } + return $result; + } + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + function rename($source, $dest) { + $source=$this->stripPath($source); + $dest=$this->stripPath($dest); + $this->zip->renameName($source, $dest); + } + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + function filesize($path) { + $stat=$this->zip->statName($path); + return $stat['size']; + } + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + function mtime($path) { + return filemtime($this->path); + } + /** + * get the files in a folder + * @param path + * @return array + */ + function getFolder($path) { + $files=$this->getFiles(); + $folderContent=array(); + $pathLength=strlen($path); + foreach($files as $file) { + if(substr($file, 0, $pathLength)==$path and $file!=$path) { + if(strrpos(substr($file, 0, -1), '/')<=$pathLength) { + $folderContent[]=substr($file, $pathLength); + } + } + } + return $folderContent; + } + /** + * get all files in the archive + * @return array + */ + function getFiles() { + $fileCount=$this->zip->numFiles; + $files=array(); + for($i=0;$i<$fileCount;$i++) { + $files[]=$this->zip->getNameIndex($i); + } + return $files; + } + /** + * get the content of a file + * @param string path + * @return string + */ + function getFile($path) { + return $this->zip->getFromName($path); + } + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + function extractFile($path, $dest) { + $fp = $this->zip->getStream($path); + file_put_contents($dest, $fp); + } + /** + * extract the archive + * @param string path + * @param string dest + * @return bool + */ + function extract($dest) { + return $this->zip->extractTo($dest); + } + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + function fileExists($path) { + return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false); + } + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + function remove($path) { + if($this->fileExists($path.'/')) { + return $this->zip->deleteName($path.'/'); + }else{ + return $this->zip->deleteName($path); + } + } + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + function getStream($path, $mode) { + if($mode=='r' or $mode=='rb') { + return $this->zip->getStream($path); + } else { + //since we cant directly get a writable stream, + //make a temp copy of the file and put it back + //in the archive when the stream is closed + if(strrpos($path, '.')!==false) { + $ext=substr($path, strrpos($path, '.')); + }else{ + $ext=''; + } + $tmpFile=OCP\Files::tmpFile($ext); + \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); + if($this->fileExists($path)) { + $this->extractFile($path, $tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile, $mode); + } + } + + private static $tempFiles=array(); + /** + * write back temporary files + */ + function writeBack($tmpFile) { + if(isset(self::$tempFiles[$tmpFile])) { + $this->addFile(self::$tempFiles[$tmpFile], $tmpFile); + unlink($tmpFile); + } + } + + private function stripPath($path) { + if(!$path || $path[0]=='/') { + return substr($path, 1); + }else{ + return $path; + } + } +} diff --git a/lib/private/arrayparser.php b/lib/private/arrayparser.php new file mode 100644 index 00000000000..3bb394a5163 --- /dev/null +++ b/lib/private/arrayparser.php @@ -0,0 +1,189 @@ +. + * + */ + +namespace OC; + +class SyntaxException extends \Exception { +} + +class ArrayParser { + const TYPE_NUM = 1; + const TYPE_BOOL = 2; + const TYPE_STRING = 3; + const TYPE_ARRAY = 4; + + function parsePHP($string) { + $string = $this->stripPHPTags($string); + $string = $this->stripAssignAndReturn($string); + return $this->parse($string); + } + + function stripPHPTags($string) { + $string = trim($string); + if (substr($string, 0, 5) === '') { + $string = substr($string, 0, -2); + } + return $string; + } + + function stripAssignAndReturn($string) { + $string = trim($string); + if (substr($string, 0, 6) === 'return') { + $string = substr($string, 6); + } + if (substr($string, 0, 1) === '$') { + list(, $string) = explode('=', $string, 2); + } + return $string; + } + + function parse($string) { + $string = trim($string); + $string = trim($string, ';'); + switch ($this->getType($string)) { + case self::TYPE_NUM: + return $this->parseNum($string); + case self::TYPE_BOOL: + return $this->parseBool($string); + case self::TYPE_STRING: + return $this->parseString($string); + case self::TYPE_ARRAY: + return $this->parseArray($string); + } + return null; + } + + function getType($string) { + $string = strtolower($string); + $first = substr($string, 0, 1); + $last = substr($string, -1, 1); + $arrayFirst = substr($string, 0, 5); + if (($first === '"' or $first === "'") and ($last === '"' or $last === "'")) { + return self::TYPE_STRING; + } elseif ($string === 'false' or $string === 'true') { + return self::TYPE_BOOL; + } elseif ($arrayFirst === 'array' and $last === ')') { + return self::TYPE_ARRAY; + } else { + return self::TYPE_NUM; + } + } + + function parseString($string) { + return substr($string, 1, -1); + } + + function parseNum($string) { + return intval($string); + } + + function parseBool($string) { + $string = strtolower($string); + return $string === 'true'; + } + + function parseArray($string) { + $body = substr($string, 5); + $body = trim($body); + $body = substr($body, 1, -1); + $items = $this->splitArray($body); + $result = array(); + $lastKey = -1; + foreach ($items as $item) { + $item = trim($item); + if ($item) { + if (strpos($item, '=>')) { + list($key, $value) = explode('=>', $item, 2); + $key = $this->parse($key); + $value = $this->parse($value); + } else { + $key = ++$lastKey; + $value = $item; + } + + if (is_numeric($key)) { + $lastKey = $key; + } + $result[$key] = $value; + } + } + return $result; + } + + function splitArray($body) { + $inSingleQuote = false;//keep track if we are inside quotes + $inDoubleQuote = false; + $bracketDepth = 0;//keep track if we are inside brackets + $parts = array(); + $start = 0; + $escaped = false;//keep track if we are after an escape character + $skips = array();//keep track of the escape characters we need to remove from the result + if (substr($body, -1, 1) !== ',') { + $body .= ','; + } + for ($i = 0; $i < strlen($body); $i++) { + $char = substr($body, $i, 1); + if ($char === '\\') { + if ($escaped) { + array_unshift($skips, $i - 1); + } + $escaped = !$escaped; + } else { + if ($char === '"' and !$inSingleQuote) { + if ($escaped) { + array_unshift($skips, $i - 1); + } else { + $inDoubleQuote = !$inDoubleQuote; + } + } elseif ($char === "'" and !$inDoubleQuote) { + if ($escaped) { + array_unshift($skips, $i - 1); + } else { + $inSingleQuote = !$inSingleQuote; + } + } elseif (!$inDoubleQuote and !$inSingleQuote) { + if ($char === '(') { + $bracketDepth++; + } elseif ($char === ')') { + if ($bracketDepth <= 0) { + throw new SyntaxException; + } else { + $bracketDepth--; + } + } elseif ($bracketDepth === 0 and $char === ',') { + $part = substr($body, $start, $i - $start); + foreach ($skips as $skip) { + $part = substr($part, 0, $skip - $start) . substr($part, $skip - $start + 1); + } + $parts[] = $part; + $start = $i + 1; + $skips = array(); + } + } + $escaped = false; + } + } + return $parts; + } +} diff --git a/lib/private/avatar.php b/lib/private/avatar.php new file mode 100644 index 00000000000..f20980c364b --- /dev/null +++ b/lib/private/avatar.php @@ -0,0 +1,89 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * This class gets and sets users avatars. + */ + +class OC_Avatar { + + private $view; + + /** + * @brief constructor + * @param $user string user to do avatar-management with + */ + public function __construct ($user) { + $this->view = new \OC\Files\View('/'.$user); + } + + /** + * @brief get the users avatar + * @param $size integer size in px of the avatar, defaults to 64 + * @return boolean|\OC_Image containing the avatar or false if there's no image + */ + public function get ($size = 64) { + if ($this->view->file_exists('avatar.jpg')) { + $ext = 'jpg'; + } elseif ($this->view->file_exists('avatar.png')) { + $ext = 'png'; + } else { + return false; + } + + $avatar = new OC_Image(); + $avatar->loadFromData($this->view->file_get_contents('avatar.'.$ext)); + $avatar->resize($size); + return $avatar; + } + + /** + * @brief sets the users avatar + * @param $data mixed imagedata or path to set a new avatar + * @throws Exception if the provided file is not a jpg or png image + * @throws Exception if the provided image is not valid + * @throws \OC\NotSquareException if the image is not square + * @return void + */ + public function set ($data) { + if (\OC_App::isEnabled('files_encryption')) { + $l = \OC_L10N::get('lib'); + throw new \Exception($l->t("Custom profile pictures don't work with encryption yet")); + } + + $img = new OC_Image($data); + $type = substr($img->mimeType(), -3); + if ($type === 'peg') { $type = 'jpg'; } + if ($type !== 'jpg' && $type !== 'png') { + $l = \OC_L10N::get('lib'); + throw new \Exception($l->t("Unknown filetype")); + } + + if (!$img->valid()) { + $l = \OC_L10N::get('lib'); + throw new \Exception($l->t("Invalid image")); + } + + if (!($img->height() === $img->width())) { + throw new \OC\NotSquareException(); + } + + $this->view->unlink('avatar.jpg'); + $this->view->unlink('avatar.png'); + $this->view->file_put_contents('avatar.'.$type, $data); + } + + /** + * @brief remove the users avatar + * @return void + */ + public function remove () { + $this->view->unlink('avatar.jpg'); + $this->view->unlink('avatar.png'); + } +} diff --git a/lib/private/backgroundjob.php b/lib/private/backgroundjob.php new file mode 100644 index 00000000000..9619dcb732c --- /dev/null +++ b/lib/private/backgroundjob.php @@ -0,0 +1,52 @@ +. +* +*/ + +/** + * This class does the dirty work. + */ +class OC_BackgroundJob{ + /** + * @brief get the execution type of background jobs + * @return string + * + * This method returns the type how background jobs are executed. If the user + * did not select something, the type is ajax. + */ + public static function getExecutionType() { + return OC_Appconfig::getValue( 'core', 'backgroundjobs_mode', 'ajax' ); + } + + /** + * @brief sets the background jobs execution type + * @param $type execution type + * @return boolean + * + * This method sets the execution type of the background jobs. Possible types + * are "none", "ajax", "webcron", "cron" + */ + public static function setExecutionType( $type ) { + if( !in_array( $type, array('none', 'ajax', 'webcron', 'cron'))) { + return false; + } + return OC_Appconfig::setValue( 'core', 'backgroundjobs_mode', $type ); + } +} diff --git a/lib/private/backgroundjob/job.php b/lib/private/backgroundjob/job.php new file mode 100644 index 00000000000..49fbffbd684 --- /dev/null +++ b/lib/private/backgroundjob/job.php @@ -0,0 +1,49 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\BackgroundJob; + +abstract class Job { + protected $id; + protected $lastRun; + protected $argument; + + /** + * @param JobList $jobList + */ + public function execute($jobList) { + $jobList->setLastRun($this); + $this->run($this->argument); + } + + abstract protected function run($argument); + + public function setId($id) { + $this->id = $id; + } + + public function setLastRun($lastRun) { + $this->lastRun = $lastRun; + } + + public function setArgument($argument) { + $this->argument = $argument; + } + + public function getId() { + return $this->id; + } + + public function getLastRun() { + return $this->lastRun; + } + + public function getArgument() { + return $this->argument; + } +} diff --git a/lib/private/backgroundjob/joblist.php b/lib/private/backgroundjob/joblist.php new file mode 100644 index 00000000000..cc803dd9b5f --- /dev/null +++ b/lib/private/backgroundjob/joblist.php @@ -0,0 +1,172 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\BackgroundJob; + +/** + * Class QueuedJob + * + * create a background job that is to be executed once + * + * @package OC\BackgroundJob + */ +class JobList { + /** + * @param Job|string $job + * @param mixed $argument + */ + public function add($job, $argument = null) { + if (!$this->has($job, $argument)) { + if ($job instanceof Job) { + $class = get_class($job); + } else { + $class = $job; + } + $argument = json_encode($argument); + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)'); + $query->execute(array($class, $argument)); + } + } + + /** + * @param Job|string $job + * @param mixed $argument + */ + public function remove($job, $argument = null) { + if ($job instanceof Job) { + $class = get_class($job); + } else { + $class = $job; + } + if (!is_null($argument)) { + $argument = json_encode($argument); + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); + $query->execute(array($class, $argument)); + } else { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?'); + $query->execute(array($class)); + } + } + + /** + * check if a job is in the list + * + * @param $job + * @param mixed $argument + * @return bool + */ + public function has($job, $argument) { + if ($job instanceof Job) { + $class = get_class($job); + } else { + $class = $job; + } + $argument = json_encode($argument); + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); + $result = $query->execute(array($class, $argument)); + return (bool)$result->fetchRow(); + } + + /** + * get all jobs in the list + * + * @return Job[] + */ + public function getAll() { + $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`'); + $result = $query->execute(); + $jobs = array(); + while ($row = $result->fetchRow()) { + $jobs[] = $this->buildJob($row); + } + return $jobs; + } + + /** + * get the next job in the list + * + * @return Job + */ + public function getNext() { + $lastId = $this->getLastJob(); + $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1); + $result = $query->execute(array($lastId)); + if ($row = $result->fetchRow()) { + return $this->buildJob($row); + } else { + //begin at the start of the queue + $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1); + $result = $query->execute(); + if ($row = $result->fetchRow()) { + return $this->buildJob($row); + } else { + return null; //empty job list + } + } + } + + /** + * @param int $id + * @return Job + */ + public function getById($id) { + $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?'); + $result = $query->execute(array($id)); + if ($row = $result->fetchRow()) { + return $this->buildJob($row); + } else { + return null; + } + } + + /** + * get the job object from a row in the db + * + * @param array $row + * @return Job + */ + private function buildJob($row) { + $class = $row['class']; + /** + * @var Job $job + */ + $job = new $class(); + $job->setId($row['id']); + $job->setLastRun($row['last_run']); + $job->setArgument(json_decode($row['argument'])); + return $job; + } + + /** + * set the job that was last ran + * + * @param Job $job + */ + public function setLastJob($job) { + \OC_Appconfig::setValue('backgroundjob', 'lastjob', $job->getId()); + } + + /** + * get the id of the last ran job + * + * @return int + */ + public function getLastJob() { + return \OC_Appconfig::getValue('backgroundjob', 'lastjob', 0); + } + + /** + * set the lastRun of $job to now + * + * @param Job $job + */ + public function setLastRun($job) { + $query = \OC_DB::prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?'); + $query->execute(array(time(), $job->getId())); + } +} diff --git a/lib/private/backgroundjob/legacy/queuedjob.php b/lib/private/backgroundjob/legacy/queuedjob.php new file mode 100644 index 00000000000..2bc001103b8 --- /dev/null +++ b/lib/private/backgroundjob/legacy/queuedjob.php @@ -0,0 +1,18 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\BackgroundJob\Legacy; + +class QueuedJob extends \OC\BackgroundJob\QueuedJob { + public function run($argument) { + $class = $argument['klass']; + $method = $argument['method']; + $parameters = $argument['parameters']; + call_user_func(array($class, $method), $parameters); + } +} diff --git a/lib/private/backgroundjob/legacy/regularjob.php b/lib/private/backgroundjob/legacy/regularjob.php new file mode 100644 index 00000000000..d4cfa348cea --- /dev/null +++ b/lib/private/backgroundjob/legacy/regularjob.php @@ -0,0 +1,15 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\BackgroundJob\Legacy; + +class RegularJob extends \OC\BackgroundJob\Job { + public function run($argument) { + call_user_func($argument); + } +} diff --git a/lib/private/backgroundjob/queuedjob.php b/lib/private/backgroundjob/queuedjob.php new file mode 100644 index 00000000000..1714182820d --- /dev/null +++ b/lib/private/backgroundjob/queuedjob.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\BackgroundJob; + +/** + * Class QueuedJob + * + * create a background job that is to be executed once + * + * @package OC\BackgroundJob + */ +abstract class QueuedJob extends Job { + /** + * run the job, then remove it from the joblist + * + * @param JobList $jobList + */ + public function execute($jobList) { + $jobList->remove($this); + $this->run($this->argument); + } +} diff --git a/lib/private/backgroundjob/timedjob.php b/lib/private/backgroundjob/timedjob.php new file mode 100644 index 00000000000..ae9f33505ab --- /dev/null +++ b/lib/private/backgroundjob/timedjob.php @@ -0,0 +1,41 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\BackgroundJob; + +/** + * Class QueuedJob + * + * create a background job that is to be executed at an interval + * + * @package OC\BackgroundJob + */ +abstract class TimedJob extends Job { + protected $interval = 0; + + /** + * set the interval for the job + * + * @param int $interval + */ + public function setInterval($interval) { + $this->interval = $interval; + } + + /** + * run the job if + * + * @param JobList $jobList + */ + public function execute($jobList) { + if ((time() - $this->lastRun) > $this->interval) { + $jobList->setLastRun($this); + $this->run($this->argument); + } + } +} diff --git a/lib/private/cache.php b/lib/private/cache.php new file mode 100644 index 00000000000..a311f10a00f --- /dev/null +++ b/lib/private/cache.php @@ -0,0 +1,112 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +class Cache { + /** + * @var Cache $user_cache + */ + static protected $user_cache; + /** + * @var Cache $global_cache + */ + static protected $global_cache; + + /** + * get the global cache + * @return Cache + */ + static public function getGlobalCache() { + if (!self::$global_cache) { + self::$global_cache = new Cache\FileGlobal(); + } + return self::$global_cache; + } + + /** + * get the user cache + * @return Cache + */ + static public function getUserCache() { + if (!self::$user_cache) { + self::$user_cache = new Cache\File(); + } + return self::$user_cache; + } + + /** + * get a value from the user cache + * @param string $key + * @return mixed + */ + static public function get($key) { + $user_cache = self::getUserCache(); + return $user_cache->get($key); + } + + /** + * set a value in the user cache + * @param string $key + * @param mixed $value + * @param int $ttl + * @return bool + */ + static public function set($key, $value, $ttl=0) { + if (empty($key)) { + return false; + } + $user_cache = self::getUserCache(); + return $user_cache->set($key, $value, $ttl); + } + + /** + * check if a value is set in the user cache + * @param string $key + * @return bool + */ + static public function hasKey($key) { + $user_cache = self::getUserCache(); + return $user_cache->hasKey($key); + } + + /** + * remove an item from the user cache + * @param string $key + * @return bool + */ + static public function remove($key) { + $user_cache = self::getUserCache(); + return $user_cache->remove($key); + } + + /** + * clear the user cache of all entries starting with a prefix + * @param string $prefix (optional) + * @return bool + */ + static public function clear($prefix='') { + $user_cache = self::getUserCache(); + return $user_cache->clear($prefix); + } + + /** + * creates cache key based on the files given + * @param $files + * @return string + */ + static public function generateCacheKeyFromFiles($files) { + $key = ''; + sort($files); + foreach($files as $file) { + $stat = stat($file); + $key .= $file.$stat['mtime'].$stat['size']; + } + return md5($key); + } +} diff --git a/lib/private/cache/broker.php b/lib/private/cache/broker.php new file mode 100644 index 00000000000..9b7e837e1bc --- /dev/null +++ b/lib/private/cache/broker.php @@ -0,0 +1,63 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Cache; + +class Broker { + + /** + * @var \OC\Cache + */ + protected $fast_cache; + + /** + * @var \OC\Cache + */ + protected $slow_cache; + + public function __construct($fast_cache, $slow_cache) { + $this->fast_cache = $fast_cache; + $this->slow_cache = $slow_cache; + } + + public function get($key) { + if ($r = $this->fast_cache->get($key)) { + return $r; + } + return $this->slow_cache->get($key); + } + + public function set($key, $value, $ttl=0) { + if (!$this->fast_cache->set($key, $value, $ttl)) { + if ($this->fast_cache->hasKey($key)) { + $this->fast_cache->remove($key); + } + return $this->slow_cache->set($key, $value, $ttl); + } + return true; + } + + public function hasKey($key) { + if ($this->fast_cache->hasKey($key)) { + return true; + } + return $this->slow_cache->hasKey($key); + } + + public function remove($key) { + if ($this->fast_cache->remove($key)) { + return true; + } + return $this->slow_cache->remove($key); + } + + public function clear($prefix='') { + $this->fast_cache->clear($prefix); + $this->slow_cache->clear($prefix); + } +} diff --git a/lib/private/cache/file.php b/lib/private/cache/file.php new file mode 100644 index 00000000000..2ab914d17b8 --- /dev/null +++ b/lib/private/cache/file.php @@ -0,0 +1,118 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Cache; + +class File { + protected $storage; + protected function getStorage() { + if (isset($this->storage)) { + return $this->storage; + } + if(\OC_User::isLoggedIn()) { + \OC\Files\Filesystem::initMountPoints(\OC_User::getUser()); + $subdir = 'cache'; + $view = new \OC\Files\View('/' . \OC_User::getUser()); + if(!$view->file_exists($subdir)) { + $view->mkdir($subdir); + } + $this->storage = new \OC\Files\View('/' . \OC_User::getUser().'/'.$subdir); + return $this->storage; + }else{ + \OC_Log::write('core', 'Can\'t get cache storage, user not logged in', \OC_Log::ERROR); + return false; + } + } + + public function get($key) { + $result = null; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + if ($this->hasKey($key)) { + $storage = $this->getStorage(); + $result = $storage->file_get_contents($key); + } + \OC_FileProxy::$enabled = $proxyStatus; + return $result; + } + + public function set($key, $value, $ttl=0) { + $storage = $this->getStorage(); + $result = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + if ($storage and $storage->file_put_contents($key, $value)) { + if ($ttl === 0) { + $ttl = 86400; // 60*60*24 + } + $result = $storage->touch($key, time() + $ttl); + } + \OC_FileProxy::$enabled = $proxyStatus; + return $result; + } + + public function hasKey($key) { + $storage = $this->getStorage(); + if ($storage && $storage->is_file($key)) { + $mtime = $storage->filemtime($key); + if ($mtime < time()) { + $storage->unlink($key); + return false; + } + return true; + } + return false; + } + + public function remove($key) { + $storage = $this->getStorage(); + if(!$storage) { + return false; + } + return $storage->unlink($key); + } + + public function clear($prefix='') { + $storage = $this->getStorage(); + if($storage and $storage->is_dir('/')) { + $dh=$storage->opendir('/'); + if(is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) { + $storage->unlink('/'.$file); + } + } + } + } + return true; + } + + public function gc() { + $storage = $this->getStorage(); + if($storage and $storage->is_dir('/')) { + $now = time(); + $dh=$storage->opendir('/'); + if(!is_resource($dh)) { + return null; + } + while (($file = readdir($dh)) !== false) { + if($file!='.' and $file!='..') { + $mtime = $storage->filemtime('/'.$file); + if ($mtime < $now) { + $storage->unlink('/'.$file); + } + } + } + } + } + + public static function loginListener() { + $c = new self(); + $c->gc(); + } +} diff --git a/lib/private/cache/fileglobal.php b/lib/private/cache/fileglobal.php new file mode 100644 index 00000000000..bd049bba4d0 --- /dev/null +++ b/lib/private/cache/fileglobal.php @@ -0,0 +1,106 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Cache; + +class FileGlobal { + static protected function getCacheDir() { + $cache_dir = get_temp_dir().'/owncloud-' . \OC_Util::getInstanceId().'/'; + if (!is_dir($cache_dir)) { + mkdir($cache_dir); + } + return $cache_dir; + } + + protected function fixKey($key) { + return str_replace('/', '_', $key); + } + + public function get($key) { + $key = $this->fixKey($key); + if ($this->hasKey($key)) { + $cache_dir = self::getCacheDir(); + return file_get_contents($cache_dir.$key); + } + return null; + } + + public function set($key, $value, $ttl=0) { + $key = $this->fixKey($key); + $cache_dir = self::getCacheDir(); + if ($cache_dir and file_put_contents($cache_dir.$key, $value)) { + if ($ttl === 0) { + $ttl = 86400; // 60*60*24 + } + return touch($cache_dir.$key, time() + $ttl); + } + return false; + } + + public function hasKey($key) { + $key = $this->fixKey($key); + $cache_dir = self::getCacheDir(); + if ($cache_dir && is_file($cache_dir.$key)) { + $mtime = filemtime($cache_dir.$key); + if ($mtime < time()) { + unlink($cache_dir.$key); + return false; + } + return true; + } + return false; + } + + public function remove($key) { + $cache_dir = self::getCacheDir(); + if(!$cache_dir) { + return false; + } + $key = $this->fixKey($key); + return unlink($cache_dir.$key); + } + + public function clear($prefix='') { + $cache_dir = self::getCacheDir(); + $prefix = $this->fixKey($prefix); + if($cache_dir and is_dir($cache_dir)) { + $dh=opendir($cache_dir); + if(is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) { + unlink($cache_dir.$file); + } + } + } + } + } + + static public function gc() { + $last_run = \OC_AppConfig::getValue('core', 'global_cache_gc_lastrun', 0); + $now = time(); + if (($now - $last_run) < 300) { + // only do cleanup every 5 minutes + return; + } + \OC_AppConfig::setValue('core', 'global_cache_gc_lastrun', $now); + $cache_dir = self::getCacheDir(); + if($cache_dir and is_dir($cache_dir)) { + $dh=opendir($cache_dir); + if(is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if($file!='.' and $file!='..') { + $mtime = filemtime($cache_dir.$file); + if ($mtime < $now) { + unlink($cache_dir.$file); + } + } + } + } + } + } +} diff --git a/lib/private/cache/fileglobalgc.php b/lib/private/cache/fileglobalgc.php new file mode 100644 index 00000000000..399dd5e6f94 --- /dev/null +++ b/lib/private/cache/fileglobalgc.php @@ -0,0 +1,9 @@ +userCache = new File(); + } + + /** + * Get a value from the user cache + * + * @param string $key + * @return mixed + */ + public function get($key) { + return $this->userCache->get($key); + } + + /** + * Set a value in the user cache + * + * @param string $key + * @param mixed $value + * @param int $ttl Time To Live in seconds. Defaults to 60*60*24 + * @return bool + */ + public function set($key, $value, $ttl = 0) { + if (empty($key)) { + return false; + } + return $this->userCache->set($key, $value, $ttl); + } + + /** + * Check if a value is set in the user cache + * + * @param string $key + * @return bool + */ + public function hasKey($key) { + return $this->userCache->hasKey($key); + } + + /** + * Remove an item from the user cache + * + * @param string $key + * @return bool + */ + public function remove($key) { + return $this->userCache->remove($key); + } + + /** + * clear the user cache of all entries starting with a prefix + * @param string $prefix (optional) + * @return bool + */ + public function clear($prefix = '') { + return $this->userCache->clear($prefix); + } +} diff --git a/lib/private/config.php b/lib/private/config.php new file mode 100644 index 00000000000..e773e6e2eb0 --- /dev/null +++ b/lib/private/config.php @@ -0,0 +1,186 @@ +. + * + */ +/* + * + * An example of config.php + * + * "mysql", + * "firstrun" => false, + * "pi" => 3.14 + * ); + * ?> + * + */ + +namespace OC; + +/** + * This class is responsible for reading and writing config.php, the very basic + * configuration file of ownCloud. + */ +class Config { + // associative array key => value + protected $cache = array(); + + protected $configDir; + protected $configFilename; + + protected $debugMode; + + /** + * @param $configDir path to the config dir, needs to end with '/' + */ + public function __construct($configDir) { + $this->configDir = $configDir; + $this->configFilename = $this->configDir.'config.php'; + $this->readData(); + $this->setDebugMode(defined('DEBUG') && DEBUG); + } + + public function setDebugMode($enable) { + $this->debugMode = $enable; + } + + /** + * @brief Lists all available config keys + * @return array with key names + * + * This function returns all keys saved in config.php. Please note that it + * does not return the values. + */ + public function getKeys() { + return array_keys($this->cache); + } + + /** + * @brief Gets a value from config.php + * @param string $key key + * @param string $default = null default value + * @return string the value or $default + * + * This function gets the value from config.php. If it does not exist, + * $default will be returned. + */ + public function getValue($key, $default = null) { + if (isset($this->cache[$key])) { + return $this->cache[$key]; + } + + return $default; + } + + /** + * @brief Sets a value + * @param string $key key + * @param string $value value + * + * This function sets the value and writes the config.php. + * + */ + public function setValue($key, $value) { + // Add change + $this->cache[$key] = $value; + + // Write changes + $this->writeData(); + } + + /** + * @brief Removes a key from the config + * @param string $key key + * + * This function removes a key from the config.php. + * + */ + public function deleteKey($key) { + if (isset($this->cache[$key])) { + // Delete key from cache + unset($this->cache[$key]); + + // Write changes + $this->writeData(); + } + } + + /** + * @brief Loads the config file + * + * Reads the config file and saves it to the cache + */ + private function readData() { + // Default config + $configFiles = array($this->configFilename); + // Add all files in the config dir ending with config.php + $extra = glob($this->configDir.'*.config.php'); + if (is_array($extra)) { + natsort($extra); + $configFiles = array_merge($configFiles, $extra); + } + // Include file and merge config + foreach ($configFiles as $file) { + if (!file_exists($file)) { + continue; + } + unset($CONFIG); + // ignore errors on include, this can happen when doing a fresh install + @include $file; + if (isset($CONFIG) && is_array($CONFIG)) { + $this->cache = array_merge($this->cache, $CONFIG); + } + } + } + + /** + * @brief Writes the config file + * + * Saves the config to the config file. + * + */ + private function writeData() { + // Create a php file ... + $defaults = new \OC_Defaults; + $content = "debugMode) { + $content .= "define('DEBUG',true);\n"; + } + $content .= '$CONFIG = '; + $content .= var_export($this->cache, true); + $content .= ";\n"; + + // Write the file + $result = @file_put_contents($this->configFilename, $content); + if (!$result) { + $url = $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html#set-the-directory-permissions'; + throw new HintException( + "Can't write into config directory!", + 'This can usually be fixed by ' + .'giving the webserver write access to the config directory.'); + } + // Prevent others not to read the config + @chmod($this->configFilename, 0640); + \OC_Util::clearOpcodeCache(); + } +} + diff --git a/lib/private/connector/sabre/ServiceUnavailable.php b/lib/private/connector/sabre/ServiceUnavailable.php new file mode 100644 index 00000000000..c1cc815c989 --- /dev/null +++ b/lib/private/connector/sabre/ServiceUnavailable.php @@ -0,0 +1,22 @@ + + * + * @license AGPL3 + */ + +class Sabre_DAV_Exception_ServiceUnavailable extends Sabre_DAV_Exception { + + /** + * Returns the HTTP statuscode for this exception + * + * @return int + */ + public function getHTTPCode() { + + return 503; + } +} diff --git a/lib/private/connector/sabre/auth.php b/lib/private/connector/sabre/auth.php new file mode 100644 index 00000000000..bf3a49593cb --- /dev/null +++ b/lib/private/connector/sabre/auth.php @@ -0,0 +1,84 @@ +. + * + */ + +class OC_Connector_Sabre_Auth extends Sabre_DAV_Auth_Backend_AbstractBasic { + /** + * Validates a username and password + * + * This method should return true or false depending on if login + * succeeded. + * + * @return bool + */ + protected function validateUserPass($username, $password) { + if (OC_User::isLoggedIn()) { + OC_Util::setupFS(OC_User::getUser()); + return true; + } else { + OC_Util::setUpFS();//login hooks may need early access to the filesystem + if(OC_User::login($username, $password)) { + OC_Util::setUpFS(OC_User::getUser()); + return true; + } + else{ + return false; + } + } + } + + /** + * Returns information about the currently logged in username. + * + * If nobody is currently logged in, this method should return null. + * + * @return string|null + */ + public function getCurrentUser() { + $user = OC_User::getUser(); + if(!$user) { + return null; + } + return $user; + } + + /** + * Override function here. We want to cache authentication cookies + * in the syncing client to avoid HTTP-401 roundtrips. + * If the sync client supplies the cookies, then OC_User::isLoggedIn() + * will return true and we can see this WebDAV request as already authenticated, + * even if there are no HTTP Basic Auth headers. + * In other case, just fallback to the parent implementation. + * + * @return bool + */ + public function authenticate(Sabre_DAV_Server $server, $realm) { + if (OC_User::isLoggedIn()) { + $user = OC_User::getUser(); + OC_Util::setupFS($user); + $this->currentUser = $user; + return true; + } + + return parent::authenticate($server, $realm); + } +} diff --git a/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php new file mode 100644 index 00000000000..382bdf06df1 --- /dev/null +++ b/lib/private/connector/sabre/directory.php @@ -0,0 +1,256 @@ +. + * + */ + +class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sabre_DAV_ICollection, Sabre_DAV_IQuota { + + /** + * Creates a new file in the directory + * + * Data will either be supplied as a stream resource, or in certain cases + * as a string. Keep in mind that you may have to support either. + * + * After succesful creation of the file, you may choose to return the ETag + * of the new file here. + * + * The returned ETag must be surrounded by double-quotes (The quotes should + * be part of the actual string). + * + * If you cannot accurately determine the ETag, you should not return it. + * If you don't store the file exactly as-is (you're transforming it + * somehow) you should also not return an ETag. + * + * This means that if a subsequent GET to this new file does not exactly + * return the same contents of what was submitted here, you are strongly + * recommended to omit the ETag. + * + * @param string $name Name of the file + * @param resource|string $data Initial payload + * @throws Sabre_DAV_Exception_Forbidden + * @return null|string + */ + public function createFile($name, $data = null) { + + if (!\OC\Files\Filesystem::isCreatable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + + if (isset($_SERVER['HTTP_OC_CHUNKED'])) { + $info = OC_FileChunking::decodeName($name); + if (empty($info)) { + throw new Sabre_DAV_Exception_NotImplemented(); + } + $chunk_handler = new OC_FileChunking($info); + $chunk_handler->store($info['index'], $data); + if ($chunk_handler->isComplete()) { + $newPath = $this->path . '/' . $info['name']; + $chunk_handler->file_assemble($newPath); + return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); + } + } else { + $newPath = $this->path . '/' . $name; + + // mark file as partial while uploading (ignored by the scanner) + $partpath = $newPath . '.part'; + + \OC\Files\Filesystem::file_put_contents($partpath, $data); + + // rename to correct path + $renameOkay = \OC\Files\Filesystem::rename($partpath, $newPath); + $fileExists = \OC\Files\Filesystem::file_exists($newPath); + if ($renameOkay === false || $fileExists === false) { + \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + \OC\Files\Filesystem::unlink($partpath); + throw new Sabre_DAV_Exception(); + } + + // allow sync clients to send the mtime along in a header + $mtime = OC_Request::hasModificationTime(); + if ($mtime !== false) { + if(\OC\Files\Filesystem::touch($newPath, $mtime)) { + header('X-OC-MTime: accepted'); + } + } + + return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); + } + + return null; + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @throws Sabre_DAV_Exception_Forbidden + * @return void + */ + public function createDirectory($name) { + + if (!\OC\Files\Filesystem::isCreatable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + + $newPath = $this->path . '/' . $name; + if(!\OC\Files\Filesystem::mkdir($newPath)) { + throw new Sabre_DAV_Exception_Forbidden('Could not create directory '.$newPath); + } + + } + + /** + * Returns a specific child node, referenced by its name + * + * @param string $name + * @throws Sabre_DAV_Exception_FileNotFound + * @return Sabre_DAV_INode + */ + public function getChild($name, $info = null) { + + $path = $this->path . '/' . $name; + if (is_null($info)) { + $info = \OC\Files\Filesystem::getFileInfo($path); + } + + if (!$info) { + throw new Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); + } + + if ($info['mimetype'] == 'httpd/unix-directory') { + $node = new OC_Connector_Sabre_Directory($path); + } else { + $node = new OC_Connector_Sabre_File($path); + } + + $node->setFileinfoCache($info); + return $node; + } + + /** + * Returns an array with all the child nodes + * + * @return Sabre_DAV_INode[] + */ + public function getChildren() { + + $folder_content = \OC\Files\Filesystem::getDirectoryContent($this->path); + $paths = array(); + foreach($folder_content as $info) { + $paths[] = $this->path.'/'.$info['name']; + $properties[$this->path.'/'.$info['name']][self::GETETAG_PROPERTYNAME] = '"' . $info['etag'] . '"'; + } + if(count($paths)>0) { + // + // the number of arguments within IN conditions are limited in most databases + // we chunk $paths into arrays of 200 items each to meet this criteria + // + $chunks = array_chunk($paths, 200, false); + foreach ($chunks as $pack) { + $placeholders = join(',', array_fill(0, count($pack), '?')); + $query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*properties`' + .' WHERE `userid` = ?' . ' AND `propertypath` IN ('.$placeholders.')' ); + array_unshift($pack, OC_User::getUser()); // prepend userid + $result = $query->execute( $pack ); + while($row = $result->fetchRow()) { + $propertypath = $row['propertypath']; + $propertyname = $row['propertyname']; + $propertyvalue = $row['propertyvalue']; + if($propertyname !== self::GETETAG_PROPERTYNAME) { + $properties[$propertypath][$propertyname] = $propertyvalue; + } + } + } + } + + $nodes = array(); + foreach($folder_content as $info) { + $node = $this->getChild($info['name'], $info); + $node->setPropertyCache($properties[$this->path.'/'.$info['name']]); + $nodes[] = $node; + } + return $nodes; + } + + /** + * Checks if a child exists. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + $path = $this->path . '/' . $name; + return \OC\Files\Filesystem::file_exists($path); + + } + + /** + * Deletes all files in this directory, and then itself + * + * @return void + * @throws Sabre_DAV_Exception_Forbidden + */ + public function delete() { + + if (!\OC\Files\Filesystem::isDeletable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + if ($this->path != "/Shared") { + \OC\Files\Filesystem::rmdir($this->path); + } + + } + + /** + * Returns available diskspace information + * + * @return array + */ + public function getQuotaInfo() { + $storageInfo = OC_Helper::getStorageInfo($this->path); + return array( + $storageInfo['used'], + $storageInfo['free'] + ); + + } + + /** + * Returns a list of properties for this nodes.; + * + * The properties list is a list of propertynames the client requested, + * encoded as xmlnamespace#tagName, for example: + * http://www.example.org/namespace#author + * If the array is empty, all properties should be returned + * + * @param array $properties + * @return void + */ + public function getProperties($properties) { + $props = parent::getProperties($properties); + if (in_array(self::GETETAG_PROPERTYNAME, $properties) && !isset($props[self::GETETAG_PROPERTYNAME])) { + $props[self::GETETAG_PROPERTYNAME] + = OC_Connector_Sabre_Node::getETagPropertyForPath($this->path); + } + return $props; + } +} diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php new file mode 100644 index 00000000000..433b1148552 --- /dev/null +++ b/lib/private/connector/sabre/file.php @@ -0,0 +1,176 @@ +. + * + */ + +class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_DAV_IFile { + + /** + * Updates the data + * + * The data argument is a readable stream resource. + * + * After a succesful put operation, you may choose to return an ETag. The + * etag must always be surrounded by double-quotes. These quotes must + * appear in the actual string you're returning. + * + * Clients may use the ETag from a PUT request to later on make sure that + * when they update the file, the contents haven't changed in the mean + * time. + * + * If you don't plan to store the file byte-by-byte, and you return a + * different object on a subsequent GET you are strongly recommended to not + * return an ETag, and just return null. + * + * @param resource $data + * @throws Sabre_DAV_Exception_Forbidden + * @return string|null + */ + public function put($data) { + + if (!\OC\Files\Filesystem::isUpdatable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + + // throw an exception if encryption was disabled but the files are still encrypted + if (\OC_Util::encryptedFiles()) { + throw new \Sabre_DAV_Exception_ServiceUnavailable(); + } + + // mark file as partial while uploading (ignored by the scanner) + $partpath = $this->path . '.part'; + + \OC\Files\Filesystem::file_put_contents($partpath, $data); + + //detect aborted upload + if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { + if (isset($_SERVER['CONTENT_LENGTH'])) { + $expected = $_SERVER['CONTENT_LENGTH']; + $actual = \OC\Files\Filesystem::filesize($partpath); + if ($actual != $expected) { + \OC\Files\Filesystem::unlink($partpath); + throw new Sabre_DAV_Exception_BadRequest( + 'expected filesize ' . $expected . ' got ' . $actual); + } + } + } + + // rename to correct path + $renameOkay = \OC\Files\Filesystem::rename($partpath, $this->path); + $fileExists = \OC\Files\Filesystem::file_exists($this->path); + if ($renameOkay === false || $fileExists === false) { + \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + \OC\Files\Filesystem::unlink($partpath); + throw new Sabre_DAV_Exception(); + } + + + //allow sync clients to send the mtime along in a header + $mtime = OC_Request::hasModificationTime(); + if ($mtime !== false) { + if (\OC\Files\Filesystem::touch($this->path, $mtime)) { + header('X-OC-MTime: accepted'); + } + } + + return OC_Connector_Sabre_Node::getETagPropertyForPath($this->path); + } + + /** + * Returns the data + * + * @return string + */ + public function get() { + + //throw execption if encryption is disabled but files are still encrypted + if (\OC_Util::encryptedFiles()) { + throw new \Sabre_DAV_Exception_ServiceUnavailable(); + } else { + return \OC\Files\Filesystem::fopen($this->path, 'rb'); + } + + } + + /** + * Delete the current file + * + * @return void + * @throws Sabre_DAV_Exception_Forbidden + */ + public function delete() { + + if (!\OC\Files\Filesystem::isDeletable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + \OC\Files\Filesystem::unlink($this->path); + + } + + /** + * Returns the size of the node, in bytes + * + * @return int + */ + public function getSize() { + $this->getFileinfoCache(); + if ($this->fileinfo_cache['size'] > -1) { + return $this->fileinfo_cache['size']; + } else { + return null; + } + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the + * file. If the file changes, the ETag MUST change. The ETag is an + * arbritrary string, but MUST be surrounded by double-quotes. + * + * Return null if the ETag can not effectively be determined + * + * @return mixed + */ + public function getETag() { + $properties = $this->getProperties(array(self::GETETAG_PROPERTYNAME)); + if (isset($properties[self::GETETAG_PROPERTYNAME])) { + return $properties[self::GETETAG_PROPERTYNAME]; + } + return null; + } + + /** + * Returns the mime-type for a file + * + * If null is returned, we'll assume application/octet-stream + * + * @return mixed + */ + public function getContentType() { + if (isset($this->fileinfo_cache['mimetype'])) { + return $this->fileinfo_cache['mimetype']; + } + + return \OC\Files\Filesystem::getMimeType($this->path); + + } +} diff --git a/lib/private/connector/sabre/locks.php b/lib/private/connector/sabre/locks.php new file mode 100644 index 00000000000..69496c15ada --- /dev/null +++ b/lib/private/connector/sabre/locks.php @@ -0,0 +1,189 @@ +. + * + */ + +class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract { + + /** + * Returns a list of Sabre_DAV_Locks_LockInfo objects + * + * This method should return all the locks for a particular uri, including + * locks that might be set on a parent uri. + * + * If returnChildLocks is set to true, this method should also look for + * any locks in the subtree of the uri for locks. + * + * @param string $uri + * @param bool $returnChildLocks + * @return array + */ + public function getLocks($uri, $returnChildLocks) { + + // NOTE: the following 10 lines or so could be easily replaced by + // pure sql. MySQL's non-standard string concatination prevents us + // from doing this though. + // NOTE: SQLite requires time() to be inserted directly. That's ugly + // but otherwise reading locks from SQLite Databases will return + // nothing + $query = 'SELECT * FROM `*PREFIX*locks`' + .' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( `uri` = ?)'; + if (OC_Config::getValue( "dbtype") === 'oci') { + //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison + $query = 'SELECT * FROM `*PREFIX*locks`' + .' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( to_char(`uri`) = ?)'; + } + $params = array(OC_User::getUser(), $uri); + + // We need to check locks for every part in the uri. + $uriParts = explode('/', $uri); + + // We already covered the last part of the uri + array_pop($uriParts); + + $currentPath=''; + + foreach($uriParts as $part) { + + if ($currentPath) $currentPath.='/'; + $currentPath.=$part; + //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison + if (OC_Config::getValue( "dbtype") === 'oci') { + $query.=' OR (`depth` != 0 AND to_char(`uri`) = ?)'; + } else { + $query.=' OR (`depth` != 0 AND `uri` = ?)'; + } + $params[] = $currentPath; + + } + + if ($returnChildLocks) { + + //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison + if (OC_Config::getValue( "dbtype") === 'oci') { + $query.=' OR (to_char(`uri`) LIKE ?)'; + } else { + $query.=' OR (`uri` LIKE ?)'; + } + $params[] = $uri . '/%'; + + } + $query.=')'; + + $result = OC_DB::executeAudited( $query, $params ); + + $lockList = array(); + while( $row = $result->fetchRow()) { + + $lockInfo = new Sabre_DAV_Locks_LockInfo(); + $lockInfo->owner = $row['owner']; + $lockInfo->token = $row['token']; + $lockInfo->timeout = $row['timeout']; + $lockInfo->created = $row['created']; + $lockInfo->scope = $row['scope']; + $lockInfo->depth = $row['depth']; + $lockInfo->uri = $row['uri']; + $lockList[] = $lockInfo; + + } + + return $lockList; + + } + + /** + * Locks a uri + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return bool + */ + public function lock($uri, Sabre_DAV_Locks_LockInfo $lockInfo) { + + // We're making the lock timeout 5 minutes + $lockInfo->timeout = 300; + $lockInfo->created = time(); + $lockInfo->uri = $uri; + + $locks = $this->getLocks($uri, false); + $exists = false; + foreach($locks as $lock) { + if ($lock->token == $lockInfo->token) { + $exists = true; + break; + } + } + + if ($exists) { + $sql = 'UPDATE `*PREFIX*locks`' + .' SET `owner` = ?, `timeout` = ?, `scope` = ?, `depth` = ?, `uri` = ?, `created` = ?' + .' WHERE `userid` = ? AND `token` = ?'; + $result = OC_DB::executeAudited( $sql, array( + $lockInfo->owner, + $lockInfo->timeout, + $lockInfo->scope, + $lockInfo->depth, + $uri, + $lockInfo->created, + OC_User::getUser(), + $lockInfo->token) + ); + } else { + $sql = 'INSERT INTO `*PREFIX*locks`' + .' (`userid`,`owner`,`timeout`,`scope`,`depth`,`uri`,`created`,`token`)' + .' VALUES (?,?,?,?,?,?,?,?)'; + $result = OC_DB::executeAudited( $sql, array( + OC_User::getUser(), + $lockInfo->owner, + $lockInfo->timeout, + $lockInfo->scope, + $lockInfo->depth, + $uri, + $lockInfo->created, + $lockInfo->token) + ); + } + + return true; + + } + + /** + * Removes a lock from a uri + * + * @param string $uri + * @param Sabre_DAV_Locks_LockInfo $lockInfo + * @return bool + */ + public function unlock($uri, Sabre_DAV_Locks_LockInfo $lockInfo) { + + $sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND `uri` = ? AND `token` = ?'; + if (OC_Config::getValue( "dbtype") === 'oci') { + //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison + $sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND to_char(`uri`) = ? AND `token` = ?'; + } + $result = OC_DB::executeAudited( $sql, array(OC_User::getUser(), $uri, $lockInfo->token)); + + return $result === 1; + + } + +} diff --git a/lib/private/connector/sabre/maintenanceplugin.php b/lib/private/connector/sabre/maintenanceplugin.php new file mode 100644 index 00000000000..2eda269afc2 --- /dev/null +++ b/lib/private/connector/sabre/maintenanceplugin.php @@ -0,0 +1,59 @@ + + * + * @license AGPL3 + */ + +require 'ServiceUnavailable.php'; + +class OC_Connector_Sabre_MaintenancePlugin extends Sabre_DAV_ServerPlugin +{ + + /** + * Reference to main server object + * + * @var Sabre_DAV_Server + */ + private $server; + + /** + * This initializes the plugin. + * + * This function is called by Sabre_DAV_Server, after + * addPlugin is called. + * + * This method should set up the required event subscriptions. + * + * @param Sabre_DAV_Server $server + * @return void + */ + public function initialize(Sabre_DAV_Server $server) { + + $this->server = $server; + $this->server->subscribeEvent('beforeMethod', array($this, 'checkMaintenanceMode'), 10); + } + + /** + * This method is called before any HTTP method and returns http status code 503 + * in case the system is in maintenance mode. + * + * @throws Sabre_DAV_Exception_ServiceUnavailable + * @internal param string $method + * @return bool + */ + public function checkMaintenanceMode() { + if (OC_Config::getValue('maintenance', false)) { + throw new Sabre_DAV_Exception_ServiceUnavailable(); + } + if (OC::checkUpgrade(false)) { + throw new Sabre_DAV_Exception_ServiceUnavailable('Upgrade needed'); + } + + return true; + } +} diff --git a/lib/private/connector/sabre/node.php b/lib/private/connector/sabre/node.php new file mode 100644 index 00000000000..29b7f9e53a5 --- /dev/null +++ b/lib/private/connector/sabre/node.php @@ -0,0 +1,238 @@ +. + * + */ + +abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IProperties { + const GETETAG_PROPERTYNAME = '{DAV:}getetag'; + const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; + + /** + * Allow configuring the method used to generate Etags + * + * @var array(class_name, function_name) + */ + public static $ETagFunction = null; + + /** + * The path to the current node + * + * @var string + */ + protected $path; + /** + * node fileinfo cache + * @var array + */ + protected $fileinfo_cache; + /** + * node properties cache + * @var array + */ + protected $property_cache = null; + + /** + * @brief Sets up the node, expects a full path name + * @param string $path + * @return void + */ + public function __construct($path) { + $this->path = $path; + } + + + + /** + * @brief Returns the name of the node + * @return string + */ + public function getName() { + + list(, $name) = Sabre_DAV_URLUtil::splitPath($this->path); + return $name; + + } + + /** + * @brief Renames the node + * @param string $name The new name + * @return void + */ + public function setName($name) { + + // rename is only allowed if the update privilege is granted + if (!\OC\Files\Filesystem::isUpdatable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + + list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path); + list(, $newName) = Sabre_DAV_URLUtil::splitPath($name); + + $newPath = $parentPath . '/' . $newName; + $oldPath = $this->path; + + \OC\Files\Filesystem::rename($this->path, $newPath); + + $this->path = $newPath; + + $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' + .' WHERE `userid` = ? AND `propertypath` = ?' ); + $query->execute( array( $newPath, OC_User::getUser(), $oldPath )); + + } + + public function setFileinfoCache($fileinfo_cache) + { + $this->fileinfo_cache = $fileinfo_cache; + } + + /** + * @brief Ensure that the fileinfo cache is filled + * @note Uses OC_FileCache or a direct stat + */ + protected function getFileinfoCache() { + if (!isset($this->fileinfo_cache)) { + if ($fileinfo_cache = \OC\Files\Filesystem::getFileInfo($this->path)) { + } else { + $fileinfo_cache = \OC\Files\Filesystem::stat($this->path); + } + + $this->fileinfo_cache = $fileinfo_cache; + } + } + + public function setPropertyCache($property_cache) + { + $this->property_cache = $property_cache; + } + + /** + * @brief Returns the last modification time, as a unix timestamp + * @return int + */ + public function getLastModified() { + $this->getFileinfoCache(); + return $this->fileinfo_cache['mtime']; + + } + + /** + * sets the last modification time of the file (mtime) to the value given + * in the second parameter or to now if the second param is empty. + * Even if the modification time is set to a custom value the access time is set to now. + */ + public function touch($mtime) { + + // touch is only allowed if the update privilege is granted + if (!\OC\Files\Filesystem::isUpdatable($this->path)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + + \OC\Files\Filesystem::touch($this->path, $mtime); + } + + /** + * @brief Updates properties on this node, + * @param array $mutations + * @see Sabre_DAV_IProperties::updateProperties + * @return bool|array + */ + public function updateProperties($properties) { + $existing = $this->getProperties(array()); + foreach($properties as $propertyName => $propertyValue) { + // If it was null, we need to delete the property + if (is_null($propertyValue)) { + if(array_key_exists( $propertyName, $existing )) { + $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*properties`' + .' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' ); + $query->execute( array( OC_User::getUser(), $this->path, $propertyName )); + } + } + else { + if( strcmp( $propertyName, self::GETETAG_PROPERTYNAME) === 0 ) { + \OC\Files\Filesystem::putFileInfo($this->path, array('etag'=> $propertyValue)); + } elseif( strcmp( $propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0 ) { + $this->touch($propertyValue); + } else { + if(!array_key_exists( $propertyName, $existing )) { + $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*properties`' + .' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)' ); + $query->execute( array( OC_User::getUser(), $this->path, $propertyName,$propertyValue )); + } else { + $query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' + .' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' ); + $query->execute( array( $propertyValue,OC_User::getUser(), $this->path, $propertyName )); + } + } + } + + } + $this->setPropertyCache(null); + return true; + } + + /** + * @brief Returns a list of properties for this nodes.; + * @param array $properties + * @return array + * @note The properties list is a list of propertynames the client + * requested, encoded as xmlnamespace#tagName, for example: + * http://www.example.org/namespace#author If the array is empty, all + * properties should be returned + */ + public function getProperties($properties) { + if (is_null($this->property_cache)) { + $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?'; + $result = OC_DB::executeAudited( $sql, array( OC_User::getUser(), $this->path ) ); + + $this->property_cache = array(); + while( $row = $result->fetchRow()) { + $this->property_cache[$row['propertyname']] = $row['propertyvalue']; + } + $this->property_cache[self::GETETAG_PROPERTYNAME] = $this->getETagPropertyForPath($this->path); + } + + // if the array was empty, we need to return everything + if(count($properties) == 0) { + return $this->property_cache; + } + + $props = array(); + foreach($properties as $property) { + if (isset($this->property_cache[$property])) $props[$property] = $this->property_cache[$property]; + } + return $props; + } + + /** + * Returns the ETag surrounded by double-quotes for this path. + * @param string $path Path of the file + * @return string|null Returns null if the ETag can not effectively be determined + */ + static public function getETagPropertyForPath($path) { + $data = \OC\Files\Filesystem::getFileInfo($path); + if (isset($data['etag'])) { + return '"'.$data['etag'].'"'; + } + return null; + } + +} diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php new file mode 100644 index 00000000000..80c3840b99d --- /dev/null +++ b/lib/private/connector/sabre/objecttree.php @@ -0,0 +1,142 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Connector\Sabre; + +use OC\Files\Filesystem; + +class ObjectTree extends \Sabre_DAV_ObjectTree { + + /** + * keep this public to allow mock injection during unit test + * + * @var \OC\Files\View + */ + public $fileView; + + /** + * Returns the INode object for the requested path + * + * @param string $path + * @throws \Sabre_DAV_Exception_NotFound + * @return \Sabre_DAV_INode + */ + public function getNodeForPath($path) { + + $path = trim($path, '/'); + if (isset($this->cache[$path])) { + return $this->cache[$path]; + } + + // Is it the root node? + if (!strlen($path)) { + return $this->rootNode; + } + + $info = $this->getFileView()->getFileInfo($path); + + if (!$info) { + throw new \Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); + } + + if ($info['mimetype'] === 'httpd/unix-directory') { + $node = new \OC_Connector_Sabre_Directory($path); + } else { + $node = new \OC_Connector_Sabre_File($path); + } + + $node->setFileinfoCache($info); + + $this->cache[$path] = $node; + return $node; + + } + + /** + * Moves a file from one location to another + * + * @param string $sourcePath The path to the file which should be moved + * @param string $destinationPath The full destination path, so not just the destination parent node + * @throws \Sabre_DAV_Exception_Forbidden + * @return int + */ + public function move($sourcePath, $destinationPath) { + + $sourceNode = $this->getNodeForPath($sourcePath); + if ($sourceNode instanceof \Sabre_DAV_ICollection and $this->nodeExists($destinationPath)) { + throw new \Sabre_DAV_Exception_Forbidden('Could not copy directory ' . $sourceNode . ', target exists'); + } + list($sourceDir,) = \Sabre_DAV_URLUtil::splitPath($sourcePath); + list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destinationPath); + + // check update privileges + $fs = $this->getFileView(); + if (!$fs->isUpdatable($sourcePath)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + if ($sourceDir !== $destinationDir) { + // for a full move we need update privileges on sourcePath and sourceDir as well as destinationDir + if (!$fs->isUpdatable($sourceDir)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + if (!$fs->isUpdatable($destinationDir)) { + throw new \Sabre_DAV_Exception_Forbidden(); + } + } + + $renameOkay = $fs->rename($sourcePath, $destinationPath); + if (!$renameOkay) { + throw new \Sabre_DAV_Exception_Forbidden(''); + } + + $this->markDirty($sourceDir); + $this->markDirty($destinationDir); + + } + + /** + * Copies a file or directory. + * + * This method must work recursively and delete the destination + * if it exists + * + * @param string $source + * @param string $destination + * @return void + */ + public function copy($source, $destination) { + + if (Filesystem::is_file($source)) { + Filesystem::copy($source, $destination); + } else { + Filesystem::mkdir($destination); + $dh = Filesystem::opendir($source); + if(is_resource($dh)) { + while (($subnode = readdir($dh)) !== false) { + + if ($subnode == '.' || $subnode == '..') continue; + $this->copy($source . '/' . $subnode, $destination . '/' . $subnode); + + } + } + } + + list($destinationDir,) = \Sabre_DAV_URLUtil::splitPath($destination); + $this->markDirty($destinationDir); + } + + /** + * @return \OC\Files\View + */ + public function getFileView() { + if (is_null($this->fileView)) { + $this->fileView = \OC\Files\Filesystem::getView(); + } + return $this->fileView; + } +} diff --git a/lib/private/connector/sabre/principal.php b/lib/private/connector/sabre/principal.php new file mode 100644 index 00000000000..59a96797c16 --- /dev/null +++ b/lib/private/connector/sabre/principal.php @@ -0,0 +1,128 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend { + /** + * Returns a list of principals based on a prefix. + * + * This prefix will often contain something like 'principals'. You are only + * expected to return principals that are in this base path. + * + * You are expected to return at least a 'uri' for every user, you can + * return any additional properties if you wish so. Common properties are: + * {DAV:}displayname + * + * @param string $prefixPath + * @return array + */ + public function getPrincipalsByPrefix( $prefixPath ) { + $principals = array(); + + if ($prefixPath == 'principals') { + foreach(OC_User::getUsers() as $user) { + $user_uri = 'principals/'.$user; + $principals[] = array( + 'uri' => $user_uri, + '{DAV:}displayname' => $user, + ); + } + } + + return $principals; + } + + /** + * Returns a specific principal, specified by it's path. + * The returned structure should be the exact same as from + * getPrincipalsByPrefix. + * + * @param string $path + * @return array + */ + public function getPrincipalByPath($path) { + list($prefix, $name) = explode('/', $path); + + if ($prefix == 'principals' && OC_User::userExists($name)) { + return array( + 'uri' => 'principals/'.$name, + '{DAV:}displayname' => $name, + ); + } + + return null; + } + + /** + * Returns the list of members for a group-principal + * + * @param string $principal + * @return array + */ + public function getGroupMemberSet($principal) { + // TODO: for now the group principal has only one member, the user itself + $principal = $this->getPrincipalByPath($principal); + if (!$principal) { + throw new Sabre_DAV_Exception('Principal not found'); + } + + return array( + $principal['uri'] + ); + } + + /** + * Returns the list of groups a principal is a member of + * + * @param string $principal + * @return array + */ + public function getGroupMembership($principal) { + list($prefix, $name) = Sabre_DAV_URLUtil::splitPath($principal); + + $group_membership = array(); + if ($prefix == 'principals') { + $principal = $this->getPrincipalByPath($principal); + if (!$principal) { + throw new Sabre_DAV_Exception('Principal not found'); + } + + // TODO: for now the user principal has only its own groups + return array( + 'principals/'.$name.'/calendar-proxy-read', + 'principals/'.$name.'/calendar-proxy-write', + // The addressbook groups are not supported in Sabre, + // see http://groups.google.com/group/sabredav-discuss/browse_thread/thread/ef2fa9759d55f8c#msg_5720afc11602e753 + //'principals/'.$name.'/addressbook-proxy-read', + //'principals/'.$name.'/addressbook-proxy-write', + ); + } + return $group_membership; + } + + /** + * Updates the list of group members for a group principal. + * + * The principals should be passed as a list of uri's. + * + * @param string $principal + * @param array $members + * @return void + */ + public function setGroupMemberSet($principal, array $members) { + throw new Sabre_DAV_Exception('Setting members of the group is not supported yet'); + } + + function updatePrincipal($path, $mutations) { + return 0; + } + + function searchPrincipals($prefixPath, array $searchProperties) { + return array(); + } +} diff --git a/lib/private/connector/sabre/quotaplugin.php b/lib/private/connector/sabre/quotaplugin.php new file mode 100644 index 00000000000..ea2cb81d1f7 --- /dev/null +++ b/lib/private/connector/sabre/quotaplugin.php @@ -0,0 +1,97 @@ +server = $server; + + $server->subscribeEvent('beforeWriteContent', array($this, 'checkQuota'), 10); + $server->subscribeEvent('beforeCreateFile', array($this, 'checkQuota'), 10); + } + + /** + * This method is called before any HTTP method and validates there is enough free space to store the file + * + * @param string $method + * @throws Sabre_DAV_Exception + * @return bool + */ + public function checkQuota($uri, $data = null) { + $length = $this->getLength(); + if ($length) { + if (substr($uri, 0, 1)!=='/') { + $uri='/'.$uri; + } + list($parentUri, $newName) = Sabre_DAV_URLUtil::splitPath($uri); + $freeSpace = $this->getFreeSpace($parentUri); + if ($freeSpace !== \OC\Files\SPACE_UNKNOWN && $length > $freeSpace) { + throw new Sabre_DAV_Exception_InsufficientStorage(); + } + } + return true; + } + + public function getLength() + { + $req = $this->server->httpRequest; + $length = $req->getHeader('X-Expected-Entity-Length'); + if (!$length) { + $length = $req->getHeader('Content-Length'); + } + + $ocLength = $req->getHeader('OC-Total-Length'); + if ($length && $ocLength) { + return max($length, $ocLength); + } + + return $length; + } + + /** + * @param $parentUri + * @return mixed + */ + public function getFreeSpace($parentUri) + { + if (is_null($this->fileView)) { + // initialize fileView + $this->fileView = \OC\Files\Filesystem::getView(); + } + + $freeSpace = $this->fileView->free_space($parentUri); + return $freeSpace; + } +} diff --git a/lib/private/connector/sabre/request.php b/lib/private/connector/sabre/request.php new file mode 100644 index 00000000000..d70c25c4e70 --- /dev/null +++ b/lib/private/connector/sabre/request.php @@ -0,0 +1,50 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 library. If not, see . + * + */ + +class OC_Connector_Sabre_Request extends Sabre_HTTP_Request { + /** + * Returns the requested uri + * + * @return string + */ + public function getUri() { + return OC_Request::requestUri(); + } + + /** + * Returns a specific item from the _SERVER array. + * + * Do not rely on this feature, it is for internal use only. + * + * @param string $field + * @return string + */ + public function getRawServerValue($field) { + if($field == 'REQUEST_URI') { + return $this->getUri(); + } + else{ + return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null; + } + } +} diff --git a/lib/private/contactsmanager.php b/lib/private/contactsmanager.php new file mode 100644 index 00000000000..fc6745b4505 --- /dev/null +++ b/lib/private/contactsmanager.php @@ -0,0 +1,145 @@ +. + * + */ + +namespace OC { + + class ContactsManager implements \OCP\Contacts\IManager { + + /** + * This function is used to search and find contacts within the users address books. + * In case $pattern is empty all contacts will be returned. + * + * @param string $pattern which should match within the $searchProperties + * @param array $searchProperties defines the properties within the query pattern should match + * @param array $options - for future use. One should always have options! + * @return array of contacts which are arrays of key-value-pairs + */ + public function search($pattern, $searchProperties = array(), $options = array()) { + $result = array(); + foreach($this->address_books as $address_book) { + $r = $address_book->search($pattern, $searchProperties, $options); + $result = array_merge($result, $r); + } + + return $result; + } + + /** + * This function can be used to delete the contact identified by the given id + * + * @param object $id the unique identifier to a contact + * @param $address_book_key + * @return bool successful or not + */ + public function delete($id, $address_book_key) { + if (!array_key_exists($address_book_key, $this->address_books)) + return null; + + $address_book = $this->address_books[$address_book_key]; + if ($address_book->getPermissions() & \OCP\PERMISSION_DELETE) + return null; + + return $address_book->delete($id); + } + + /** + * This function is used to create a new contact if 'id' is not given or not present. + * Otherwise the contact will be updated by replacing the entire data set. + * + * @param array $properties this array if key-value-pairs defines a contact + * @param $address_book_key string to identify the address book in which the contact shall be created or updated + * @return array representing the contact just created or updated + */ + public function createOrUpdate($properties, $address_book_key) { + + if (!array_key_exists($address_book_key, $this->address_books)) + return null; + + $address_book = $this->address_books[$address_book_key]; + if ($address_book->getPermissions() & \OCP\PERMISSION_CREATE) + return null; + + return $address_book->createOrUpdate($properties); + } + + /** + * Check if contacts are available (e.g. contacts app enabled) + * + * @return bool true if enabled, false if not + */ + public function isEnabled() { + return !empty($this->address_books); + } + + /** + * @param \OCP\IAddressBook $address_book + */ + public function registerAddressBook(\OCP\IAddressBook $address_book) { + $this->address_books[$address_book->getKey()] = $address_book; + } + + /** + * @param \OCP\IAddressBook $address_book + */ + public function unregisterAddressBook(\OCP\IAddressBook $address_book) { + unset($this->address_books[$address_book->getKey()]); + } + + /** + * @return array + */ + public function getAddressBooks() { + $result = array(); + foreach($this->address_books as $address_book) { + $result[$address_book->getKey()] = $address_book->getDisplayName(); + } + + return $result; + } + + /** + * removes all registered address book instances + */ + public function clear() { + $this->address_books = array(); + } + + /** + * @var \OCP\IAddressBook[] which holds all registered address books + */ + private $address_books = array(); + + /** + * In order to improve lazy loading a closure can be registered which will be called in case + * address books are actually requested + * + * @param string $key + * @param \Closure $callable + */ + function register($key, \Closure $callable) + { + // + //TODO: implement me + // + } + } +} diff --git a/lib/private/db.php b/lib/private/db.php new file mode 100644 index 00000000000..1e5d12649df --- /dev/null +++ b/lib/private/db.php @@ -0,0 +1,462 @@ +. + * + */ + +define('MDB2_SCHEMA_DUMP_STRUCTURE', '1'); + +class DatabaseException extends Exception { + private $query; + + //FIXME getQuery seems to be unused, maybe use parent constructor with $message, $code and $previous + public function __construct($message, $query = null){ + parent::__construct($message); + $this->query = $query; + } + + public function getQuery() { + return $this->query; + } +} + +/** + * This class manages the access to the database. It basically is a wrapper for + * Doctrine with some adaptions. + */ +class OC_DB { + /** + * @var \OC\DB\Connection $connection + */ + static private $connection; //the prefered connection to use, only Doctrine + + static private $prefix=null; + static private $type=null; + + /** + * @brief connects to the database + * @return bool true if connection can be established or false on error + * + * Connects to the database as specified in config.php + */ + public static function connect() { + if(self::$connection) { + return true; + } + + // The global data we need + $name = OC_Config::getValue( "dbname", "owncloud" ); + $host = OC_Config::getValue( "dbhost", "" ); + $user = OC_Config::getValue( "dbuser", "" ); + $pass = OC_Config::getValue( "dbpassword", "" ); + $type = OC_Config::getValue( "dbtype", "sqlite" ); + if(strpos($host, ':')) { + list($host, $port)=explode(':', $host, 2); + } else { + $port=false; + } + + // do nothing if the connection already has been established + if (!self::$connection) { + $config = new \Doctrine\DBAL\Configuration(); + $eventManager = new \Doctrine\Common\EventManager(); + switch($type) { + case 'sqlite': + case 'sqlite3': + $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ); + $connectionParams = array( + 'user' => $user, + 'password' => $pass, + 'path' => $datadir.'/'.$name.'.db', + 'driver' => 'pdo_sqlite', + ); + $connectionParams['adapter'] = '\OC\DB\AdapterSqlite'; + $connectionParams['wrapperClass'] = 'OC\DB\Connection'; + break; + case 'mysql': + $connectionParams = array( + 'user' => $user, + 'password' => $pass, + 'host' => $host, + 'port' => $port, + 'dbname' => $name, + 'charset' => 'UTF8', + 'driver' => 'pdo_mysql', + ); + $connectionParams['adapter'] = '\OC\DB\Adapter'; + $connectionParams['wrapperClass'] = 'OC\DB\Connection'; + break; + case 'pgsql': + $connectionParams = array( + 'user' => $user, + 'password' => $pass, + 'host' => $host, + 'port' => $port, + 'dbname' => $name, + 'driver' => 'pdo_pgsql', + ); + $connectionParams['adapter'] = '\OC\DB\AdapterPgSql'; + $connectionParams['wrapperClass'] = 'OC\DB\Connection'; + break; + case 'oci': + $connectionParams = array( + 'user' => $user, + 'password' => $pass, + 'host' => $host, + 'dbname' => $name, + 'charset' => 'AL32UTF8', + 'driver' => 'oci8', + ); + if (!empty($port)) { + $connectionParams['port'] = $port; + } + $connectionParams['adapter'] = '\OC\DB\AdapterOCI8'; + $connectionParams['wrapperClass'] = 'OC\DB\OracleConnection'; + $eventManager->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\OracleSessionInit); + break; + case 'mssql': + $connectionParams = array( + 'user' => $user, + 'password' => $pass, + 'host' => $host, + 'port' => $port, + 'dbname' => $name, + 'charset' => 'UTF8', + 'driver' => 'pdo_sqlsrv', + ); + $connectionParams['adapter'] = '\OC\DB\AdapterSQLSrv'; + $connectionParams['wrapperClass'] = 'OC\DB\Connection'; + break; + default: + return false; + } + $connectionParams['tablePrefix'] = OC_Config::getValue('dbtableprefix', 'oc_' ); + try { + self::$connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config, $eventManager); + if ($type === 'sqlite' || $type === 'sqlite3') { + // Sqlite doesn't handle query caching and schema changes + // TODO: find a better way to handle this + self::$connection->disableQueryStatementCaching(); + } + } catch(\Doctrine\DBAL\DBALException $e) { + OC_Log::write('core', $e->getMessage(), OC_Log::FATAL); + OC_User::setUserId(null); + + // send http status 503 + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + OC_Template::printErrorPage('Failed to connect to database'); + die(); + } + } + return true; + } + + /** + * @return \OC\DB\Connection + */ + static public function getConnection() { + self::connect(); + return self::$connection; + } + + /** + * get MDB2 schema manager + * + * @return \OC\DB\MDB2SchemaManager + */ + private static function getMDB2SchemaManager() + { + return new \OC\DB\MDB2SchemaManager(self::getConnection()); + } + + /** + * @brief Prepare a SQL query + * @param string $query Query string + * @param int $limit + * @param int $offset + * @param bool $isManipulation + * @throws DatabaseException + * @return \Doctrine\DBAL\Statement prepared SQL query + * + * SQL query via Doctrine prepare(), needs to be execute()'d! + */ + static public function prepare( $query , $limit = null, $offset = null, $isManipulation = null) { + self::connect(); + + if ($isManipulation === null) { + //try to guess, so we return the number of rows on manipulations + $isManipulation = self::isManipulation($query); + } + + // return the result + try { + $result = self::$connection->prepare($query, $limit, $offset); + } catch (\Doctrine\DBAL\DBALException $e) { + throw new \DatabaseException($e->getMessage(), $query); + } + // differentiate between query and manipulation + $result = new OC_DB_StatementWrapper($result, $isManipulation); + return $result; + } + + /** + * tries to guess the type of statement based on the first 10 characters + * the current check allows some whitespace but does not work with IF EXISTS or other more complex statements + * + * @param string $sql + * @return bool + */ + static public function isManipulation( $sql ) { + $selectOccurrence = stripos($sql, 'SELECT'); + if ($selectOccurrence !== false && $selectOccurrence < 10) { + return false; + } + $insertOccurrence = stripos($sql, 'INSERT'); + if ($insertOccurrence !== false && $insertOccurrence < 10) { + return true; + } + $updateOccurrence = stripos($sql, 'UPDATE'); + if ($updateOccurrence !== false && $updateOccurrence < 10) { + return true; + } + $deleteOccurrence = stripos($sql, 'DELETE'); + if ($deleteOccurrence !== false && $deleteOccurrence < 10) { + return true; + } + return false; + } + + /** + * @brief execute a prepared statement, on error write log and throw exception + * @param mixed $stmt OC_DB_StatementWrapper, + * an array with 'sql' and optionally 'limit' and 'offset' keys + * .. or a simple sql query string + * @param array $parameters + * @return result + * @throws DatabaseException + */ + static public function executeAudited( $stmt, array $parameters = null) { + if (is_string($stmt)) { + // convert to an array with 'sql' + if (stripos($stmt, 'LIMIT') !== false) { //OFFSET requires LIMIT, so we only need to check for LIMIT + // TODO try to convert LIMIT OFFSET notation to parameters, see fixLimitClauseForMSSQL + $message = 'LIMIT and OFFSET are forbidden for portability reasons,' + . ' pass an array with \'limit\' and \'offset\' instead'; + throw new DatabaseException($message); + } + $stmt = array('sql' => $stmt, 'limit' => null, 'offset' => null); + } + if (is_array($stmt)) { + // convert to prepared statement + if ( ! array_key_exists('sql', $stmt) ) { + $message = 'statement array must at least contain key \'sql\''; + throw new DatabaseException($message); + } + if ( ! array_key_exists('limit', $stmt) ) { + $stmt['limit'] = null; + } + if ( ! array_key_exists('limit', $stmt) ) { + $stmt['offset'] = null; + } + $stmt = self::prepare($stmt['sql'], $stmt['limit'], $stmt['offset']); + } + self::raiseExceptionOnError($stmt, 'Could not prepare statement'); + if ($stmt instanceof OC_DB_StatementWrapper) { + $result = $stmt->execute($parameters); + self::raiseExceptionOnError($result, 'Could not execute statement'); + } else { + if (is_object($stmt)) { + $message = 'Expected a prepared statement or array got ' . get_class($stmt); + } else { + $message = 'Expected a prepared statement or array got ' . gettype($stmt); + } + throw new DatabaseException($message); + } + return $result; + } + + /** + * @brief gets last value of autoincrement + * @param string $table The optional table name (will replace *PREFIX*) and add sequence suffix + * @return int id + * @throws DatabaseException + * + * \Doctrine\DBAL\Connection lastInsertId + * + * Call this method right after the insert command or other functions may + * cause trouble! + */ + public static function insertid($table=null) { + self::connect(); + return self::$connection->lastInsertId($table); + } + + /** + * @brief Insert a row if a matching row doesn't exists. + * @param string $table. The table to insert into in the form '*PREFIX*tableName' + * @param array $input. An array of fieldname/value pairs + * @return int number of updated rows + */ + public static function insertIfNotExist($table, $input) { + self::connect(); + return self::$connection->insertIfNotExist($table, $input); + } + + /** + * Start a transaction + */ + public static function beginTransaction() { + self::connect(); + self::$connection->beginTransaction(); + } + + /** + * Commit the database changes done during a transaction that is in progress + */ + public static function commit() { + self::connect(); + self::$connection->commit(); + } + + /** + * @brief saves database schema to xml file + * @param string $file name of file + * @param int $mode + * @return bool + * + * TODO: write more documentation + */ + public static function getDbStructure( $file, $mode = 0) { + $schemaManager = self::getMDB2SchemaManager(); + return $schemaManager->getDbStructure($file); + } + + /** + * @brief Creates tables from XML file + * @param string $file file to read structure from + * @return bool + * + * TODO: write more documentation + */ + public static function createDbFromStructure( $file ) { + $schemaManager = self::getMDB2SchemaManager(); + $result = $schemaManager->createDbFromStructure($file); + return $result; + } + + /** + * @brief update the database schema + * @param string $file file to read structure from + * @throws Exception + * @return bool + */ + public static function updateDbFromStructure($file) { + $schemaManager = self::getMDB2SchemaManager(); + try { + $result = $schemaManager->updateDbFromStructure($file); + } catch (Exception $e) { + OC_Log::write('core', 'Failed to update database structure ('.$e.')', OC_Log::FATAL); + throw $e; + } + return $result; + } + + /** + * @brief drop a table + * @param string $tableName the table to drop + */ + public static function dropTable($tableName) { + $schemaManager = self::getMDB2SchemaManager(); + $schemaManager->dropTable($tableName); + } + + /** + * remove all tables defined in a database structure xml file + * @param string $file the xml file describing the tables + */ + public static function removeDBStructure($file) { + $schemaManager = self::getMDB2SchemaManager(); + $schemaManager->removeDBStructure($file); + } + + /** + * @brief replaces the ownCloud tables with a new set + * @param $file string path to the MDB2 xml db export file + */ + public static function replaceDB( $file ) { + $schemaManager = self::getMDB2SchemaManager(); + $schemaManager->replaceDB($file); + } + + /** + * check if a result is an error, works with Doctrine + * @param mixed $result + * @return bool + */ + public static function isError($result) { + //Doctrine returns false on error (and throws an exception) + return $result === false; + } + /** + * check if a result is an error and throws an exception, works with \Doctrine\DBAL\DBALException + * @param mixed $result + * @param string $message + * @return void + * @throws DatabaseException + */ + public static function raiseExceptionOnError($result, $message = null) { + if(self::isError($result)) { + if ($message === null) { + $message = self::getErrorMessage($result); + } else { + $message .= ', Root cause:' . self::getErrorMessage($result); + } + throw new DatabaseException($message, self::getErrorCode($result)); + } + } + + public static function getErrorCode($error) { + $code = self::$connection->errorCode(); + return $code; + } + /** + * returns the error code and message as a string for logging + * works with DoctrineException + * @param mixed $error + * @return string + */ + public static function getErrorMessage($error) { + if (self::$connection) { + return self::$connection->getError(); + } + return ''; + } + + /** + * @param bool $enabled + */ + static public function enableCaching($enabled) { + if ($enabled) { + self::$connection->enableQueryStatementCaching(); + } else { + self::$connection->disableQueryStatementCaching(); + } + } +} diff --git a/lib/private/db/adapter.php b/lib/private/db/adapter.php new file mode 100644 index 00000000000..6b31f37dd98 --- /dev/null +++ b/lib/private/db/adapter.php @@ -0,0 +1,72 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\DB; + +/** + * This handles the way we use to write queries, into something that can be + * handled by the database abstraction layer. + */ +class Adapter { + + /** + * @var \OC\DB\Connection $conn + */ + protected $conn; + + public function __construct($conn) { + $this->conn = $conn; + } + + /** + * @param string $table name + * @return int id of last insert statement + */ + public function lastInsertId($table) { + return $this->conn->realLastInsertId($table); + } + + /** + * @param string $statement that needs to be changed so the db can handle it + * @return string changed statement + */ + public function fixupStatement($statement) { + return $statement; + } + + /** + * @brief insert the @input values when they do not exist yet + * @param string $table name + * @param array $input key->value pairs + * @return int count of inserted rows + */ + public function insertIfNotExist($table, $input) { + $query = 'INSERT INTO `' .$table . '` (`' + . implode('`,`', array_keys($input)) . '`) SELECT ' + . str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative? + . 'FROM `' . $table . '` WHERE '; + + foreach($input as $key => $value) { + $query .= '`' . $key . '` = ? AND '; + } + $query = substr($query, 0, strlen($query) - 5); + $query .= ' HAVING COUNT(*) = 0'; + $inserts = array_values($input); + $inserts = array_merge($inserts, $inserts); + + try { + return $this->conn->executeUpdate($query, $inserts); + } catch(\Doctrine\DBAL\DBALException $e) { + $entry = 'DB Error: "'.$e->getMessage() . '"
'; + $entry .= 'Offending command was: ' . $query.'
'; + \OC_Log::write('core', $entry, \OC_Log::FATAL); + error_log('DB error: ' . $entry); + \OC_Template::printErrorPage( $entry ); + } + } +} diff --git a/lib/private/db/adapteroci8.php b/lib/private/db/adapteroci8.php new file mode 100644 index 00000000000..bc226e979ec --- /dev/null +++ b/lib/private/db/adapteroci8.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +namespace OC\DB; + +class AdapterOCI8 extends Adapter { + public function lastInsertId($table) { + if($table !== null) { + $suffix = '_SEQ'; + $table = '"'.$table.$suffix.'"'; + } + return $this->conn->realLastInsertId($table); + } + + const UNIX_TIMESTAMP_REPLACEMENT = "(cast(sys_extract_utc(systimestamp) as date) - date'1970-01-01') * 86400"; + public function fixupStatement($statement) { + $statement = str_replace( '`', '"', $statement ); + $statement = str_ireplace( 'NOW()', 'CURRENT_TIMESTAMP', $statement ); + $statement = str_ireplace( 'UNIX_TIMESTAMP()', self::UNIX_TIMESTAMP_REPLACEMENT, $statement ); + return $statement; + } +} diff --git a/lib/private/db/adapterpgsql.php b/lib/private/db/adapterpgsql.php new file mode 100644 index 00000000000..990d71c9f29 --- /dev/null +++ b/lib/private/db/adapterpgsql.php @@ -0,0 +1,23 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +namespace OC\DB; + +class AdapterPgSql extends Adapter { + public function lastInsertId($table) { + return $this->conn->fetchColumn('SELECT lastval()'); + } + + const UNIX_TIMESTAMP_REPLACEMENT = 'cast(extract(epoch from current_timestamp) as integer)'; + public function fixupStatement($statement) { + $statement = str_replace( '`', '"', $statement ); + $statement = str_ireplace( 'UNIX_TIMESTAMP()', self::UNIX_TIMESTAMP_REPLACEMENT, $statement ); + return $statement; + } +} diff --git a/lib/private/db/adaptersqlite.php b/lib/private/db/adaptersqlite.php new file mode 100644 index 00000000000..fa6d308ae32 --- /dev/null +++ b/lib/private/db/adaptersqlite.php @@ -0,0 +1,60 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +namespace OC\DB; + +class AdapterSqlite extends Adapter { + public function fixupStatement($statement) { + $statement = str_replace( '`', '"', $statement ); + $statement = str_ireplace( 'NOW()', 'datetime(\'now\')', $statement ); + $statement = str_ireplace( 'UNIX_TIMESTAMP()', 'strftime(\'%s\',\'now\')', $statement ); + return $statement; + } + + public function insertIfNotExist($table, $input) { + // NOTE: For SQLite we have to use this clumsy approach + // otherwise all fieldnames used must have a unique key. + $query = 'SELECT COUNT(*) FROM `' . $table . '` WHERE '; + foreach($input as $key => $value) { + $query .= '`' . $key . '` = ? AND '; + } + $query = substr($query, 0, strlen($query) - 5); + try { + $stmt = $this->conn->prepare($query); + $result = $stmt->execute(array_values($input)); + } catch(\Doctrine\DBAL\DBALException $e) { + $entry = 'DB Error: "'.$e->getMessage() . '"
'; + $entry .= 'Offending command was: ' . $query . '
'; + \OC_Log::write('core', $entry, \OC_Log::FATAL); + error_log('DB error: '.$entry); + \OC_Template::printErrorPage( $entry ); + } + + if ($stmt->fetchColumn() === '0') { + $query = 'INSERT INTO `' . $table . '` (`' + . implode('`,`', array_keys($input)) . '`) VALUES(' + . str_repeat('?,', count($input)-1).'? ' . ')'; + } else { + return 0; //no rows updated + } + + try { + $statement = $this->conn->prepare($query); + $result = $statement->execute(array_values($input)); + } catch(\Doctrine\DBAL\DBALException $e) { + $entry = 'DB Error: "'.$e->getMessage() . '"
'; + $entry .= 'Offending command was: ' . $query.'
'; + \OC_Log::write('core', $entry, \OC_Log::FATAL); + error_log('DB error: ' . $entry); + \OC_Template::printErrorPage( $entry ); + } + + return $result; + } +} diff --git a/lib/private/db/adaptersqlsrv.php b/lib/private/db/adaptersqlsrv.php new file mode 100644 index 00000000000..d0a67af28a7 --- /dev/null +++ b/lib/private/db/adaptersqlsrv.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +namespace OC\DB; + +class AdapterSQLSrv extends Adapter { + public function lastInsertId($table) { + if($table !== null) { + $table = $this->conn->replaceTablePrefix( $table ); + } + return $this->conn->lastInsertId($table); + } + + public function fixupStatement($statement) { + $statement = preg_replace( "/\`(.*?)`/", "[$1]", $statement ); + $statement = str_ireplace( 'NOW()', 'CURRENT_TIMESTAMP', $statement ); + $statement = str_replace( 'LENGTH(', 'LEN(', $statement ); + $statement = str_replace( 'SUBSTR(', 'SUBSTRING(', $statement ); + $statement = str_ireplace( 'UNIX_TIMESTAMP()', 'DATEDIFF(second,{d \'1970-01-01\'},GETDATE())', $statement ); + return $statement; + } +} diff --git a/lib/private/db/connection.php b/lib/private/db/connection.php new file mode 100644 index 00000000000..2d3193a148a --- /dev/null +++ b/lib/private/db/connection.php @@ -0,0 +1,197 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\DB; +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\Cache\QueryCacheProfile; +use Doctrine\Common\EventManager; + +class Connection extends \Doctrine\DBAL\Connection implements \OCP\IDBConnection { + /** + * @var string $tablePrefix + */ + protected $tablePrefix; + + /** + * @var \OC\DB\Adapter $adapter + */ + protected $adapter; + + /** + * @var \Doctrine\DBAL\Driver\Statement[] $preparedQueries + */ + protected $preparedQueries = array(); + + protected $cachingQueryStatementEnabled = true; + + /** + * Initializes a new instance of the Connection class. + * + * @param array $params The connection parameters. + * @param \Doctrine\DBAL\Driver $driver + * @param \Doctrine\DBAL\Configuration $config + * @param \Doctrine\Common\EventManager $eventManager + * @throws \Exception + */ + public function __construct(array $params, Driver $driver, Configuration $config = null, + EventManager $eventManager = null) + { + if (!isset($params['adapter'])) { + throw new \Exception('adapter not set'); + } + if (!isset($params['tablePrefix'])) { + throw new \Exception('tablePrefix not set'); + } + parent::__construct($params, $driver, $config, $eventManager); + $this->adapter = new $params['adapter']($this); + $this->tablePrefix = $params['tablePrefix']; + } + + /** + * Prepares an SQL statement. + * + * @param string $statement The SQL statement to prepare. + * @param int $limit + * @param int $offset + * @return \Doctrine\DBAL\Driver\Statement The prepared statement. + */ + public function prepare( $statement, $limit=null, $offset=null ) { + if ($limit === -1) { + $limit = null; + } + if (!is_null($limit)) { + $platform = $this->getDatabasePlatform(); + $statement = $platform->modifyLimitQuery($statement, $limit, $offset); + } else { + if (isset($this->preparedQueries[$statement]) && $this->cachingQueryStatementEnabled) { + return $this->preparedQueries[$statement]; + } + $origStatement = $statement; + } + $statement = $this->replaceTablePrefix($statement); + $statement = $this->adapter->fixupStatement($statement); + + if(\OC_Config::getValue( 'log_query', false)) { + \OC_Log::write('core', 'DB prepare : '.$statement, \OC_Log::DEBUG); + } + $result = parent::prepare($statement); + if (is_null($limit) && $this->cachingQueryStatementEnabled) { + $this->preparedQueries[$origStatement] = $result; + } + return $result; + } + + /** + * Executes an, optionally parameterized, SQL query. + * + * If the query is parameterized, a prepared statement is used. + * If an SQLLogger is configured, the execution is logged. + * + * @param string $query The SQL query to execute. + * @param array $params The parameters to bind to the query, if any. + * @param array $types The types the previous parameters are in. + * @param QueryCacheProfile $qcp + * @return \Doctrine\DBAL\Driver\Statement The executed statement. + * @internal PERF: Directly prepares a driver statement, not a wrapper. + */ + public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null) + { + $query = $this->replaceTablePrefix($query); + $query = $this->adapter->fixupStatement($query); + return parent::executeQuery($query, $params, $types, $qcp); + } + + /** + * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters + * and returns the number of affected rows. + * + * This method supports PDO binding types as well as DBAL mapping types. + * + * @param string $query The SQL query. + * @param array $params The query parameters. + * @param array $types The parameter types. + * @return integer The number of affected rows. + * @internal PERF: Directly prepares a driver statement, not a wrapper. + */ + public function executeUpdate($query, array $params = array(), array $types = array()) + { + $query = $this->replaceTablePrefix($query); + $query = $this->adapter->fixupStatement($query); + return parent::executeUpdate($query, $params, $types); + } + + /** + * Returns the ID of the last inserted row, or the last value from a sequence object, + * depending on the underlying driver. + * + * Note: This method may not return a meaningful or consistent result across different drivers, + * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY + * columns or sequences. + * + * @param string $seqName Name of the sequence object from which the ID should be returned. + * @return string A string representation of the last inserted ID. + */ + public function lastInsertId($seqName = null) + { + if ($seqName) { + $seqName = $this->replaceTablePrefix($seqName); + } + return $this->adapter->lastInsertId($seqName); + } + + // internal use + public function realLastInsertId($seqName = null) + { + return parent::lastInsertId($seqName); + } + + /** + * @brief Insert a row if a matching row doesn't exists. + * @param string $table. The table to insert into in the form '*PREFIX*tableName' + * @param array $input. An array of fieldname/value pairs + * @return bool The return value from execute() + */ + public function insertIfNotExist($table, $input) { + return $this->adapter->insertIfNotExist($table, $input); + } + + /** + * returns the error code and message as a string for logging + * works with DoctrineException + * @return string + */ + public function getError() { + $msg = $this->errorCode() . ': '; + $errorInfo = $this->errorInfo(); + if (is_array($errorInfo)) { + $msg .= 'SQLSTATE = '.$errorInfo[0] . ', '; + $msg .= 'Driver Code = '.$errorInfo[1] . ', '; + $msg .= 'Driver Message = '.$errorInfo[2]; + } + return $msg; + } + + // internal use + /** + * @param string $statement + * @return string + */ + protected function replaceTablePrefix($statement) { + return str_replace( '*PREFIX*', $this->tablePrefix, $statement ); + } + + public function enableQueryStatementCaching() { + $this->cachingQueryStatementEnabled = true; + } + + public function disableQueryStatementCaching() { + $this->cachingQueryStatementEnabled = false; + $this->preparedQueries = array(); + } +} diff --git a/lib/private/db/mdb2schemamanager.php b/lib/private/db/mdb2schemamanager.php new file mode 100644 index 00000000000..8e76f46c78f --- /dev/null +++ b/lib/private/db/mdb2schemamanager.php @@ -0,0 +1,150 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\DB; + +class MDB2SchemaManager { + /** + * @var \OC\DB\Connection $conn + */ + protected $conn; + + /** + * @param \OC\DB\Connection $conn + */ + public function __construct($conn) { + $this->conn = $conn; + } + + /** + * @brief saves database scheme to xml file + * @param string $file name of file + * @param int|string $mode + * @return bool + * + * TODO: write more documentation + */ + public function getDbStructure( $file, $mode = MDB2_SCHEMA_DUMP_STRUCTURE) { + $sm = $this->conn->getSchemaManager(); + + return \OC_DB_MDB2SchemaWriter::saveSchemaToFile($file, $sm); + } + + /** + * @brief Creates tables from XML file + * @param string $file file to read structure from + * @return bool + * + * TODO: write more documentation + */ + public function createDbFromStructure( $file ) { + $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); + $toSchema = $schemaReader->loadSchemaFromFile($file); + return $this->executeSchemaChange($toSchema); + } + + /** + * @brief update the database scheme + * @param string $file file to read structure from + * @return bool + */ + public function updateDbFromStructure($file) { + $sm = $this->conn->getSchemaManager(); + $fromSchema = $sm->createSchema(); + + $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); + $toSchema = $schemaReader->loadSchemaFromFile($file); + + // remove tables we don't know about + foreach($fromSchema->getTables() as $table) { + if (!$toSchema->hasTable($table->getName())) { + $fromSchema->dropTable($table->getName()); + } + } + // remove sequences we don't know about + foreach($fromSchema->getSequences() as $table) { + if (!$toSchema->hasSequence($table->getName())) { + $fromSchema->dropSequence($table->getName()); + } + } + + $comparator = new \Doctrine\DBAL\Schema\Comparator(); + $schemaDiff = $comparator->compare($fromSchema, $toSchema); + + $platform = $this->conn->getDatabasePlatform(); + $tables = $schemaDiff->newTables + $schemaDiff->changedTables + $schemaDiff->removedTables; + foreach($tables as $tableDiff) { + $tableDiff->name = $platform->quoteIdentifier($tableDiff->name); + } + + return $this->executeSchemaChange($schemaDiff); + } + + /** + * @brief drop a table + * @param string $tableName the table to drop + */ + public function dropTable($tableName) { + $sm = $this->conn->getSchemaManager(); + $fromSchema = $sm->createSchema(); + $toSchema = clone $fromSchema; + $toSchema->dropTable($tableName); + $sql = $fromSchema->getMigrateToSql($toSchema, $this->conn->getDatabasePlatform()); + $this->conn->executeQuery($sql); + } + + /** + * remove all tables defined in a database structure xml file + * @param string $file the xml file describing the tables + */ + public function removeDBStructure($file) { + $schemaReader = new MDB2SchemaReader(\OC_Config::getObject(), $this->conn->getDatabasePlatform()); + $fromSchema = $schemaReader->loadSchemaFromFile($file); + $toSchema = clone $fromSchema; + foreach($toSchema->getTables() as $table) { + $toSchema->dropTable($table->getName()); + } + $comparator = new \Doctrine\DBAL\Schema\Comparator(); + $schemaDiff = $comparator->compare($fromSchema, $toSchema); + $this->executeSchemaChange($schemaDiff); + } + + /** + * @brief replaces the ownCloud tables with a new set + * @param $file string path to the MDB2 xml db export file + */ + public function replaceDB( $file ) { + $apps = \OC_App::getAllApps(); + $this->conn->beginTransaction(); + // Delete the old tables + $this->removeDBStructure( \OC::$SERVERROOT . '/db_structure.xml' ); + + foreach($apps as $app) { + $path = \OC_App::getAppPath($app).'/appinfo/database.xml'; + if(file_exists($path)) { + $this->removeDBStructure( $path ); + } + } + + // Create new tables + $this->conn->commit(); + } + + /** + * @param \Doctrine\DBAL\Schema\Schema $schema + * @return bool + */ + private function executeSchemaChange($schema) { + $this->conn->beginTransaction(); + foreach($schema->toSql($this->conn->getDatabasePlatform()) as $sql) { + $this->conn->query($sql); + } + $this->conn->commit(); + return true; + } +} diff --git a/lib/private/db/mdb2schemareader.php b/lib/private/db/mdb2schemareader.php new file mode 100644 index 00000000000..b7128a2f176 --- /dev/null +++ b/lib/private/db/mdb2schemareader.php @@ -0,0 +1,305 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\DB; + +class MDB2SchemaReader { + /** + * @var string $DBNAME + */ + protected $DBNAME; + + /** + * @var string $DBTABLEPREFIX + */ + protected $DBTABLEPREFIX; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + protected $platform; + + /** + * @param \OC\Config $config + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct($config, $platform) { + $this->platform = $platform; + $this->DBNAME = $config->getValue('dbname', 'owncloud'); + $this->DBTABLEPREFIX = $config->getValue('dbtableprefix', 'oc_'); + } + + /** + * @param string $file + * @return \Doctrine\DBAL\Schema\Schema + * @throws \DomainException + */ + public function loadSchemaFromFile($file) { + $schema = new \Doctrine\DBAL\Schema\Schema(); + $xml = simplexml_load_file($file); + foreach ($xml->children() as $child) { + /** + * @var \SimpleXMLElement $child + */ + switch ($child->getName()) { + case 'name': + case 'create': + case 'overwrite': + case 'charset': + break; + case 'table': + $this->loadTable($schema, $child); + break; + default: + throw new \DomainException('Unknown element: ' . $child->getName()); + + } + } + return $schema; + } + + /** + * @param\Doctrine\DBAL\Schema\Schema $schema + * @param \SimpleXMLElement $xml + * @throws \DomainException + */ + private function loadTable($schema, $xml) { + $table = null; + foreach ($xml->children() as $child) { + /** + * @var \SimpleXMLElement $child + */ + switch ($child->getName()) { + case 'name': + $name = (string)$child; + $name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name); + $name = $this->platform->quoteIdentifier($name); + $table = $schema->createTable($name); + break; + case 'create': + case 'overwrite': + case 'charset': + break; + case 'declaration': + if (is_null($table)) { + throw new \DomainException('Table declaration before table name'); + } + $this->loadDeclaration($table, $child); + break; + default: + throw new \DomainException('Unknown element: ' . $child->getName()); + + } + } + } + + /** + * @param \Doctrine\DBAL\Schema\Table $table + * @param \SimpleXMLElement $xml + * @throws \DomainException + */ + private function loadDeclaration($table, $xml) { + foreach ($xml->children() as $child) { + /** + * @var \SimpleXMLElement $child + */ + switch ($child->getName()) { + case 'field': + $this->loadField($table, $child); + break; + case 'index': + $this->loadIndex($table, $child); + break; + default: + throw new \DomainException('Unknown element: ' . $child->getName()); + + } + } + } + + /** + * @param \Doctrine\DBAL\Schema\Table $table + * @param \SimpleXMLElement $xml + * @throws \DomainException + */ + private function loadField($table, $xml) { + $options = array(); + foreach ($xml->children() as $child) { + /** + * @var \SimpleXMLElement $child + */ + switch ($child->getName()) { + case 'name': + $name = (string)$child; + $name = $this->platform->quoteIdentifier($name); + break; + case 'type': + $type = (string)$child; + switch ($type) { + case 'text': + $type = 'string'; + break; + case 'clob': + $type = 'text'; + break; + case 'timestamp': + $type = 'datetime'; + break; + } + break; + case 'length': + $length = (string)$child; + $options['length'] = $length; + break; + case 'unsigned': + $unsigned = $this->asBool($child); + $options['unsigned'] = $unsigned; + break; + case 'notnull': + $notnull = $this->asBool($child); + $options['notnull'] = $notnull; + break; + case 'autoincrement': + $autoincrement = $this->asBool($child); + $options['autoincrement'] = $autoincrement; + break; + case 'default': + $default = (string)$child; + $options['default'] = $default; + break; + case 'comments': + $comment = (string)$child; + $options['comment'] = $comment; + break; + case 'primary': + $primary = $this->asBool($child); + $options['primary'] = $primary; + break; + default: + throw new \DomainException('Unknown element: ' . $child->getName()); + + } + } + if (isset($name) && isset($type)) { + if (empty($options['default'])) { + if (empty($options['notnull']) || !$options['notnull']) { + unset($options['default']); + $options['notnull'] = false; + } else { + $options['default'] = ''; + } + if ($type == 'integer') { + $options['default'] = 0; + } elseif ($type == 'boolean') { + $options['default'] = false; + } + if (!empty($options['autoincrement']) && $options['autoincrement']) { + unset($options['default']); + } + } + if ($type === 'integer' && isset($options['default'])) { + $options['default'] = (int)$options['default']; + } + if ($type === 'integer' && isset($options['length'])) { + $length = $options['length']; + if ($length < 4) { + $type = 'smallint'; + } else if ($length > 4) { + $type = 'bigint'; + } + } + if ($type === 'boolean' && isset($options['default'])) { + $options['default'] = $this->asBool($options['default']); + } + if (!empty($options['autoincrement']) + && !empty($options['notnull']) + ) { + $options['primary'] = true; + } + $table->addColumn($name, $type, $options); + if (!empty($options['primary']) && $options['primary']) { + $table->setPrimaryKey(array($name)); + } + } + } + + /** + * @param \Doctrine\DBAL\Schema\Table $table + * @param \SimpleXMLElement $xml + * @throws \DomainException + */ + private function loadIndex($table, $xml) { + $name = null; + $fields = array(); + foreach ($xml->children() as $child) { + /** + * @var \SimpleXMLElement $child + */ + switch ($child->getName()) { + case 'name': + $name = (string)$child; + break; + case 'primary': + $primary = $this->asBool($child); + break; + case 'unique': + $unique = $this->asBool($child); + break; + case 'field': + foreach ($child->children() as $field) { + /** + * @var \SimpleXMLElement $field + */ + switch ($field->getName()) { + case 'name': + $field_name = (string)$field; + $field_name = $this->platform->quoteIdentifier($field_name); + $fields[] = $field_name; + break; + case 'sorting': + break; + default: + throw new \DomainException('Unknown element: ' . $field->getName()); + + } + } + break; + default: + throw new \DomainException('Unknown element: ' . $child->getName()); + + } + } + if (!empty($fields)) { + if (isset($primary) && $primary) { + $table->setPrimaryKey($fields, $name); + } else + if (isset($unique) && $unique) { + $table->addUniqueIndex($fields, $name); + } else { + $table->addIndex($fields, $name); + } + } else { + throw new \DomainException('Empty index definition: ' . $name . ' options:' . print_r($fields, true)); + } + } + + /** + * @param \SimpleXMLElement | string $xml + * @return bool + */ + private function asBool($xml) { + $result = (string)$xml; + if ($result == 'true') { + $result = true; + } elseif ($result == 'false') { + $result = false; + } + return (bool)$result; + } + +} diff --git a/lib/private/db/mdb2schemawriter.php b/lib/private/db/mdb2schemawriter.php new file mode 100644 index 00000000000..21b43cbfe80 --- /dev/null +++ b/lib/private/db/mdb2schemawriter.php @@ -0,0 +1,133 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_DB_MDB2SchemaWriter { + + /** + * @param $file + * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $sm + * @return bool + */ + static public function saveSchemaToFile($file, $sm) { + $xml = new SimpleXMLElement(''); + $xml->addChild('name', OC_Config::getValue( "dbname", "owncloud" )); + $xml->addChild('create', 'true'); + $xml->addChild('overwrite', 'false'); + $xml->addChild('charset', 'utf8'); + foreach ($sm->listTables() as $table) { + self::saveTable($table, $xml->addChild('table')); + } + file_put_contents($file, $xml->asXML()); + return true; + } + + private static function saveTable($table, $xml) { + $xml->addChild('name', $table->getName()); + $declaration = $xml->addChild('declaration'); + foreach($table->getColumns() as $column) { + self::saveColumn($column, $declaration->addChild('field')); + } + foreach($table->getIndexes() as $index) { + if ($index->getName() == 'PRIMARY') { + $autoincrement = false; + foreach($index->getColumns() as $column) { + if ($table->getColumn($column)->getAutoincrement()) { + $autoincrement = true; + } + } + if ($autoincrement) { + continue; + } + } + self::saveIndex($index, $declaration->addChild('index')); + } + } + + private static function saveColumn($column, $xml) { + $xml->addChild('name', $column->getName()); + switch($column->getType()) { + case 'SmallInt': + case 'Integer': + case 'BigInt': + $xml->addChild('type', 'integer'); + $default = $column->getDefault(); + if (is_null($default) && $column->getAutoincrement()) { + $default = '0'; + } + $xml->addChild('default', $default); + $xml->addChild('notnull', self::toBool($column->getNotnull())); + if ($column->getAutoincrement()) { + $xml->addChild('autoincrement', '1'); + } + if ($column->getUnsigned()) { + $xml->addChild('unsigned', 'true'); + } + $length = '4'; + if ($column->getType() == 'SmallInt') { + $length = '2'; + } + elseif ($column->getType() == 'BigInt') { + $length = '8'; + } + $xml->addChild('length', $length); + break; + case 'String': + $xml->addChild('type', 'text'); + $default = trim($column->getDefault()); + if ($default === '') { + $default = false; + } + $xml->addChild('default', $default); + $xml->addChild('notnull', self::toBool($column->getNotnull())); + $xml->addChild('length', $column->getLength()); + break; + case 'Text': + $xml->addChild('type', 'clob'); + $xml->addChild('notnull', self::toBool($column->getNotnull())); + break; + case 'Decimal': + $xml->addChild('type', 'decimal'); + $xml->addChild('default', $column->getDefault()); + $xml->addChild('notnull', self::toBool($column->getNotnull())); + $xml->addChild('length', '15'); + break; + case 'Boolean': + $xml->addChild('type', 'integer'); + $xml->addChild('default', $column->getDefault()); + $xml->addChild('notnull', self::toBool($column->getNotnull())); + $xml->addChild('length', '1'); + break; + case 'DateTime': + $xml->addChild('type', 'timestamp'); + $xml->addChild('default', $column->getDefault()); + $xml->addChild('notnull', self::toBool($column->getNotnull())); + break; + + } + } + + private static function saveIndex($index, $xml) { + $xml->addChild('name', $index->getName()); + if ($index->isPrimary()) { + $xml->addChild('primary', 'true'); + } + elseif ($index->isUnique()) { + $xml->addChild('unique', 'true'); + } + foreach($index->getColumns() as $column) { + $field = $xml->addChild('field'); + $field->addChild('name', $column); + $field->addChild('sorting', 'ascending'); + + } + } + + private static function toBool($bool) { + return $bool ? 'true' : 'false'; + } +} diff --git a/lib/private/db/oracleconnection.php b/lib/private/db/oracleconnection.php new file mode 100644 index 00000000000..e2fc4644f47 --- /dev/null +++ b/lib/private/db/oracleconnection.php @@ -0,0 +1,50 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\DB; + +class OracleConnection extends Connection { + /** + * Quote the keys of the array + */ + private function quoteKeys(array $data) { + $return = array(); + foreach($data as $key => $value) { + $return[$this->quoteIdentifier($key)] = $value; + } + return $return; + } + + /* + * {@inheritDoc} + */ + public function insert($tableName, array $data, array $types = array()) { + $tableName = $this->quoteIdentifier($tableName); + $data = $this->quoteKeys($data); + return parent::insert($tableName, $data, $types); + } + + /* + * {@inheritDoc} + */ + public function update($tableName, array $data, array $identifier, array $types = array()) { + $tableName = $this->quoteIdentifier($tableName); + $data = $this->quoteKeys($data); + $identifier = $this->quoteKeys($identifier); + return parent::update($tableName, $data, $identifier, $types); + } + + /* + * {@inheritDoc} + */ + public function delete($tableName, array $identifier) { + $tableName = $this->quoteIdentifier($tableName); + $identifier = $this->quoteKeys($identifier); + return parent::delete($tableName, $identifier); + } +} diff --git a/lib/private/db/statementwrapper.php b/lib/private/db/statementwrapper.php new file mode 100644 index 00000000000..b8da1afc0e5 --- /dev/null +++ b/lib/private/db/statementwrapper.php @@ -0,0 +1,191 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * small wrapper around \Doctrine\DBAL\Driver\Statement to make it behave, more like an MDB2 Statement + */ +class OC_DB_StatementWrapper { + /** + * @var \Doctrine\DBAL\Driver\Statement + */ + private $statement = null; + private $isManipulation = false; + private $lastArguments = array(); + + public function __construct($statement, $isManipulation) { + $this->statement = $statement; + $this->isManipulation = $isManipulation; + } + + /** + * pass all other function directly to the \Doctrine\DBAL\Driver\Statement + */ + public function __call($name,$arguments) { + return call_user_func_array(array($this->statement,$name), $arguments); + } + + /** + * provide numRows + */ + public function numRows() { + $type = OC_Config::getValue( "dbtype", "sqlite" ); + if ($type == 'oci') { + // OCI doesn't have a queryString, just do a rowCount for now + return $this->statement->rowCount(); + } + $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i'; + $queryString = $this->statement->getWrappedStatement()->queryString; + if (preg_match($regex, $queryString, $output) > 0) { + $query = OC_DB::prepare("SELECT COUNT(*) FROM {$output[1]}"); + return $query->execute($this->lastArguments)->fetchColumn(); + }else{ + return $this->statement->rowCount(); + } + } + + /** + * make execute return the result instead of a bool + */ + public function execute($input=array()) { + if(OC_Config::getValue( "log_query", false)) { + $params_str = str_replace("\n", " ", var_export($input, true)); + OC_Log::write('core', 'DB execute with arguments : '.$params_str, OC_Log::DEBUG); + } + $this->lastArguments = $input; + if (count($input) > 0) { + + if (!isset($type)) { + $type = OC_Config::getValue( "dbtype", "sqlite" ); + } + + if ($type == 'mssql') { + $input = $this->tryFixSubstringLastArgumentDataForMSSQL($input); + } + + $result = $this->statement->execute($input); + } else { + $result = $this->statement->execute(); + } + + if ($result === false) { + return false; + } + if ($this->isManipulation) { + return $this->statement->rowCount(); + } else { + return $this; + } + } + + private function tryFixSubstringLastArgumentDataForMSSQL($input) { + $query = $this->statement->getWrappedStatement()->queryString; + $pos = stripos ($query, 'SUBSTRING'); + + if ( $pos === false) { + return $input; + } + + try { + $newQuery = ''; + + $cArg = 0; + + $inSubstring = false; + + // Create new query + for ($i = 0; $i < strlen ($query); $i++) { + if ($inSubstring == false) { + // Defines when we should start inserting values + if (substr ($query, $i, 9) == 'SUBSTRING') { + $inSubstring = true; + } + } else { + // Defines when we should stop inserting values + if (substr ($query, $i, 1) == ')') { + $inSubstring = false; + } + } + + if (substr ($query, $i, 1) == '?') { + // We found a question mark + if ($inSubstring) { + $newQuery .= $input[$cArg]; + + // + // Remove from input array + // + array_splice ($input, $cArg, 1); + } else { + $newQuery .= substr ($query, $i, 1); + $cArg++; + } + } else { + $newQuery .= substr ($query, $i, 1); + } + } + + // The global data we need + $name = OC_Config::getValue( "dbname", "owncloud" ); + $host = OC_Config::getValue( "dbhost", "" ); + $user = OC_Config::getValue( "dbuser", "" ); + $pass = OC_Config::getValue( "dbpassword", "" ); + if (strpos($host, ':')) { + list($host, $port) = explode(':', $host, 2); + } else { + $port = false; + } + $opts = array(); + + if ($port) { + $dsn = 'sqlsrv:Server='.$host.','.$port.';Database='.$name; + } else { + $dsn = 'sqlsrv:Server='.$host.';Database='.$name; + } + + $PDO = new PDO($dsn, $user, $pass, $opts); + $PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); + $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $this->statement = $PDO->prepare($newQuery); + + $this->lastArguments = $input; + + return $input; + } catch (PDOException $e){ + $entry = 'PDO DB Error: "'.$e->getMessage().'"
'; + $entry .= 'Offending command was: '.$this->statement->queryString .'
'; + $entry .= 'Input parameters: ' .print_r($input, true).'
'; + $entry .= 'Stack trace: ' .$e->getTraceAsString().'
'; + OC_Log::write('core', $entry, OC_Log::FATAL); + OC_User::setUserId(null); + + // send http status 503 + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + OC_Template::printErrorPage('Failed to connect to database'); + die ($entry); + } + } + + /** + * provide an alias for fetch + */ + public function fetchRow() { + return $this->statement->fetch(); + } + + /** + * Provide a simple fetchOne. + * fetch single column from the next row + * @param int $colnum the column number to fetch + * @return string + */ + public function fetchOne($colnum = 0) { + return $this->statement->fetchColumn($colnum); + } +} diff --git a/lib/private/defaults.php b/lib/private/defaults.php new file mode 100644 index 00000000000..10813a3e8d8 --- /dev/null +++ b/lib/private/defaults.php @@ -0,0 +1,135 @@ +defaultEntity = "ownCloud"; /* e.g. company name, used for footers and copyright notices */ + $this->defaultName = "ownCloud"; /* short name, used when referring to the software */ + $this->defaultTitle = "ownCloud"; /* can be a longer name, for titles */ + $this->defaultBaseUrl = "http://owncloud.org"; + $this->defaultSyncClientUrl = " http://owncloud.org/sync-clients/"; + $this->defaultDocBaseUrl = "http://doc.owncloud.org"; + $this->defaultSlogan = $l->t("web services under your control"); + $this->defaultLogoClaim = ""; + + if (class_exists("OC_Theme")) { + $this->theme = new OC_Theme(); + } + } + + private function themeExist($method) { + if (OC_Util::getTheme() !== '' && method_exists('OC_Theme', $method)) { + return true; + } + return false; + } + + public function getBaseUrl() { + if ($this->themeExist('getBaseUrl')) { + return $this->theme->getBaseUrl(); + } else { + return $this->defaultBaseUrl; + } + } + + public function getSyncClientUrl() { + if ($this->themeExist('getSyncClientUrl')) { + return $this->theme->getSyncClientUrl(); + } else { + return $this->defaultSyncClientUrl; + } + } + + public function getDocBaseUrl() { + if ($this->themeExist('getDocBaseUrl')) { + return $this->theme->getDocBaseUrl(); + } else { + return $this->defaultDocBaseUrl; + } + } + + public function getTitle() { + if ($this->themeExist('getTitle')) { + return $this->theme->getTitle(); + } else { + return $this->defaultTitle; + } + } + + public function getName() { + if ($this->themeExist('getName')) { + return $this->theme->getName(); + } else { + return $this->defaultName; + } + } + + public function getEntity() { + if ($this->themeExist('getEntity')) { + return $this->theme->getEntity(); + } else { + return $this->defaultEntity; + } + } + + public function getSlogan() { + if ($this->themeExist('getSlogan')) { + return $this->theme->getSlogan(); + } else { + return $this->defaultSlogan; + } + } + + public function getLogoClaim() { + if ($this->themeExist('getLogoClaim')) { + return $this->theme->getLogoClaim(); + } else { + return $this->defaultLogoClaim; + } + } + + public function getShortFooter() { + if ($this->themeExist('getShortFooter')) { + $footer = $this->theme->getShortFooter(); + } else { + $footer = "getBaseUrl() . "\" target=\"_blank\">" .$this->getEntity() . "". + ' – ' . $this->getSlogan(); + } + + return $footer; + } + + public function getLongFooter() { + if ($this->themeExist('getLongFooter')) { + $footer = $this->theme->getLongFooter(); + } else { + $footer = $this->getShortFooter(); + } + + return $footer; + } + +} diff --git a/lib/private/eventsource.php b/lib/private/eventsource.php new file mode 100644 index 00000000000..a83084d9251 --- /dev/null +++ b/lib/private/eventsource.php @@ -0,0 +1,85 @@ +. +* +*/ + +/** + * wrapper for server side events (http://en.wikipedia.org/wiki/Server-sent_events) + * includes a fallback for older browsers and IE + * + * use server side events with caution, to many open requests can hang the server + */ +class OC_EventSource{ + private $fallback; + private $fallBackId=0; + + public function __construct() { + OC_Util::obEnd(); + header('Cache-Control: no-cache'); + $this->fallback=isset($_GET['fallback']) and $_GET['fallback']=='true'; + if($this->fallback) { + $this->fallBackId=$_GET['fallback_id']; + header("Content-Type: text/html"); + echo str_repeat(''.PHP_EOL, 10); //dummy data to keep IE happy + }else{ + header("Content-Type: text/event-stream"); + } + if( !OC_Util::isCallRegistered()) { + $this->send('error', 'Possible CSRF attack. Connection will be closed.'); + exit(); + } + flush(); + + } + + /** + * send a message to the client + * @param string $type + * @param mixed $data + * + * if only one parameter is given, a typeless message will be send with that parameter as data + */ + public function send($type, $data=null) { + if(is_null($data)) { + $data=$type; + $type=null; + } + if($this->fallback) { + $response=''.PHP_EOL; + echo $response; + }else{ + if($type) { + echo 'event: '.$type.PHP_EOL; + } + echo 'data: '.json_encode($data).PHP_EOL; + } + echo PHP_EOL; + flush(); + } + + /** + * close the connection of the even source + */ + public function close() { + $this->send('__internal__', 'close');//server side closing can be an issue, let the client do it + } +} diff --git a/lib/private/filechunking.php b/lib/private/filechunking.php new file mode 100644 index 00000000000..313a6ee87d2 --- /dev/null +++ b/lib/private/filechunking.php @@ -0,0 +1,149 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +class OC_FileChunking { + protected $info; + protected $cache; + + static public function decodeName($name) { + preg_match('/(?P.*)-chunking-(?P\d+)-(?P\d+)-(?P\d+)/', $name, $matches); + return $matches; + } + + public function __construct($info) { + $this->info = $info; + } + + public function getPrefix() { + $name = $this->info['name']; + $transferid = $this->info['transferid']; + + return $name.'-chunking-'.$transferid.'-'; + } + + protected function getCache() { + if (!isset($this->cache)) { + $this->cache = new \OC\Cache\File(); + } + return $this->cache; + } + + public function store($index, $data) { + $cache = $this->getCache(); + $name = $this->getPrefix().$index; + $cache->set($name, $data); + } + + public function isComplete() { + $prefix = $this->getPrefix(); + $parts = 0; + $cache = $this->getCache(); + for($i=0; $i < $this->info['chunkcount']; $i++) { + if ($cache->hasKey($prefix.$i)) { + $parts ++; + } + } + return $parts == $this->info['chunkcount']; + } + + public function assemble($f) { + $cache = $this->getCache(); + $prefix = $this->getPrefix(); + $count = 0; + for($i=0; $i < $this->info['chunkcount']; $i++) { + $chunk = $cache->get($prefix.$i); + $cache->remove($prefix.$i); + $count += fwrite($f, $chunk); + } + return $count; + } + + public function signature_split($orgfile, $input) { + $info = unpack('n', fread($input, 2)); + $blocksize = $info[1]; + $this->info['transferid'] = mt_rand(); + $count = 0; + $needed = array(); + $cache = $this->getCache(); + $prefix = $this->getPrefix(); + while (!feof($orgfile)) { + $new_md5 = fread($input, 16); + if (feof($input)) { + break; + } + $data = fread($orgfile, $blocksize); + $org_md5 = md5($data, true); + if ($org_md5 == $new_md5) { + $cache->set($prefix.$count, $data); + } else { + $needed[] = $count; + } + $count++; + } + return array( + 'transferid' => $this->info['transferid'], + 'needed' => $needed, + 'count' => $count, + ); + } + + public function file_assemble($path) { + $absolutePath = \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getView()->getAbsolutePath($path)); + $data = ''; + // use file_put_contents as method because that best matches what this function does + if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) + && \OC\Files\Filesystem::isValidPath($path)) { + $path = \OC\Files\Filesystem::getView()->getRelativePath($absolutePath); + $exists = \OC\Files\Filesystem::file_exists($path); + $run = true; + if(!$exists) { + OC_Hook::emit( + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_create, + array( + \OC\Files\Filesystem::signal_param_path => $path, + \OC\Files\Filesystem::signal_param_run => &$run + ) + ); + } + OC_Hook::emit( + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_write, + array( + \OC\Files\Filesystem::signal_param_path => $path, + \OC\Files\Filesystem::signal_param_run => &$run + ) + ); + if(!$run) { + return false; + } + $target = \OC\Files\Filesystem::fopen($path, 'w'); + if($target) { + $count = $this->assemble($target); + fclose($target); + if(!$exists) { + OC_Hook::emit( + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_post_create, + array( \OC\Files\Filesystem::signal_param_path => $path) + ); + } + OC_Hook::emit( + \OC\Files\Filesystem::CLASSNAME, + \OC\Files\Filesystem::signal_post_write, + array( \OC\Files\Filesystem::signal_param_path => $path) + ); + OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); + return $count > 0; + }else{ + return false; + } + } + } +} diff --git a/lib/private/fileproxy.php b/lib/private/fileproxy.php new file mode 100644 index 00000000000..52ec79b4bdb --- /dev/null +++ b/lib/private/fileproxy.php @@ -0,0 +1,115 @@ +. +* +*/ + +/** + * Class for manipulating filesystem requests + * + * Manipulation happens by using 2 kind of proxy operations, pre and post proxies + * that manipulate the filesystem call and the result of the call respectively + * + * A pre-proxy recieves the filepath as arugments (or 2 filespaths in case of + * operations like copy or move) and return a boolean + * If a pre-proxy returns false the file operation will be canceled + * All filesystem operations have a pre-proxy + * + * A post-proxy recieves 2 arguments, the filepath and the result of the operation. + * The return value of the post-proxy will be used as the new result of the operation + * The operations that have a post-proxy are: + * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, + * is_writable, filemtime, filectime, file_get_contents, + * getMimeType, hash, fopen, free_space and search + */ + +class OC_FileProxy{ + private static $proxies=array(); + public static $enabled=true; + + /** + * fallback function when a proxy operation is not implemented + * @param string $function the name of the proxy operation + * @param mixed + * + * this implements a dummy proxy for all operations + */ + public function __call($function, $arguments) { + if(substr($function, 0, 3)=='pre') { + return true; + }else{ + return $arguments[1]; + } + } + + /** + * register a proxy to be used + * @param OC_FileProxy $proxy + */ + public static function register($proxy) { + self::$proxies[]=$proxy; + } + + public static function getProxies($operation) { + $proxies=array(); + foreach(self::$proxies as $proxy) { + if(method_exists($proxy, $operation)) { + $proxies[]=$proxy; + } + } + return $proxies; + } + + public static function runPreProxies($operation,&$filepath,&$filepath2=null) { + if(!self::$enabled) { + return true; + } + $operation='pre'.$operation; + $proxies=self::getProxies($operation); + foreach($proxies as $proxy) { + if(!is_null($filepath2)) { + if($proxy->$operation($filepath, $filepath2)===false) { + return false; + } + }else{ + if($proxy->$operation($filepath)===false) { + return false; + } + } + } + return true; + } + + public static function runPostProxies($operation, $path, $result) { + if(!self::$enabled) { + return $result; + } + $operation='post'.$operation; + $proxies=self::getProxies($operation); + foreach($proxies as $proxy) { + $result=$proxy->$operation($path, $result); + } + return $result; + } + + public static function clearProxies() { + self::$proxies=array(); + } +} diff --git a/lib/private/fileproxy/fileoperations.php b/lib/private/fileproxy/fileoperations.php new file mode 100644 index 00000000000..b2ff2e7e5e9 --- /dev/null +++ b/lib/private/fileproxy/fileoperations.php @@ -0,0 +1,37 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 library. If not, see . + * + */ + +/** + * check if standard file operations + */ + +class OC_FileProxy_FileOperations extends OC_FileProxy{ + static $rootView; + + public function premkdir($path) { + if(!self::$rootView) { + self::$rootView = new \OC\Files\View(''); + } + return !self::$rootView->file_exists($path); + } + +} diff --git a/lib/private/files.php b/lib/private/files.php new file mode 100644 index 00000000000..c705d2adb1a --- /dev/null +++ b/lib/private/files.php @@ -0,0 +1,321 @@ +. + * + */ + +/** + * Class for fileserver access + * + */ +class OC_Files { + static $tmpFiles = array(); + + static public function getFileInfo($path){ + return \OC\Files\Filesystem::getFileInfo($path); + } + + static public function getDirectoryContent($path){ + return \OC\Files\Filesystem::getDirectoryContent($path); + } + + /** + * return the content of a file or return a zip file containing multiple files + * + * @param string $dir + * @param string $file ; separated list of files to download + * @param boolean $only_header ; boolean to only send header of the request + */ + public static function get($dir, $files, $only_header = false) { + $xsendfile = false; + if (isset($_SERVER['MOD_X_SENDFILE_ENABLED']) || + isset($_SERVER['MOD_X_SENDFILE2_ENABLED']) || + isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) { + $xsendfile = true; + } + + if (is_array($files) && count($files) == 1) { + $files = $files[0]; + } + + if (is_array($files)) { + self::validateZipDownload($dir, $files); + $executionTime = intval(ini_get('max_execution_time')); + set_time_limit(0); + $zip = new ZipArchive(); + $filename = OC_Helper::tmpFile('.zip'); + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { + $l = OC_L10N::get('lib'); + throw new Exception($l->t('cannot open "%s"', array($filename))); + } + foreach ($files as $file) { + $file = $dir . '/' . $file; + if (\OC\Files\Filesystem::is_file($file)) { + $tmpFile = \OC\Files\Filesystem::toTmpFile($file); + self::$tmpFiles[] = $tmpFile; + $zip->addFile($tmpFile, basename($file)); + } elseif (\OC\Files\Filesystem::is_dir($file)) { + self::zipAddDir($file, $zip); + } + } + $zip->close(); + if ($xsendfile) { + $filename = OC_Helper::moveToNoClean($filename); + } + $basename = basename($dir); + if ($basename) { + $name = $basename . '.zip'; + } else { + $name = 'owncloud.zip'; + } + + set_time_limit($executionTime); + } elseif (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) { + self::validateZipDownload($dir, $files); + $executionTime = intval(ini_get('max_execution_time')); + set_time_limit(0); + $zip = new ZipArchive(); + $filename = OC_Helper::tmpFile('.zip'); + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { + $l = OC_L10N::get('lib'); + throw new Exception($l->t('cannot open "%s"', array($filename))); + } + $file = $dir . '/' . $files; + self::zipAddDir($file, $zip); + $zip->close(); + if ($xsendfile) { + $filename = OC_Helper::moveToNoClean($filename); + } + $name = $files . '.zip'; + set_time_limit($executionTime); + } else { + $zip = false; + $filename = $dir . '/' . $files; + $name = $files; + } + OC_Util::obEnd(); + if ($zip or \OC\Files\Filesystem::isReadable($filename)) { + if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) { + header( 'Content-Disposition: attachment; filename="' . rawurlencode($name) . '"' ); + } else { + header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode($name) + . '; filename="' . rawurlencode($name) . '"' ); + } + header('Content-Transfer-Encoding: binary'); + OC_Response::disableCaching(); + if ($zip) { + ini_set('zlib.output_compression', 'off'); + header('Content-Type: application/zip'); + header('Content-Length: ' . filesize($filename)); + self::addSendfileHeader($filename); + }else{ + $filesize = \OC\Files\Filesystem::filesize($filename); + header('Content-Type: '.\OC\Files\Filesystem::getMimeType($filename)); + if ($filesize > -1) { + header("Content-Length: ".$filesize); + } + list($storage) = \OC\Files\Filesystem::resolvePath($filename); + if ($storage instanceof \OC\Files\Storage\Local) { + self::addSendfileHeader(\OC\Files\Filesystem::getLocalFile($filename)); + } + } + } elseif ($zip or !\OC\Files\Filesystem::file_exists($filename)) { + header("HTTP/1.0 404 Not Found"); + $tmpl = new OC_Template('', '404', 'guest'); + $tmpl->assign('file', $name); + $tmpl->printPage(); + } else { + header("HTTP/1.0 403 Forbidden"); + die('403 Forbidden'); + } + if($only_header) { + return ; + } + if ($zip) { + $handle = fopen($filename, 'r'); + if ($handle) { + $chunkSize = 8 * 1024; // 1 MB chunks + while (!feof($handle)) { + echo fread($handle, $chunkSize); + flush(); + } + } + if (!$xsendfile) { + unlink($filename); + } + }else{ + \OC\Files\Filesystem::readfile($filename); + } + foreach (self::$tmpFiles as $tmpFile) { + if (file_exists($tmpFile) and is_file($tmpFile)) { + unlink($tmpFile); + } + } + } + + private static function addSendfileHeader($filename) { + if (isset($_SERVER['MOD_X_SENDFILE_ENABLED'])) { + header("X-Sendfile: " . $filename); + } + if (isset($_SERVER['MOD_X_SENDFILE2_ENABLED'])) { + if (isset($_SERVER['HTTP_RANGE']) && + preg_match("/^bytes=([0-9]+)-([0-9]*)$/", $_SERVER['HTTP_RANGE'], $range)) { + $filelength = filesize($filename); + if ($range[2] == "") { + $range[2] = $filelength - 1; + } + header("Content-Range: bytes $range[1]-$range[2]/" . $filelength); + header("HTTP/1.1 206 Partial content"); + header("X-Sendfile2: " . str_replace(",", "%2c", rawurlencode($filename)) . " $range[1]-$range[2]"); + } else { + header("X-Sendfile: " . $filename); + } + } + + if (isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) { + header("X-Accel-Redirect: " . $filename); + } + } + + public static function zipAddDir($dir, $zip, $internalDir='') { + $dirname=basename($dir); + $zip->addEmptyDir($internalDir.$dirname); + $internalDir.=$dirname.='/'; + $files=OC_Files::getDirectoryContent($dir); + foreach($files as $file) { + $filename=$file['name']; + $file=$dir.'/'.$filename; + if(\OC\Files\Filesystem::is_file($file)) { + $tmpFile=\OC\Files\Filesystem::toTmpFile($file); + OC_Files::$tmpFiles[]=$tmpFile; + $zip->addFile($tmpFile, $internalDir.$filename); + }elseif(\OC\Files\Filesystem::is_dir($file)) { + self::zipAddDir($file, $zip, $internalDir); + } + } + } + + /** + * checks if the selected files are within the size constraint. If not, outputs an error page. + * + * @param dir $dir + * @param files $files + */ + static function validateZipDownload($dir, $files) { + if (!OC_Config::getValue('allowZipDownload', true)) { + $l = OC_L10N::get('lib'); + header("HTTP/1.0 409 Conflict"); + OC_Template::printErrorPage( + $l->t('ZIP download is turned off.'), + $l->t('Files need to be downloaded one by one.') + . '
' . $l->t('Back to Files') . '' + ); + exit; + } + + $zipLimit = OC_Config::getValue('maxZipInputSize', OC_Helper::computerFileSize('800 MB')); + if ($zipLimit > 0) { + $totalsize = 0; + if(!is_array($files)) { + $files = array($files); + } + foreach ($files as $file) { + $path = $dir . '/' . $file; + if(\OC\Files\Filesystem::is_dir($path)) { + foreach (\OC\Files\Filesystem::getDirectoryContent($path) as $i) { + $totalsize += $i['size']; + } + } else { + $totalsize += \OC\Files\Filesystem::filesize($path); + } + } + if ($totalsize > $zipLimit) { + $l = OC_L10N::get('lib'); + header("HTTP/1.0 409 Conflict"); + OC_Template::printErrorPage( + $l->t('Selected files too large to generate zip file.'), + $l->t('Download the files in smaller chunks, seperately or kindly ask your administrator.') + .'
' + . $l->t('Back to Files') . '' + ); + exit; + } + } + } + + /** + * set the maximum upload size limit for apache hosts using .htaccess + * + * @param int size filesisze in bytes + * @return false on failure, size on success + */ + static function setUploadLimit($size) { + //don't allow user to break his config -- upper boundary + if ($size > PHP_INT_MAX) { + //max size is always 1 byte lower than computerFileSize returns + if ($size > PHP_INT_MAX + 1) + return false; + $size -= 1; + } else { + $size = OC_Helper::humanFileSize($size); + $size = substr($size, 0, -1); //strip the B + $size = str_replace(' ', '', $size); //remove the space between the size and the postfix + } + + //don't allow user to break his config -- broken or malicious size input + if (intval($size) == 0) { + return false; + } + + $htaccess = @file_get_contents(OC::$SERVERROOT . '/.htaccess'); //supress errors in case we don't have permissions for + if (!$htaccess) { + return false; + } + + $phpValueKeys = array( + 'upload_max_filesize', + 'post_max_size' + ); + + foreach ($phpValueKeys as $key) { + $pattern = '/php_value ' . $key . ' (\S)*/'; + $setting = 'php_value ' . $key . ' ' . $size; + $hasReplaced = 0; + $content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced); + if ($content !== null) { + $htaccess = $content; + } + if ($hasReplaced == 0) { + $htaccess .= "\n" . $setting; + } + } + + //check for write permissions + if (is_writable(OC::$SERVERROOT . '/.htaccess')) { + file_put_contents(OC::$SERVERROOT . '/.htaccess', $htaccess); + return OC_Helper::computerFileSize($size); + } else { + OC_Log::write('files', + 'Can\'t write upload limit to ' . OC::$SERVERROOT . '/.htaccess. Please check the file permissions', + OC_Log::WARN); + } + return false; + } +} diff --git a/lib/private/files/cache/backgroundwatcher.php b/lib/private/files/cache/backgroundwatcher.php new file mode 100644 index 00000000000..923804f48d0 --- /dev/null +++ b/lib/private/files/cache/backgroundwatcher.php @@ -0,0 +1,104 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +use \OC\Files\Mount; +use \OC\Files\Filesystem; + +class BackgroundWatcher { + static $folderMimetype = null; + + static private function getFolderMimetype() { + if (!is_null(self::$folderMimetype)) { + return self::$folderMimetype; + } + $sql = 'SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'; + $result = \OC_DB::executeAudited($sql, array('httpd/unix-directory')); + $row = $result->fetchRow(); + return $row['id']; + } + + static private function checkUpdate($id) { + $cacheItem = Cache::getById($id); + if (is_null($cacheItem)) { + return; + } + list($storageId, $internalPath) = $cacheItem; + $mounts = Filesystem::getMountByStorageId($storageId); + + if (count($mounts) === 0) { + //if the storage we need isn't mounted on default, try to find a user that has access to the storage + $permissionsCache = new Permissions($storageId); + $users = $permissionsCache->getUsers($id); + if (count($users) === 0) { + return; + } + Filesystem::initMountPoints($users[0]); + $mounts = Filesystem::getMountByStorageId($storageId); + if (count($mounts) === 0) { + return; + } + } + $storage = $mounts[0]->getStorage(); + $watcher = new Watcher($storage); + $watcher->checkUpdate($internalPath); + } + + /** + * get the next fileid in the cache + * + * @param int $previous + * @param bool $folder + * @return int + */ + static private function getNextFileId($previous, $folder) { + if ($folder) { + $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` = ? ORDER BY `fileid` ASC', 1); + } else { + $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` != ? ORDER BY `fileid` ASC', 1); + } + $result = \OC_DB::executeAudited($stmt, array($previous,self::getFolderMimetype())); + if ($row = $result->fetchRow()) { + return $row['fileid']; + } else { + return 0; + } + } + + static public function checkNext() { + // check both 1 file and 1 folder, this way new files are detected quicker because there are less folders than files usually + $previousFile = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_file', 0); + $previousFolder = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_folder', 0); + $nextFile = self::getNextFileId($previousFile, false); + $nextFolder = self::getNextFileId($previousFolder, true); + \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_file', $nextFile); + \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_folder', $nextFolder); + if ($nextFile > 0) { + self::checkUpdate($nextFile); + } + if ($nextFolder > 0) { + self::checkUpdate($nextFolder); + } + } + + static public function checkAll() { + $previous = 0; + $next = 1; + while ($next != 0) { + $next = self::getNextFileId($previous, true); + self::checkUpdate($next); + } + $previous = 0; + $next = 1; + while ($next != 0) { + $next = self::getNextFileId($previous, false); + self::checkUpdate($next); + } + } +} diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php new file mode 100644 index 00000000000..e69733727af --- /dev/null +++ b/lib/private/files/cache/cache.php @@ -0,0 +1,582 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * Metadata cache for the filesystem + * + * don't use this class directly if you need to get metadata, use \OC\Files\Filesystem::getFileInfo instead + */ +class Cache { + const NOT_FOUND = 0; + const PARTIAL = 1; //only partial data available, file not cached in the database + const SHALLOW = 2; //folder in cache, but not all child files are completely scanned + const COMPLETE = 3; + + /** + * @var array partial data for the cache + */ + private $partial = array(); + + /** + * @var string + */ + private $storageId; + + /** + * @var Storage $storageCache + */ + private $storageCache; + + private $mimetypeIds = array(); + private $mimetypes = array(); + + /** + * @param \OC\Files\Storage\Storage|string $storage + */ + public function __construct($storage) { + if ($storage instanceof \OC\Files\Storage\Storage) { + $this->storageId = $storage->getId(); + } else { + $this->storageId = $storage; + } + if (strlen($this->storageId) > 64) { + $this->storageId = md5($this->storageId); + } + + $this->storageCache = new Storage($storage); + } + + public function getNumericStorageId() { + return $this->storageCache->getNumericId(); + } + + /** + * normalize mimetypes + * + * @param string $mime + * @return int + */ + public function getMimetypeId($mime) { + if (!isset($this->mimetypeIds[$mime])) { + $result = \OC_DB::executeAudited('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?', array($mime)); + if ($row = $result->fetchRow()) { + $this->mimetypeIds[$mime] = $row['id']; + } else { + $result = \OC_DB::executeAudited('INSERT INTO `*PREFIX*mimetypes`(`mimetype`) VALUES(?)', array($mime)); + $this->mimetypeIds[$mime] = \OC_DB::insertid('*PREFIX*mimetypes'); + } + $this->mimetypes[$this->mimetypeIds[$mime]] = $mime; + } + return $this->mimetypeIds[$mime]; + } + + public function getMimetype($id) { + if (!isset($this->mimetypes[$id])) { + $sql = 'SELECT `mimetype` FROM `*PREFIX*mimetypes` WHERE `id` = ?'; + $result = \OC_DB::executeAudited($sql, array($id)); + if ($row = $result->fetchRow()) { + $this->mimetypes[$id] = $row['mimetype']; + } else { + return null; + } + } + return $this->mimetypes[$id]; + } + + /** + * get the stored metadata of a file or folder + * + * @param string/int $file + * @return array | false + */ + public function get($file) { + if (is_string($file) or $file == '') { + // normalize file + $file = $this->normalize($file); + + $where = 'WHERE `storage` = ? AND `path_hash` = ?'; + $params = array($this->getNumericStorageId(), md5($file)); + } else { //file id + $where = 'WHERE `fileid` = ?'; + $params = array($file); + } + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, + `storage_mtime`, `encrypted`, `unencrypted_size`, `etag` + FROM `*PREFIX*filecache` ' . $where; + $result = \OC_DB::executeAudited($sql, $params); + $data = $result->fetchRow(); + + //FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO + //PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false + if ($data === null) { + $data = false; + } + + //merge partial data + if (!$data and is_string($file)) { + if (isset($this->partial[$file])) { + $data = $this->partial[$file]; + } + } else { + //fix types + $data['fileid'] = (int)$data['fileid']; + $data['size'] = (int)$data['size']; + $data['mtime'] = (int)$data['mtime']; + $data['encrypted'] = (bool)$data['encrypted']; + $data['unencrypted_size'] = (int)$data['unencrypted_size']; + $data['storage'] = $this->storageId; + $data['mimetype'] = $this->getMimetype($data['mimetype']); + $data['mimepart'] = $this->getMimetype($data['mimepart']); + if ($data['storage_mtime'] == 0) { + $data['storage_mtime'] = $data['mtime']; + } + } + + return $data; + } + + /** + * get the metadata of all files stored in $folder + * + * @param string $folder + * @return array + */ + public function getFolderContents($folder) { + $fileId = $this->getId($folder); + if ($fileId > -1) { + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, + `storage_mtime`, `encrypted`, `unencrypted_size`, `etag` + FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC'; + $result = \OC_DB::executeAudited($sql,array($fileId)); + $files = $result->fetchAll(); + foreach ($files as &$file) { + $file['mimetype'] = $this->getMimetype($file['mimetype']); + $file['mimepart'] = $this->getMimetype($file['mimepart']); + if ($file['storage_mtime'] == 0) { + $file['storage_mtime'] = $file['mtime']; + } + } + return $files; + } else { + return array(); + } + } + + /** + * store meta data for a file or folder + * + * @param string $file + * @param array $data + * + * @return int file id + */ + public function put($file, array $data) { + if (($id = $this->getId($file)) > -1) { + $this->update($id, $data); + return $id; + } else { + // normalize file + $file = $this->normalize($file); + + if (isset($this->partial[$file])) { //add any saved partial data + $data = array_merge($this->partial[$file], $data); + unset($this->partial[$file]); + } + + $requiredFields = array('size', 'mtime', 'mimetype'); + foreach ($requiredFields as $field) { + if (!isset($data[$field])) { //data not complete save as partial and return + $this->partial[$file] = $data; + return -1; + } + } + + $data['path'] = $file; + $data['parent'] = $this->getParentId($file); + $data['name'] = \OC_Util::basename($file); + + list($queryParts, $params) = $this->buildParts($data); + $queryParts[] = '`storage`'; + $params[] = $this->getNumericStorageId(); + $valuesPlaceholder = array_fill(0, count($queryParts), '?'); + + $sql = 'INSERT INTO `*PREFIX*filecache` (' . implode(', ', $queryParts) . ')' + . ' VALUES (' . implode(', ', $valuesPlaceholder) . ')'; + \OC_DB::executeAudited($sql, $params); + + return (int)\OC_DB::insertid('*PREFIX*filecache'); + } + } + + /** + * update the metadata in the cache + * + * @param int $id + * @param array $data + */ + public function update($id, array $data) { + + if(isset($data['path'])) { + // normalize path + $data['path'] = $this->normalize($data['path']); + } + + if(isset($data['name'])) { + // normalize path + $data['name'] = $this->normalize($data['name']); + } + + list($queryParts, $params) = $this->buildParts($data); + $params[] = $id; + + $sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? WHERE `fileid` = ?'; + \OC_DB::executeAudited($sql, $params); + } + + /** + * extract query parts and params array from data array + * + * @param array $data + * @return array + */ + function buildParts(array $data) { + $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'unencrypted_size', 'etag'); + $params = array(); + $queryParts = array(); + foreach ($data as $name => $value) { + if (array_search($name, $fields) !== false) { + if ($name === 'path') { + $params[] = md5($value); + $queryParts[] = '`path_hash`'; + } elseif ($name === 'mimetype') { + $params[] = $this->getMimetypeId(substr($value, 0, strpos($value, '/'))); + $queryParts[] = '`mimepart`'; + $value = $this->getMimetypeId($value); + } elseif ($name === 'storage_mtime') { + if (!isset($data['mtime'])) { + $params[] = $value; + $queryParts[] = '`mtime`'; + } + } elseif ($name === 'encrypted') { + // Boolean to integer conversion + $value = $value ? 1 : 0; + } + $params[] = $value; + $queryParts[] = '`' . $name . '`'; + } + } + return array($queryParts, $params); + } + + /** + * get the file id for a file + * + * @param string $file + * @return int + */ + public function getId($file) { + // normalize file + $file = $this->normalize($file); + + $pathHash = md5($file); + + $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'; + $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $pathHash)); + if ($row = $result->fetchRow()) { + return $row['fileid']; + } else { + return -1; + } + } + + /** + * get the id of the parent folder of a file + * + * @param string $file + * @return int + */ + public function getParentId($file) { + if ($file === '') { + return -1; + } else { + $parent = dirname($file); + if ($parent === '.') { + $parent = ''; + } + return $this->getId($parent); + } + } + + /** + * check if a file is available in the cache + * + * @param string $file + * @return bool + */ + public function inCache($file) { + return $this->getId($file) != -1; + } + + /** + * remove a file or folder from the cache + * + * @param string $file + */ + public function remove($file) { + $entry = $this->get($file); + if ($entry['mimetype'] === 'httpd/unix-directory') { + $children = $this->getFolderContents($file); + foreach ($children as $child) { + $this->remove($child['path']); + } + } + + $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?'; + \OC_DB::executeAudited($sql, array($entry['fileid'])); + + $permissionsCache = new Permissions($this->storageId); + $permissionsCache->remove($entry['fileid']); + } + + /** + * Move a file or folder in the cache + * + * @param string $source + * @param string $target + */ + public function move($source, $target) { + // normalize source and target + $source = $this->normalize($source); + $target = $this->normalize($target); + + $sourceData = $this->get($source); + $sourceId = $sourceData['fileid']; + $newParentId = $this->getParentId($target); + + if ($sourceData['mimetype'] === 'httpd/unix-directory') { + //find all child entries + $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?'; + $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $source . '/%')); + $childEntries = $result->fetchAll(); + $sourceLength = strlen($source); + $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); + + foreach ($childEntries as $child) { + $targetPath = $target . substr($child['path'], $sourceLength); + \OC_DB::executeAudited($query, array($targetPath, md5($targetPath), $child['fileid'])); + } + } + + $sql = 'UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?'; + \OC_DB::executeAudited($sql, array($target, md5($target), basename($target), $newParentId, $sourceId)); + } + + /** + * remove all entries for files that are stored on the storage from the cache + */ + public function clear() { + $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?'; + \OC_DB::executeAudited($sql, array($this->getNumericStorageId())); + + $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'; + \OC_DB::executeAudited($sql, array($this->storageId)); + } + + /** + * @param string $file + * + * @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE + */ + public function getStatus($file) { + // normalize file + $file = $this->normalize($file); + + $pathHash = md5($file); + $sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'; + $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $pathHash)); + if ($row = $result->fetchRow()) { + if ((int)$row['size'] === -1) { + return self::SHALLOW; + } else { + return self::COMPLETE; + } + } else { + if (isset($this->partial[$file])) { + return self::PARTIAL; + } else { + return self::NOT_FOUND; + } + } + } + + /** + * search for files matching $pattern + * + * @param string $pattern + * @return array of file data + */ + public function search($pattern) { + + // normalize pattern + $pattern = $this->normalize($pattern); + + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` + FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?'; + $result = \OC_DB::executeAudited($sql, array($pattern, $this->getNumericStorageId())); + $files = array(); + while ($row = $result->fetchRow()) { + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } + return $files; + } + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return array + */ + public function searchByMime($mimetype) { + if (strpos($mimetype, '/')) { + $where = '`mimetype` = ?'; + } else { + $where = '`mimepart` = ?'; + } + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` + FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'; + $mimetype = $this->getMimetypeId($mimetype); + $result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId())); + $files = array(); + while ($row = $result->fetchRow()) { + $row['mimetype'] = $this->getMimetype($row['mimetype']); + $row['mimepart'] = $this->getMimetype($row['mimepart']); + $files[] = $row; + } + return $files; + } + + /** + * update the folder size and the size of all parent folders + * + * @param $path + */ + public function correctFolderSize($path) { + $this->calculateFolderSize($path); + if ($path !== '') { + $parent = dirname($path); + if ($parent === '.' or $parent === '/') { + $parent = ''; + } + $this->correctFolderSize($parent); + } + } + + /** + * get the size of a folder and set it in the cache + * + * @param string $path + * @return int + */ + public function calculateFolderSize($path) { + $totalSize = 0; + $entry = $this->get($path); + if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { + $id = $entry['fileid']; + $sql = 'SELECT SUM(`size`), MIN(`size`) FROM `*PREFIX*filecache` '. + 'WHERE `parent` = ? AND `storage` = ?'; + $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); + if ($row = $result->fetchRow()) { + list($sum, $min) = array_values($row); + $sum = (int)$sum; + $min = (int)$min; + if ($min === -1) { + $totalSize = $min; + } else { + $totalSize = $sum; + } + if ($entry['size'] !== $totalSize) { + $this->update($id, array('size' => $totalSize)); + } + + } + } + return $totalSize; + } + + /** + * get all file ids on the files on the storage + * + * @return int[] + */ + public function getAll() { + $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?'; + $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId())); + $ids = array(); + while ($row = $result->fetchRow()) { + $ids[] = $row['fileid']; + } + return $ids; + } + + /** + * find a folder in the cache which has not been fully scanned + * + * If multiply incomplete folders are in the cache, the one with the highest id will be returned, + * use the one with the highest id gives the best result with the background scanner, since that is most + * likely the folder where we stopped scanning previously + * + * @return string|bool the path of the folder or false when no folder matched + */ + public function getIncomplete() { + $query = \OC_DB::prepare('SELECT `path` FROM `*PREFIX*filecache`' + . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC',1); + $result = \OC_DB::executeAudited($query, array($this->getNumericStorageId())); + if ($row = $result->fetchRow()) { + return $row['path']; + } else { + return false; + } + } + + /** + * get the storage id of the storage for a file and the internal path of the file + * + * @param int $id + * @return array, first element holding the storage id, second the path + */ + static public function getById($id) { + $sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?'; + $result = \OC_DB::executeAudited($sql, array($id)); + if ($row = $result->fetchRow()) { + $numericId = $row['storage']; + $path = $row['path']; + } else { + return null; + } + + if ($id = Storage::getStorageId($numericId)) { + return array($id, $path); + } else { + return null; + } + } + + /** + * normalize the given path + * @param $path + * @return string + */ + public function normalize($path) { + + return \OC_Util::normalizeUnicode($path); + } +} diff --git a/lib/private/files/cache/legacy.php b/lib/private/files/cache/legacy.php new file mode 100644 index 00000000000..8eed1f67a5d --- /dev/null +++ b/lib/private/files/cache/legacy.php @@ -0,0 +1,136 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * Provide read only support for the old filecache + */ +class Legacy { + private $user; + + private $cacheHasItems = null; + + public function __construct($user) { + $this->user = $user; + } + + /** + * get the numbers of items in the legacy cache + * + * @return int + */ + function getCount() { + $sql = 'SELECT COUNT(`id`) AS `count` FROM `*PREFIX*fscache` WHERE `user` = ?'; + $result = \OC_DB::executeAudited($sql, array($this->user)); + if ($row = $result->fetchRow()) { + return $row['count']; + } else { + return 0; + } + } + + /** + * check if a legacy cache is present and holds items + * + * @return bool + */ + function hasItems() { + if (!is_null($this->cacheHasItems)) { + return $this->cacheHasItems; + } + try { + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `user` = ?',1); + } catch (\Exception $e) { + $this->cacheHasItems = false; + return false; + } + try { + $result = $query->execute(array($this->user)); + } catch (\Exception $e) { + $this->cacheHasItems = false; + return false; + } + + if ($result === false || property_exists($result, 'error_message_prefix')) { + $this->cacheHasItems = false; + return false; + } + + $this->cacheHasItems = (bool)$result->fetchRow(); + return $this->cacheHasItems; + } + + /** + * get an item from the legacy cache + * + * @param string|int $path + * @return array + */ + function get($path) { + if (is_numeric($path)) { + $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `id` = ?'; + } else { + $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?'; + } + $result = \OC_DB::executeAudited($sql, array($path)); + $data = $result->fetchRow(); + $data['etag'] = $this->getEtag($data['path'], $data['user']); + return $data; + } + + /** + * Get the ETag for the given path + * + * @param type $path + * @return string + */ + function getEtag($path, $user = null) { + static $query = null; + + $pathDetails = explode('/', $path, 4); + if((!$user) && !isset($pathDetails[1])) { + //no user!? Too odd, return empty string. + return ''; + } else if(!$user) { + //guess user from path, if no user passed. + $user = $pathDetails[1]; + } + + if(!isset($pathDetails[3]) || is_null($pathDetails[3])) { + $relativePath = ''; + } else { + $relativePath = $pathDetails[3]; + } + + if(is_null($query)){ + $query = \OC_DB::prepare('SELECT `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = \'{DAV:}getetag\''); + } + $result = \OC_DB::executeAudited($query,array($user, '/' . $relativePath)); + if ($row = $result->fetchRow()) { + return trim($row['propertyvalue'], '"'); + } else { + return ''; + } + } + + /** + * get all child items of an item from the legacy cache + * + * @param int $id + * @return array + */ + function getChildren($id) { + $result = \OC_DB::executeAudited('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?', array($id)); + $data = $result->fetchAll(); + foreach ($data as $i => $item) { + $data[$i]['etag'] = $this->getEtag($item['path'], $item['user']); + } + return $data; + } +} diff --git a/lib/private/files/cache/permissions.php b/lib/private/files/cache/permissions.php new file mode 100644 index 00000000000..2e2bdb20b78 --- /dev/null +++ b/lib/private/files/cache/permissions.php @@ -0,0 +1,143 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +class Permissions { + /** + * @var string $storageId + */ + private $storageId; + + /** + * @param \OC\Files\Storage\Storage|string $storage + */ + public function __construct($storage) { + if ($storage instanceof \OC\Files\Storage\Storage) { + $this->storageId = $storage->getId(); + } else { + $this->storageId = $storage; + } + } + + /** + * get the permissions for a single file + * + * @param int $fileId + * @param string $user + * @return int (-1 if file no permissions set) + */ + public function get($fileId, $user) { + $sql = 'SELECT `permissions` FROM `*PREFIX*permissions` WHERE `user` = ? AND `fileid` = ?'; + $result = \OC_DB::executeAudited($sql, array($user, $fileId)); + if ($row = $result->fetchRow()) { + return $row['permissions']; + } else { + return -1; + } + } + + /** + * set the permissions of a file + * + * @param int $fileId + * @param string $user + * @param int $permissions + */ + public function set($fileId, $user, $permissions) { + if (self::get($fileId, $user) !== -1) { + $sql = 'UPDATE `*PREFIX*permissions` SET `permissions` = ? WHERE `user` = ? AND `fileid` = ?'; + } else { + $sql = 'INSERT INTO `*PREFIX*permissions`(`permissions`, `user`, `fileid`) VALUES(?, ?,? )'; + } + \OC_DB::executeAudited($sql, array($permissions, $user, $fileId)); + } + + /** + * get the permissions of multiply files + * + * @param int[] $fileIds + * @param string $user + * @return int[] + */ + public function getMultiple($fileIds, $user) { + if (count($fileIds) === 0) { + return array(); + } + $params = $fileIds; + $params[] = $user; + $inPart = implode(', ', array_fill(0, count($fileIds), '?')); + + $sql = 'SELECT `fileid`, `permissions` FROM `*PREFIX*permissions`' + . ' WHERE `fileid` IN (' . $inPart . ') AND `user` = ?'; + $result = \OC_DB::executeAudited($sql, $params); + $filePermissions = array(); + while ($row = $result->fetchRow()) { + $filePermissions[$row['fileid']] = $row['permissions']; + } + return $filePermissions; + } + + /** + * get the permissions for all files in a folder + * + * @param int $parentId + * @param string $user + * @return int[] + */ + public function getDirectoryPermissions($parentId, $user) { + $sql = 'SELECT `*PREFIX*permissions`.`fileid`, `permissions` + FROM `*PREFIX*permissions` + INNER JOIN `*PREFIX*filecache` ON `*PREFIX*permissions`.`fileid` = `*PREFIX*filecache`.`fileid` + WHERE `*PREFIX*filecache`.`parent` = ? AND `*PREFIX*permissions`.`user` = ?'; + + $result = \OC_DB::executeAudited($sql, array($parentId, $user)); + $filePermissions = array(); + while ($row = $result->fetchRow()) { + $filePermissions[$row['fileid']] = $row['permissions']; + } + return $filePermissions; + } + + /** + * remove the permissions for a file + * + * @param int $fileId + * @param string $user + */ + public function remove($fileId, $user = null) { + if (is_null($user)) { + \OC_DB::executeAudited('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ?', array($fileId)); + } else { + $sql = 'DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'; + \OC_DB::executeAudited($sql, array($fileId, $user)); + } + } + + public function removeMultiple($fileIds, $user) { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'); + foreach ($fileIds as $fileId) { + \OC_DB::executeAudited($query, array($fileId, $user)); + } + } + + /** + * get the list of users which have permissions stored for a file + * + * @param int $fileId + */ + public function getUsers($fileId) { + $sql = 'SELECT `user` FROM `*PREFIX*permissions` WHERE `fileid` = ?'; + $result = \OC_DB::executeAudited($sql, array($fileId)); + $users = array(); + while ($row = $result->fetchRow()) { + $users[] = $row['user']; + } + return $users; + } +} diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php new file mode 100644 index 00000000000..96f84609cf2 --- /dev/null +++ b/lib/private/files/cache/scanner.php @@ -0,0 +1,258 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +use OC\Files\Filesystem; +use OC\Hooks\BasicEmitter; + +/** + * Class Scanner + * + * Hooks available in scope \OC\Files\Cache\Scanner: + * - scanFile(string $path, string $storageId) + * - scanFolder(string $path, string $storageId) + * + * @package OC\Files\Cache + */ +class Scanner extends BasicEmitter { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage; + + /** + * @var string $storageId + */ + private $storageId; + + /** + * @var \OC\Files\Cache\Cache $cache + */ + private $cache; + + /** + * @var \OC\Files\Cache\Permissions $permissionsCache + */ + private $permissionsCache; + + const SCAN_RECURSIVE = true; + const SCAN_SHALLOW = false; + + const REUSE_ETAG = 1; + const REUSE_SIZE = 2; + + public function __construct(\OC\Files\Storage\Storage $storage) { + $this->storage = $storage; + $this->storageId = $this->storage->getId(); + $this->cache = $storage->getCache(); + $this->permissionsCache = $storage->getPermissionsCache(); + } + + /** + * get all the metadata of a file or folder + * * + * + * @param string $path + * @return array with metadata of the file + */ + public function getData($path) { + $data = array(); + if (!$this->storage->isReadable($path)) return null; //cant read, nothing we can do + $data['mimetype'] = $this->storage->getMimeType($path); + $data['mtime'] = $this->storage->filemtime($path); + if ($data['mimetype'] == 'httpd/unix-directory') { + $data['size'] = -1; //unknown + } else { + $data['size'] = $this->storage->filesize($path); + } + $data['etag'] = $this->storage->getETag($path); + $data['storage_mtime'] = $data['mtime']; + return $data; + } + + /** + * scan a single file and store it in the cache + * + * @param string $file + * @param int $reuseExisting + * @param bool $parentExistsInCache + * @return array with metadata of the scanned file + */ + public function scanFile($file, $reuseExisting = 0, $parentExistsInCache = false) { + if (!self::isPartialFile($file) + and !Filesystem::isFileBlacklisted($file) + ) { + $this->emit('\OC\Files\Cache\Scanner', 'scanFile', array($file, $this->storageId)); + \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId)); + $data = $this->getData($file); + if ($data) { + if ($file and !$parentExistsInCache) { + $parent = dirname($file); + if ($parent === '.' or $parent === '/') { + $parent = ''; + } + if (!$this->cache->inCache($parent)) { + $this->scanFile($parent); + } + } + $newData = $data; + $cacheData = $this->cache->get($file); + if ($cacheData) { + $this->permissionsCache->remove($cacheData['fileid']); + if ($reuseExisting) { + // prevent empty etag + $etag = $cacheData['etag']; + $propagateETagChange = false; + if (empty($etag)) { + $etag = $data['etag']; + $propagateETagChange = true; + } + // only reuse data if the file hasn't explicitly changed + if (isset($data['mtime']) && isset($cacheData['mtime']) && $data['mtime'] === $cacheData['mtime']) { + if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { + $data['size'] = $cacheData['size']; + } + if ($reuseExisting & self::REUSE_ETAG) { + $data['etag'] = $etag; + if ($propagateETagChange) { + $parent = $file; + while ($parent !== '') { + $parent = dirname($parent); + if ($parent === '.') { + $parent = ''; + } + $parentCacheData = $this->cache->get($parent); + $this->cache->update($parentCacheData['fileid'], array( + 'etag' => $this->storage->getETag($parent), + )); + } + } + } + } + // Only update metadata that has changed + $newData = array_diff($data, $cacheData); + } + } + if (!empty($newData)) { + $this->cache->put($file, $newData); + } + } else { + $this->cache->remove($file); + } + return $data; + } + return null; + } + + /** + * scan a folder and all it's children + * + * @param string $path + * @param bool $recursive + * @param int $reuse + * @return int the size of the scanned folder or -1 if the size is unknown at this stage + */ + public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) { + if ($reuse === -1) { + $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : 0; + } + $this->scanFile($path, $reuse); + return $this->scanChildren($path, $recursive, $reuse); + } + + /** + * scan all the files and folders in a folder + * + * @param string $path + * @param bool $recursive + * @param int $reuse + * @return int the size of the scanned folder or -1 if the size is unknown at this stage + */ + public function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) { + if ($reuse === -1) { + $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : 0; + } + $this->emit('\OC\Files\Cache\Scanner', 'scanFolder', array($path, $this->storageId)); + $size = 0; + $childQueue = array(); + $existingChildren = array(); + if ($this->cache->inCache($path)) { + $children = $this->cache->getFolderContents($path); + foreach ($children as $child) { + $existingChildren[] = $child['name']; + } + } + $newChildren = array(); + if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) { + \OC_DB::beginTransaction(); + if (is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + $child = ($path) ? $path . '/' . $file : $file; + if (!Filesystem::isIgnoredDir($file)) { + $newChildren[] = $file; + $data = $this->scanFile($child, $reuse, true); + if ($data) { + if ($data['size'] === -1) { + if ($recursive === self::SCAN_RECURSIVE) { + $childQueue[] = $child; + } else { + $size = -1; + } + } else if ($size !== -1) { + $size += $data['size']; + } + } + } + } + } + $removedChildren = \array_diff($existingChildren, $newChildren); + foreach ($removedChildren as $childName) { + $child = ($path) ? $path . '/' . $childName : $childName; + $this->cache->remove($child); + } + \OC_DB::commit(); + foreach ($childQueue as $child) { + $childSize = $this->scanChildren($child, self::SCAN_RECURSIVE, $reuse); + if ($childSize === -1) { + $size = -1; + } else { + $size += $childSize; + } + } + $this->cache->put($path, array('size' => $size)); + } + return $size; + } + + /** + * @brief check if the file should be ignored when scanning + * NOTE: files with a '.part' extension are ignored as well! + * prevents unfinished put requests to be scanned + * @param String $file + * @return boolean + */ + public static function isPartialFile($file) { + if (pathinfo($file, PATHINFO_EXTENSION) === 'part') { + return true; + } + return false; + } + + /** + * walk over any folders that are not fully scanned yet and scan them + */ + public function backgroundScan() { + $lastPath = null; + while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) { + $this->scan($path); + $this->cache->correctFolderSize($path); + $lastPath = $path; + } + } +} diff --git a/lib/private/files/cache/storage.php b/lib/private/files/cache/storage.php new file mode 100644 index 00000000000..8a9e47ca36d --- /dev/null +++ b/lib/private/files/cache/storage.php @@ -0,0 +1,60 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * Class Storage + * + * cache storage specific data + * + * @package OC\Files\Cache + */ +class Storage { + private $storageId; + private $numericId; + + /** + * @param \OC\Files\Storage\Storage|string $storage + */ + public function __construct($storage) { + if ($storage instanceof \OC\Files\Storage\Storage) { + $this->storageId = $storage->getId(); + } else { + $this->storageId = $storage; + } + if (strlen($this->storageId) > 64) { + $this->storageId = md5($this->storageId); + } + + $sql = 'SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'; + $result = \OC_DB::executeAudited($sql, array($this->storageId)); + if ($row = $result->fetchRow()) { + $this->numericId = $row['numeric_id']; + } else { + $sql = 'INSERT INTO `*PREFIX*storages` (`id`) VALUES(?)'; + \OC_DB::executeAudited($sql, array($this->storageId)); + $this->numericId = \OC_DB::insertid('*PREFIX*storages'); + } + } + + public function getNumericId() { + return $this->numericId; + } + + public static function getStorageId($numericId) { + + $sql = 'SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?'; + $result = \OC_DB::executeAudited($sql, array($numericId)); + if ($row = $result->fetchRow()) { + return $row['id']; + } else { + return null; + } + } +} diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php new file mode 100644 index 00000000000..1f30173a8f8 --- /dev/null +++ b/lib/private/files/cache/updater.php @@ -0,0 +1,161 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; +use OCP\Util; + +/** + * listen to filesystem hooks and change the cache accordingly + */ +class Updater { + + /** + * resolve a path to a storage and internal path + * + * @param string $path the relative path + * @return array consisting of the storage and the internal path + */ + static public function resolvePath($path) { + $view = \OC\Files\Filesystem::getView(); + return $view->resolvePath($path); + } + + /** + * perform a write update + * + * @param string $path the relative path of the file + */ + static public function writeUpdate($path) { + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = self::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Scanner::SCAN_SHALLOW); + $cache->correctFolderSize($internalPath); + self::correctFolder($path, $storage->filemtime($internalPath)); + } + } + + /** + * perform a delete update + * + * @param string $path the relative path of the file + */ + static public function deleteUpdate($path) { + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = self::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $cache->remove($internalPath); + $cache->correctFolderSize($internalPath); + self::correctFolder($path, time()); + } + } + + /** + * preform a rename update + * + * @param string $from the relative path of the source file + * @param string $to the relative path of the target file + */ + static public function renameUpdate($from, $to) { + /** + * @var \OC\Files\Storage\Storage $storageFrom + * @var \OC\Files\Storage\Storage $storageTo + * @var string $internalFrom + * @var string $internalTo + */ + list($storageFrom, $internalFrom) = self::resolvePath($from); + list($storageTo, $internalTo) = self::resolvePath($to); + if ($storageFrom && $storageTo) { + if ($storageFrom === $storageTo) { + $cache = $storageFrom->getCache($internalFrom); + $cache->move($internalFrom, $internalTo); + $cache->correctFolderSize($internalFrom); + $cache->correctFolderSize($internalTo); + self::correctFolder($from, time()); + self::correctFolder($to, time()); + } else { + self::deleteUpdate($from); + self::writeUpdate($to); + } + } + } + + /** + * Update the mtime and ETag of all parent folders + * + * @param string $path + * @param string $time + */ + static public function correctFolder($path, $time) { + if ($path !== '' && $path !== '/') { + $parent = dirname($path); + if ($parent === '.' || $parent === '\\') { + $parent = ''; + } + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = self::resolvePath($parent); + if ($storage) { + $cache = $storage->getCache(); + $id = $cache->getId($internalPath); + if ($id !== -1) { + $cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath))); + self::correctFolder($parent, $time); + } else { + Util::writeLog('core', 'Path not in cache: '.$internalPath, Util::ERROR); + } + } + } + } + + /** + * @param array $params + */ + static public function writeHook($params) { + self::writeUpdate($params['path']); + } + + /** + * @param array $params + */ + static public function touchHook($params) { + $path = $params['path']; + list($storage, $internalPath) = self::resolvePath($path); + $cache = $storage->getCache(); + $id = $cache->getId($internalPath); + if ($id !== -1) { + $cache->update($id, array('etag' => $storage->getETag($internalPath))); + } + self::writeUpdate($path); + } + + /** + * @param array $params + */ + static public function renameHook($params) { + self::renameUpdate($params['oldpath'], $params['newpath']); + } + + /** + * @param array $params + */ + static public function deleteHook($params) { + self::deleteUpdate($params['path']); + } +} diff --git a/lib/private/files/cache/upgrade.php b/lib/private/files/cache/upgrade.php new file mode 100644 index 00000000000..cfb9a117311 --- /dev/null +++ b/lib/private/files/cache/upgrade.php @@ -0,0 +1,227 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +class Upgrade { + /** + * @var Legacy $legacy + */ + private $legacy; + + private $numericIds = array(); + + private $mimeTypeIds = array(); + + /** + * @param Legacy $legacy + */ + public function __construct($legacy) { + $this->legacy = $legacy; + } + + /** + * Preform a upgrade a path and it's childs + * + * @param string $path + * @param bool $mode + */ + function upgradePath($path, $mode = Scanner::SCAN_RECURSIVE) { + if (!$this->legacy->hasItems()) { + return; + } + \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $path); + if ($row = $this->legacy->get($path)) { + $data = $this->getNewData($row); + if ($data) { + $this->insert($data); + $this->upgradeChilds($data['id'], $mode); + } + } + } + + /** + * upgrade all child elements of an item + * + * @param int $id + * @param bool $mode + */ + function upgradeChilds($id, $mode = Scanner::SCAN_RECURSIVE) { + $children = $this->legacy->getChildren($id); + foreach ($children as $child) { + $childData = $this->getNewData($child); + \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $child['path']); + if ($childData) { + $this->insert($childData); + if ($mode == Scanner::SCAN_RECURSIVE) { + $this->upgradeChilds($child['id']); + } + } + } + } + + /** + * insert data into the new cache + * + * @param array $data the data for the new cache + */ + function insert($data) { + static $insertQuery = null; + if(is_null($insertQuery)) { + $insertQuery = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` + ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` ) + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); + } + if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) { + \OC_DB::executeAudited($insertQuery, array($data['id'], $data['storage'], + $data['path'], $data['path_hash'], $data['parent'], $data['name'], + $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'], $data['etag'])); + } + } + + /** + * check if an item is already in the new cache + * + * @param string $storage + * @param string $pathHash + * @param string $id + * @return bool + */ + function inCache($storage, $pathHash, $id) { + static $query = null; + if(is_null($query)) { + $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?'); + } + $result = \OC_DB::executeAudited($query, array($storage, $pathHash, $id)); + return (bool)$result->fetchRow(); + } + + /** + * get the new data array from the old one + * + * @param array $data the data from the old cache + * Example data array + * Array + * ( + * [id] => 418 + * [path] => /tina/files/picture.jpg //relative to datadir + * [path_hash] => 66d4547e372888deed80b24fec9b192b + * [parent] => 234 + * [name] => picture.jpg + * [user] => tina + * [size] => 1265283 + * [ctime] => 1363909709 + * [mtime] => 1363909709 + * [mimetype] => image/jpeg + * [mimepart] => image + * [encrypted] => 0 + * [versioned] => 0 + * [writable] => 1 + * ) + * + * @return array + */ + function getNewData($data) { + //Make sure there is a path, otherwise we can do nothing. + if(!isset($data['path'])) { + return false; + } + $newData = $data; + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath; + */ + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']); + if ($storage) { + $newData['etag'] = $data['etag']; + $newData['path_hash'] = md5($internalPath); + $newData['path'] = $internalPath; + $newData['storage'] = $this->getNumericId($storage); + $newData['parent'] = ($internalPath === '') ? -1 : $data['parent']; + $newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ; + $newData['storage_object'] = $storage; + $newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage); + $newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage); + return $newData; + } else { + \OC_Log::write('core', 'Unable to migrate data from old cache for '.$data['path'].' because the storage was not found', \OC_Log::ERROR); + return false; + } + } + + /** + * get the numeric storage id + * + * @param \OC\Files\Storage\Storage $storage + * @return int + */ + function getNumericId($storage) { + $storageId = $storage->getId(); + if (!isset($this->numericIds[$storageId])) { + $cache = $storage->getCache(); + $this->numericIds[$storageId] = $cache->getNumericStorageId(); + } + return $this->numericIds[$storageId]; + } + + /** + * get the numeric id for a mimetype + * + * @param string $mimetype + * @param \OC\Files\Storage\Storage $storage + * @return int + */ + function getMimetypeId($mimetype, $storage) { + if (!isset($this->mimeTypeIds[$mimetype])) { + $cache = new Cache($storage); + $this->mimeTypeIds[$mimetype] = $cache->getMimetypeId($mimetype); + } + return $this->mimeTypeIds[$mimetype]; + } + + /** + * check if a cache upgrade is required for $user + * + * @param string $user + * @return bool + */ + static function needUpgrade($user) { + $cacheVersion = (int)\OCP\Config::getUserValue($user, 'files', 'cache_version', 4); + return $cacheVersion < 5; + } + + /** + * mark the filecache as upgrade + * + * @param string $user + */ + static function upgradeDone($user) { + \OCP\Config::setUserValue($user, 'files', 'cache_version', 5); + } + + /** + * Does a "silent" upgrade, i.e. without an Event-Source as triggered + * on User-Login via Ajax. This method is called within the regular + * ownCloud upgrade. + * + * @param string $user a User ID + */ + public static function doSilentUpgrade($user) { + if(!self::needUpgrade($user)) { + return; + } + $legacy = new \OC\Files\Cache\Legacy($user); + if ($legacy->hasItems()) { + \OC_DB::beginTransaction(); + $upgrade = new \OC\Files\Cache\Upgrade($legacy); + $upgrade->upgradePath('/' . $user . '/files'); + \OC_DB::commit(); + } + \OC\Files\Cache\Upgrade::upgradeDone($user); + } +} diff --git a/lib/private/files/cache/watcher.php b/lib/private/files/cache/watcher.php new file mode 100644 index 00000000000..8bfd4602f3a --- /dev/null +++ b/lib/private/files/cache/watcher.php @@ -0,0 +1,72 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * check the storage backends for updates and change the cache accordingly + */ +class Watcher { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage; + + /** + * @var Cache $cache + */ + private $cache; + + /** + * @var Scanner $scanner; + */ + private $scanner; + + /** + * @param \OC\Files\Storage\Storage $storage + */ + public function __construct(\OC\Files\Storage\Storage $storage) { + $this->storage = $storage; + $this->cache = $storage->getCache(); + $this->scanner = $storage->getScanner(); + } + + /** + * check $path for updates + * + * @param string $path + */ + public function checkUpdate($path) { + $cachedEntry = $this->cache->get($path); + if ($this->storage->hasUpdated($path, $cachedEntry['storage_mtime'])) { + if ($this->storage->is_dir($path)) { + $this->scanner->scan($path, Scanner::SCAN_SHALLOW); + } else { + $this->scanner->scanFile($path); + } + if ($cachedEntry['mimetype'] === 'httpd/unix-directory') { + $this->cleanFolder($path); + } + $this->cache->correctFolderSize($path); + } + } + + /** + * remove deleted files in $path from the cache + * + * @param string $path + */ + public function cleanFolder($path) { + $cachedContent = $this->cache->getFolderContents($path); + foreach ($cachedContent as $entry) { + if (!$this->storage->file_exists($entry['path'])) { + $this->cache->remove($entry['path']); + } + } + } +} diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php new file mode 100644 index 00000000000..10ec5c41d11 --- /dev/null +++ b/lib/private/files/filesystem.php @@ -0,0 +1,770 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class for abstraction of filesystem functions + * This class won't call any filesystem functions for itself but will pass them to the correct OC_Filestorage object + * this class should also handle all the file permission related stuff + * + * Hooks provided: + * read(path) + * write(path, &run) + * post_write(path) + * create(path, &run) (when a file is created, both create and write will be emitted in that order) + * post_create(path) + * delete(path, &run) + * post_delete(path) + * rename(oldpath,newpath, &run) + * post_rename(oldpath,newpath) + * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order) + * post_rename(oldpath,newpath) + * post_initMountPoints(user, user_dir) + * + * the &run parameter can be set to false to prevent the operation from occurring + */ + +namespace OC\Files; + +use OC\Files\Storage\Loader; +const SPACE_NOT_COMPUTED = -1; +const SPACE_UNKNOWN = -2; +const SPACE_UNLIMITED = -3; + +class Filesystem { + /** + * @var Mount\Manager $mounts + */ + private static $mounts; + + public static $loaded = false; + /** + * @var \OC\Files\View $defaultInstance + */ + static private $defaultInstance; + + + /** + * classname which used for hooks handling + * used as signalclass in OC_Hooks::emit() + */ + const CLASSNAME = 'OC_Filesystem'; + + /** + * signalname emitted before file renaming + * + * @param string $oldpath + * @param string $newpath + */ + const signal_rename = 'rename'; + + /** + * signal emitted after file renaming + * + * @param string $oldpath + * @param string $newpath + */ + const signal_post_rename = 'post_rename'; + + /** + * signal emitted before file/dir creation + * + * @param string $path + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_create = 'create'; + + /** + * signal emitted after file/dir creation + * + * @param string $path + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_post_create = 'post_create'; + + /** + * signal emits before file/dir copy + * + * @param string $oldpath + * @param string $newpath + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_copy = 'copy'; + + /** + * signal emits after file/dir copy + * + * @param string $oldpath + * @param string $newpath + */ + const signal_post_copy = 'post_copy'; + + /** + * signal emits before file/dir save + * + * @param string $path + * @param bool $run changing this flag to false in hook handler will cancel event + */ + const signal_write = 'write'; + + /** + * signal emits after file/dir save + * + * @param string $path + */ + const signal_post_write = 'post_write'; + + /** + * signal emits when reading file/dir + * + * @param string $path + */ + const signal_read = 'read'; + + /** + * signal emits when removing file/dir + * + * @param string $path + */ + const signal_delete = 'delete'; + + /** + * parameters definitions for signals + */ + const signal_param_path = 'path'; + const signal_param_oldpath = 'oldpath'; + const signal_param_newpath = 'newpath'; + + /** + * run - changing this flag to false in hook handler will cancel event + */ + const signal_param_run = 'run'; + + /** + * @var \OC\Files\Storage\Loader $loader + */ + private static $loader; + + /** + * @param callable $wrapper + */ + public static function addStorageWrapper($wrapper) { + self::getLoader()->addStorageWrapper($wrapper); + + $mounts = self::getMountManager()->getAll(); + foreach ($mounts as $mount) { + $mount->wrapStorage($wrapper); + } + } + + public static function getLoader() { + if (!self::$loader) { + self::$loader = new Loader(); + } + return self::$loader; + } + + public static function getMountManager() { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + return self::$mounts; + } + + /** + * get the mountpoint of the storage object for a path + * ( note: because a storage is not always mounted inside the fakeroot, the + * returned mountpoint is relative to the absolute root of the filesystem + * and doesn't take the chroot into account ) + * + * @param string $path + * @return string + */ + static public function getMountPoint($path) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + $mount = self::$mounts->find($path); + if ($mount) { + return $mount->getMountPoint(); + } else { + return ''; + } + } + + /** + * get a list of all mount points in a directory + * + * @param string $path + * @return string[] + */ + static public function getMountPoints($path) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + $result = array(); + $mounts = self::$mounts->findIn($path); + foreach ($mounts as $mount) { + $result[] = $mount->getMountPoint(); + } + return $result; + } + + /** + * get the storage mounted at $mountPoint + * + * @param string $mountPoint + * @return \OC\Files\Storage\Storage + */ + public static function getStorage($mountPoint) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + $mount = self::$mounts->find($mountPoint); + return $mount->getStorage(); + } + + /** + * @param $id + * @return Mount\Mount[] + */ + public static function getMountByStorageId($id) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + return self::$mounts->findByStorageId($id); + } + + /** + * @param $id + * @return Mount\Mount[] + */ + public static function getMountByNumericId($id) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + return self::$mounts->findByNumericId($id); + } + + /** + * resolve a path to a storage and internal path + * + * @param string $path + * @return array consisting of the storage and the internal path + */ + static public function resolvePath($path) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + $mount = self::$mounts->find($path); + if ($mount) { + return array($mount->getStorage(), $mount->getInternalPath($path)); + } else { + return array(null, null); + } + } + + static public function init($user, $root) { + if (self::$defaultInstance) { + return false; + } + self::getLoader(); + self::$defaultInstance = new View($root); + + if (!self::$mounts) { + self::$mounts = new Mount\Manager(); + } + + //load custom mount config + self::initMountPoints($user); + + self::$loaded = true; + + return true; + } + + static public function initMounts() { + if (!self::$mounts) { + self::$mounts = new Mount\Manager(); + } + } + + /** + * Initialize system and personal mount points for a user + * + * @param string $user + */ + public static function initMountPoints($user = '') { + if ($user == '') { + $user = \OC_User::getUser(); + } + $parser = new \OC\ArrayParser(); + + $root = \OC_User::getHome($user); + self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user); + $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data"); + + //move config file to it's new position + if (is_file(\OC::$SERVERROOT . '/config/mount.json')) { + rename(\OC::$SERVERROOT . '/config/mount.json', $datadir . '/mount.json'); + } + // Load system mount points + if (is_file(\OC::$SERVERROOT . '/config/mount.php') or is_file($datadir . '/mount.json')) { + if (is_file($datadir . '/mount.json')) { + $mountConfig = json_decode(file_get_contents($datadir . '/mount.json'), true); + } elseif (is_file(\OC::$SERVERROOT . '/config/mount.php')) { + $mountConfig = $parser->parsePHP(file_get_contents(\OC::$SERVERROOT . '/config/mount.php')); + } + if (isset($mountConfig['global'])) { + foreach ($mountConfig['global'] as $mountPoint => $options) { + self::mount($options['class'], $options['options'], $mountPoint); + } + } + if (isset($mountConfig['group'])) { + foreach ($mountConfig['group'] as $group => $mounts) { + if (\OC_Group::inGroup($user, $group)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + self::mount($options['class'], $options['options'], $mountPoint); + } + } + } + } + if (isset($mountConfig['user'])) { + foreach ($mountConfig['user'] as $mountUser => $mounts) { + if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + self::mount($options['class'], $options['options'], $mountPoint); + } + } + } + } + } + // Load personal mount points + if (is_file($root . '/mount.php') or is_file($root . '/mount.json')) { + if (is_file($root . '/mount.json')) { + $mountConfig = json_decode(file_get_contents($root . '/mount.json'), true); + } elseif (is_file($root . '/mount.php')) { + $mountConfig = $parser->parsePHP(file_get_contents($root . '/mount.php')); + } + if (isset($mountConfig['user'][$user])) { + foreach ($mountConfig['user'][$user] as $mountPoint => $options) { + self::mount($options['class'], $options['options'], $mountPoint); + } + } + } + + // Chance to mount for other storages + \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root)); + } + + /** + * fill in the correct values for $user + * + * @param string $user + * @param string $input + * @return string + */ + private static function setUserVars($user, $input) { + return str_replace('$user', $user, $input); + } + + /** + * get the default filesystem view + * + * @return View + */ + static public function getView() { + return self::$defaultInstance; + } + + /** + * tear down the filesystem, removing all storage providers + */ + static public function tearDown() { + self::clearMounts(); + self::$defaultInstance = null; + } + + /** + * @brief get the relative path of the root data directory for the current user + * @return string + * + * Returns path like /admin/files + */ + static public function getRoot() { + return self::$defaultInstance->getRoot(); + } + + /** + * clear all mounts and storage backends + */ + public static function clearMounts() { + if (self::$mounts) { + self::$mounts->clear(); + } + } + + /** + * mount an \OC\Files\Storage\Storage in our virtual filesystem + * + * @param \OC\Files\Storage\Storage|string $class + * @param array $arguments + * @param string $mountpoint + */ + static public function mount($class, $arguments, $mountpoint) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } + $mount = new Mount\Mount($class, $mountpoint, $arguments, self::getLoader()); + self::$mounts->addMount($mount); + } + + /** + * return the path to a local version of the file + * we need this because we can't know if a file is stored local or not from + * outside the filestorage and for some purposes a local file is needed + * + * @param string $path + * @return string + */ + static public function getLocalFile($path) { + return self::$defaultInstance->getLocalFile($path); + } + + /** + * @param string $path + * @return string + */ + static public function getLocalFolder($path) { + return self::$defaultInstance->getLocalFolder($path); + } + + /** + * return path to file which reflects one visible in browser + * + * @param string $path + * @return string + */ + static public function getLocalPath($path) { + $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files'; + $newpath = $path; + if (strncmp($newpath, $datadir, strlen($datadir)) == 0) { + $newpath = substr($path, strlen($datadir)); + } + return $newpath; + } + + /** + * check if the requested path is valid + * + * @param string $path + * @return bool + */ + static public function isValidPath($path) { + $path = self::normalizePath($path); + if (!$path || $path[0] !== '/') { + $path = '/' . $path; + } + if (strstr($path, '/../') || strrchr($path, '/') === '/..') { + return false; + } + return true; + } + + /** + * checks if a file is blacklisted for storage in the filesystem + * Listens to write and rename hooks + * + * @param array $data from hook + */ + static public function isBlacklisted($data) { + if (isset($data['path'])) { + $path = $data['path']; + } else if (isset($data['newpath'])) { + $path = $data['newpath']; + } + if (isset($path)) { + if (self::isFileBlacklisted($path)) { + $data['run'] = false; + } + } + } + + /** + * @param string $filename + * @return bool + */ + static public function isFileBlacklisted($filename) { + $blacklist = \OC_Config::getValue('blacklisted_files', array('.htaccess')); + $filename = strtolower(basename($filename)); + return (in_array($filename, $blacklist)); + } + + /** + * @brief check if the directory should be ignored when scanning + * NOTE: the special directories . and .. would cause never ending recursion + * @param String $dir + * @return boolean + */ + static public function isIgnoredDir($dir) { + if ($dir === '.' || $dir === '..') { + return true; + } + return false; + } + + /** + * following functions are equivalent to their php builtin equivalents for arguments/return values. + */ + static public function mkdir($path) { + return self::$defaultInstance->mkdir($path); + } + + static public function rmdir($path) { + return self::$defaultInstance->rmdir($path); + } + + static public function opendir($path) { + return self::$defaultInstance->opendir($path); + } + + static public function readdir($path) { + return self::$defaultInstance->readdir($path); + } + + static public function is_dir($path) { + return self::$defaultInstance->is_dir($path); + } + + static public function is_file($path) { + return self::$defaultInstance->is_file($path); + } + + static public function stat($path) { + return self::$defaultInstance->stat($path); + } + + static public function filetype($path) { + return self::$defaultInstance->filetype($path); + } + + static public function filesize($path) { + return self::$defaultInstance->filesize($path); + } + + static public function readfile($path) { + return self::$defaultInstance->readfile($path); + } + + static public function isCreatable($path) { + return self::$defaultInstance->isCreatable($path); + } + + static public function isReadable($path) { + return self::$defaultInstance->isReadable($path); + } + + static public function isUpdatable($path) { + return self::$defaultInstance->isUpdatable($path); + } + + static public function isDeletable($path) { + return self::$defaultInstance->isDeletable($path); + } + + static public function isSharable($path) { + return self::$defaultInstance->isSharable($path); + } + + static public function file_exists($path) { + return self::$defaultInstance->file_exists($path); + } + + static public function filemtime($path) { + return self::$defaultInstance->filemtime($path); + } + + static public function touch($path, $mtime = null) { + return self::$defaultInstance->touch($path, $mtime); + } + + static public function file_get_contents($path) { + return self::$defaultInstance->file_get_contents($path); + } + + static public function file_put_contents($path, $data) { + return self::$defaultInstance->file_put_contents($path, $data); + } + + static public function unlink($path) { + return self::$defaultInstance->unlink($path); + } + + static public function rename($path1, $path2) { + return self::$defaultInstance->rename($path1, $path2); + } + + static public function copy($path1, $path2) { + return self::$defaultInstance->copy($path1, $path2); + } + + static public function fopen($path, $mode) { + return self::$defaultInstance->fopen($path, $mode); + } + + static public function toTmpFile($path) { + return self::$defaultInstance->toTmpFile($path); + } + + static public function fromTmpFile($tmpFile, $path) { + return self::$defaultInstance->fromTmpFile($tmpFile, $path); + } + + static public function getMimeType($path) { + return self::$defaultInstance->getMimeType($path); + } + + static public function hash($type, $path, $raw = false) { + return self::$defaultInstance->hash($type, $path, $raw); + } + + static public function free_space($path = '/') { + return self::$defaultInstance->free_space($path); + } + + static public function search($query) { + return self::$defaultInstance->search($query); + } + + static public function searchByMime($query) { + return self::$defaultInstance->searchByMime($query); + } + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + */ + static public function hasUpdated($path, $time) { + return self::$defaultInstance->hasUpdated($path, $time); + } + + /** + * @brief Fix common problems with a file path + * @param string $path + * @param bool $stripTrailingSlash + * @return string + */ + public static function normalizePath($path, $stripTrailingSlash = true) { + if ($path == '') { + return '/'; + } + //no windows style slashes + $path = str_replace('\\', '/', $path); + //add leading slash + if ($path[0] !== '/') { + $path = '/' . $path; + } + //remove duplicate slashes + while (strpos($path, '//') !== false) { + $path = str_replace('//', '/', $path); + } + //remove trailing slash + if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') { + $path = substr($path, 0, -1); + } + //normalize unicode if possible + $path = \OC_Util::normalizeUnicode($path); + + return $path; + } + + /** + * get the filesystem info + * + * @param string $path + * @return array + * + * returns an associative array with the following keys: + * - size + * - mtime + * - mimetype + * - encrypted + * - versioned + */ + public static function getFileInfo($path) { + return self::$defaultInstance->getFileInfo($path); + } + + /** + * change file metadata + * + * @param string $path + * @param array $data + * @return int + * + * returns the fileid of the updated file + */ + public static function putFileInfo($path, $data) { + return self::$defaultInstance->putFileInfo($path, $data); + } + + /** + * get the content of a directory + * + * @param string $directory path under datadirectory + * @param string $mimetype_filter limit returned content to this mimetype or mimepart + * @return array + */ + public static function getDirectoryContent($directory, $mimetype_filter = '') { + return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter); + } + + /** + * Get the path of a file by id + * + * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file + * + * @param int $id + * @return string + */ + public static function getPath($id) { + return self::$defaultInstance->getPath($id); + } + + /** + * Get the owner for a file or folder + * + * @param string $path + * @return string + */ + public static function getOwner($path) { + return self::$defaultInstance->getOwner($path); + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + static public function getETag($path) { + return self::$defaultInstance->getETag($path); + } +} + +\OC_Util::setupFS(); diff --git a/lib/private/files/mapper.php b/lib/private/files/mapper.php new file mode 100644 index 00000000000..47abd4e52fe --- /dev/null +++ b/lib/private/files/mapper.php @@ -0,0 +1,239 @@ +unchangedPhysicalRoot = $rootDir; + } + + /** + * @param string $logicPath + * @param bool $create indicates if the generated physical name shall be stored in the database or not + * @return string the physical path + */ + public function logicToPhysical($logicPath, $create) { + $physicalPath = $this->resolveLogicPath($logicPath); + if ($physicalPath !== null) { + return $physicalPath; + } + + return $this->create($logicPath, $create); + } + + /** + * @param string $physicalPath + * @return string + */ + public function physicalToLogic($physicalPath) { + $logicPath = $this->resolvePhysicalPath($physicalPath); + if ($logicPath !== null) { + return $logicPath; + } + + $this->insert($physicalPath, $physicalPath); + return $physicalPath; + } + + /** + * @param string $path + * @param bool $isLogicPath indicates if $path is logical or physical + * @param $recursive + * @return void + */ + public function removePath($path, $isLogicPath, $recursive) { + if ($recursive) { + $path=$path.'%'; + } + + if ($isLogicPath) { + \OC_DB::executeAudited('DELETE FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?', array($path)); + } else { + \OC_DB::executeAudited('DELETE FROM `*PREFIX*file_map` WHERE `physic_path` LIKE ?', array($path)); + } + } + + /** + * @param $path1 + * @param $path2 + * @throws \Exception + */ + public function copy($path1, $path2) + { + $path1 = $this->stripLast($path1); + $path2 = $this->stripLast($path2); + $physicPath1 = $this->logicToPhysical($path1, true); + $physicPath2 = $this->logicToPhysical($path2, true); + + $sql = 'SELECT * FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?'; + $result = \OC_DB::executeAudited($sql, array($path1.'%')); + $updateQuery = \OC_DB::prepare('UPDATE `*PREFIX*file_map`' + .' SET `logic_path` = ?' + .' , `logic_path_hash` = ?' + .' , `physic_path` = ?' + .' , `physic_path_hash` = ?' + .' WHERE `logic_path` = ?'); + while( $row = $result->fetchRow()) { + $currentLogic = $row['logic_path']; + $currentPhysic = $row['physic_path']; + $newLogic = $path2.$this->stripRootFolder($currentLogic, $path1); + $newPhysic = $physicPath2.$this->stripRootFolder($currentPhysic, $physicPath1); + if ($path1 !== $currentLogic) { + try { + \OC_DB::executeAudited($updateQuery, array($newLogic, md5($newLogic), $newPhysic, md5($newPhysic), + $currentLogic)); + } catch (\Exception $e) { + error_log('Mapper::Copy failed '.$currentLogic.' -> '.$newLogic.'\n'.$e); + throw $e; + } + } + } + } + + /** + * @param $path + * @param $root + * @return bool|string + */ + public function stripRootFolder($path, $root) { + if (strpos($path, $root) !== 0) { + // throw exception ??? + return false; + } + if (strlen($path) > strlen($root)) { + return substr($path, strlen($root)); + } + + return ''; + } + + private function stripLast($path) { + if (substr($path, -1) == '/') { + $path = substr_replace($path, '', -1); + } + return $path; + } + + private function resolveLogicPath($logicPath) { + $logicPath = $this->stripLast($logicPath); + $sql = 'SELECT * FROM `*PREFIX*file_map` WHERE `logic_path_hash` = ?'; + $result = \OC_DB::executeAudited($sql, array(md5($logicPath))); + $result = $result->fetchRow(); + if ($result === false) { + return null; + } + + return $result['physic_path']; + } + + private function resolvePhysicalPath($physicalPath) { + $physicalPath = $this->stripLast($physicalPath); + $sql = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `physic_path_hash` = ?'); + $result = \OC_DB::executeAudited($sql, array(md5($physicalPath))); + $result = $result->fetchRow(); + + return $result['logic_path']; + } + + private function create($logicPath, $store) { + $logicPath = $this->stripLast($logicPath); + $index = 0; + + // create the slugified path + $physicalPath = $this->slugifyPath($logicPath); + + // detect duplicates + while ($this->resolvePhysicalPath($physicalPath) !== null) { + $physicalPath = $this->slugifyPath($logicPath, $index++); + } + + // insert the new path mapping if requested + if ($store) { + $this->insert($logicPath, $physicalPath); + } + + return $physicalPath; + } + + private function insert($logicPath, $physicalPath) { + $sql = 'INSERT INTO `*PREFIX*file_map` (`logic_path`, `physic_path`, `logic_path_hash`, `physic_path_hash`) + VALUES (?, ?, ?, ?)'; + \OC_DB::executeAudited($sql, array($logicPath, $physicalPath, md5($logicPath), md5($physicalPath))); + } + + public function slugifyPath($path, $index=null) { + $path = $this->stripRootFolder($path, $this->unchangedPhysicalRoot); + + $pathElements = explode('/', $path); + $sluggedElements = array(); + + $last= end($pathElements); + + foreach ($pathElements as $pathElement) { + // remove empty elements + if (empty($pathElement)) { + continue; + } + + $sluggedElements[] = self::slugify($pathElement); + } + + // apply index to file name + if ($index !== null) { + $last= array_pop($sluggedElements); + + // if filename contains periods - add index number before last period + if (preg_match('~\.[^\.]+$~i',$last,$extension)){ + array_push($sluggedElements, substr($last,0,-(strlen($extension[0]))).'-'.$index.$extension[0]); + } else { + // if filename doesn't contain periods add index ofter the last char + array_push($sluggedElements, $last.'-'.$index); + } + + } + + $sluggedPath = $this->unchangedPhysicalRoot.implode('/', $sluggedElements); + return $this->stripLast($sluggedPath); + } + + /** + * Modifies a string to remove all non ASCII characters and spaces. + * + * @param string $text + * @return string + */ + private function slugify($text) + { + // replace non letter or digits or dots by - + $text = preg_replace('~[^\\pL\d\.]+~u', '-', $text); + + // trim + $text = trim($text, '-'); + + // transliterate + if (function_exists('iconv')) { + $text = iconv('utf-8', 'us-ascii//TRANSLIT//IGNORE', $text); + } + + // lowercase + $text = strtolower($text); + + // remove unwanted characters + $text = preg_replace('~[^-\w\.]+~', '', $text); + + // trim ending dots (for security reasons and win compatibility) + $text = preg_replace('~\.+$~', '', $text); + + if (empty($text)) { + return uniqid(); + } + + return $text; + } +} diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php new file mode 100644 index 00000000000..4c432dcf724 --- /dev/null +++ b/lib/private/files/mount/manager.php @@ -0,0 +1,127 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Mount; + +use \OC\Files\Filesystem; + +class Manager { + /** + * @var Mount[] + */ + private $mounts = array(); + + /** + * @param Mount $mount + */ + public function addMount($mount) { + $this->mounts[$mount->getMountPoint()] = $mount; + } + + /** + * Find the mount for $path + * + * @param $path + * @return Mount + */ + public function find($path) { + \OC_Util::setupFS(); + $path = $this->formatPath($path); + if (isset($this->mounts[$path])) { + return $this->mounts[$path]; + } + + \OC_Hook::emit('OC_Filesystem', 'get_mountpoint', array('path' => $path)); + $foundMountPoint = ''; + $mountPoints = array_keys($this->mounts); + foreach ($mountPoints as $mountpoint) { + if (strpos($path, $mountpoint) === 0 and strlen($mountpoint) > strlen($foundMountPoint)) { + $foundMountPoint = $mountpoint; + } + } + if (isset($this->mounts[$foundMountPoint])) { + return $this->mounts[$foundMountPoint]; + } else { + return null; + } + } + + /** + * Find all mounts in $path + * + * @param $path + * @return Mount[] + */ + public function findIn($path) { + \OC_Util::setupFS(); + $path = $this->formatPath($path); + $result = array(); + $pathLength = strlen($path); + $mountPoints = array_keys($this->mounts); + foreach ($mountPoints as $mountPoint) { + if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) { + $result[] = $this->mounts[$mountPoint]; + } + } + return $result; + } + + public function clear() { + $this->mounts = array(); + } + + /** + * Find mounts by storage id + * + * @param string $id + * @return Mount[] + */ + public function findByStorageId($id) { + \OC_Util::setupFS(); + if (strlen($id) > 64) { + $id = md5($id); + } + $result = array(); + foreach ($this->mounts as $mount) { + if ($mount->getStorageId() === $id) { + $result[] = $mount; + } + } + return $result; + } + + /** + * @return Mount[] + */ + public function getAll() { + return $this->mounts; + } + + /** + * Find mounts by numeric storage id + * + * @param string $id + * @return Mount + */ + public function findByNumericId($id) { + $storageId = \OC\Files\Cache\Storage::getStorageId($id); + return $this->findByStorageId($storageId); + } + + /** + * @param string $path + * @return string + */ + private function formatPath($path) { + $path = Filesystem::normalizePath($path); + if (strlen($path) > 1) { + $path .= '/'; + } + return $path; + } +} diff --git a/lib/private/files/mount/mount.php b/lib/private/files/mount/mount.php new file mode 100644 index 00000000000..0ce2f5975c7 --- /dev/null +++ b/lib/private/files/mount/mount.php @@ -0,0 +1,148 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Mount; + +use \OC\Files\Filesystem; +use OC\Files\Storage\Loader; +use OC\Files\Storage\Storage; + +class Mount { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage = null; + private $class; + private $storageId; + private $arguments = array(); + private $mountPoint; + + /** + * @var \OC\Files\Storage\Loader $loader + */ + private $loader; + + /** + * @param string | \OC\Files\Storage\Storage $storage + * @param string $mountpoint + * @param array $arguments (optional)\ + * @param \OC\Files\Storage\Loader $loader + */ + public function __construct($storage, $mountpoint, $arguments = null, $loader = null) { + if (is_null($arguments)) { + $arguments = array(); + } + if (is_null($loader)) { + $this->loader = new Loader(); + } else { + $this->loader = $loader; + } + + $mountpoint = $this->formatPath($mountpoint); + if ($storage instanceof Storage) { + $this->class = get_class($storage); + $this->storage = $this->loader->wrap($mountpoint, $storage); + } else { + // Update old classes to new namespace + if (strpos($storage, 'OC_Filestorage_') !== false) { + $storage = '\OC\Files\Storage\\' . substr($storage, 15); + } + $this->class = $storage; + $this->arguments = $arguments; + } + $this->mountPoint = $mountpoint; + } + + /** + * @return string + */ + public function getMountPoint() { + return $this->mountPoint; + } + + /** + * create the storage that is mounted + * + * @return \OC\Files\Storage\Storage + */ + private function createStorage() { + if (class_exists($this->class)) { + try { + return $this->loader->load($this->mountPoint, $this->class, $this->arguments); + } catch (\Exception $exception) { + \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR); + return null; + } + } else { + \OC_Log::write('core', 'storage backend ' . $this->class . ' not found', \OC_Log::ERROR); + return null; + } + } + + /** + * @return \OC\Files\Storage\Storage + */ + public function getStorage() { + if (is_null($this->storage)) { + $this->storage = $this->createStorage(); + } + return $this->storage; + } + + /** + * @return string + */ + public function getStorageId() { + if (!$this->storageId) { + if (is_null($this->storage)) { + $storage = $this->createStorage(); //FIXME: start using exceptions + if (is_null($storage)) { + return null; + } + $this->storage = $storage; + } + $this->storageId = $this->storage->getId(); + if (strlen($this->storageId) > 64) { + $this->storageId = md5($this->storageId); + } + } + return $this->storageId; + } + + /** + * @param string $path + * @return string + */ + public function getInternalPath($path) { + if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) { + $internalPath = ''; + } else { + $internalPath = substr($path, strlen($this->mountPoint)); + } + return $internalPath; + } + + /** + * @param string $path + * @return string + */ + private function formatPath($path) { + $path = Filesystem::normalizePath($path); + if (strlen($path) > 1) { + $path .= '/'; + } + return $path; + } + + /** + * @param callable $wrapper + */ + public function wrapStorage($wrapper) { + $this->storage = $wrapper($this->mountPoint, $this->storage); + } +} diff --git a/lib/private/files/node/file.php b/lib/private/files/node/file.php new file mode 100644 index 00000000000..75d5e0166b6 --- /dev/null +++ b/lib/private/files/node/file.php @@ -0,0 +1,155 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OCP\Files\NotPermittedException; + +class File extends Node implements \OCP\Files\File { + /** + * @return string + * @throws \OCP\Files\NotPermittedException + */ + public function getContent() { + if ($this->checkPermissions(\OCP\PERMISSION_READ)) { + /** + * @var \OC\Files\Storage\Storage $storage; + */ + return $this->view->file_get_contents($this->path); + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $data + * @throws \OCP\Files\NotPermittedException + */ + public function putContent($data) { + if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { + $this->sendHooks(array('preWrite')); + $this->view->file_put_contents($this->path, $data); + $this->sendHooks(array('postWrite')); + } else { + throw new NotPermittedException(); + } + } + + /** + * @return string + */ + public function getMimeType() { + return $this->view->getMimeType($this->path); + } + + /** + * @param string $mode + * @return resource + * @throws \OCP\Files\NotPermittedException + */ + public function fopen($mode) { + $preHooks = array(); + $postHooks = array(); + $requiredPermissions = \OCP\PERMISSION_READ; + switch ($mode) { + case 'r+': + case 'rb+': + case 'w+': + case 'wb+': + case 'x+': + case 'xb+': + case 'a+': + case 'ab+': + case 'w': + case 'wb': + case 'x': + case 'xb': + case 'a': + case 'ab': + $preHooks[] = 'preWrite'; + $postHooks[] = 'postWrite'; + $requiredPermissions |= \OCP\PERMISSION_UPDATE; + break; + } + + if ($this->checkPermissions($requiredPermissions)) { + $this->sendHooks($preHooks); + $result = $this->view->fopen($this->path, $mode); + $this->sendHooks($postHooks); + return $result; + } else { + throw new NotPermittedException(); + } + } + + public function delete() { + if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { + $this->sendHooks(array('preDelete')); + $this->view->unlink($this->path); + $nonExisting = new NonExistingFile($this->root, $this->view, $this->path); + $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); + $this->exists = false; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OCP\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->copy($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + return $targetNode; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OCP\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function move($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->rename($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + $this->path = $targetPath; + return $targetNode; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $type + * @param bool $raw + * @return string + */ + public function hash($type, $raw = false) { + return $this->view->hash($type, $this->path, $raw); + } +} diff --git a/lib/private/files/node/folder.php b/lib/private/files/node/folder.php new file mode 100644 index 00000000000..923f53821b2 --- /dev/null +++ b/lib/private/files/node/folder.php @@ -0,0 +1,382 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; + +class Folder extends Node implements \OCP\Files\Folder { + /** + * @param string $path path relative to the folder + * @return string + * @throws \OCP\Files\NotPermittedException + */ + public function getFullPath($path) { + if (!$this->isValidPath($path)) { + throw new NotPermittedException(); + } + return $this->path . $this->normalizePath($path); + } + + /** + * @param string $path + * @throws \OCP\Files\NotFoundException + * @return string + */ + public function getRelativePath($path) { + if ($this->path === '' or $this->path === '/') { + return $this->normalizePath($path); + } + if (strpos($path, $this->path) !== 0) { + throw new NotFoundException(); + } else { + $path = substr($path, strlen($this->path)); + if (strlen($path) === 0) { + return '/'; + } else { + return $this->normalizePath($path); + } + } + } + + /** + * check if a node is a (grand-)child of the folder + * + * @param \OC\Files\Node\Node $node + * @return bool + */ + public function isSubNode($node) { + return strpos($node->getPath(), $this->path . '/') === 0; + } + + /** + * get the content of this directory + * + * @throws \OCP\Files\NotFoundException + * @return Node[] + */ + public function getDirectoryListing() { + $result = array(); + + /** + * @var \OC\Files\Storage\Storage $storage + */ + list($storage, $internalPath) = $this->view->resolvePath($this->path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $permissionsCache = $storage->getPermissionsCache($internalPath); + + //trigger cache update check + $this->view->getFileInfo($this->path); + + $files = $cache->getFolderContents($internalPath); + $permissions = $permissionsCache->getDirectoryPermissions($this->getId(), $this->root->getUser()->getUID()); + } else { + $files = array(); + } + + //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders + $mounts = $this->root->getMountsIn($this->path); + $dirLength = strlen($this->path); + foreach ($mounts as $mount) { + $subStorage = $mount->getStorage(); + if ($subStorage) { + $subCache = $subStorage->getCache(''); + + if ($subCache->getStatus('') === Cache::NOT_FOUND) { + $subScanner = $subStorage->getScanner(''); + $subScanner->scanFile(''); + } + + $rootEntry = $subCache->get(''); + if ($rootEntry) { + $relativePath = trim(substr($mount->getMountPoint(), $dirLength), '/'); + if ($pos = strpos($relativePath, '/')) { + //mountpoint inside subfolder add size to the correct folder + $entryName = substr($relativePath, 0, $pos); + foreach ($files as &$entry) { + if ($entry['name'] === $entryName) { + if ($rootEntry['size'] >= 0) { + $entry['size'] += $rootEntry['size']; + } else { + $entry['size'] = -1; + } + } + } + } else { //mountpoint in this folder, add an entry for it + $rootEntry['name'] = $relativePath; + $rootEntry['storageObject'] = $subStorage; + + //remove any existing entry with the same name + foreach ($files as $i => $file) { + if ($file['name'] === $rootEntry['name']) { + $files[$i] = null; + break; + } + } + $files[] = $rootEntry; + } + } + } + } + + foreach ($files as $file) { + if ($file) { + if (isset($permissions[$file['fileid']])) { + $file['permissions'] = $permissions[$file['fileid']]; + } + $node = $this->createNode($this->path . '/' . $file['name'], $file); + $result[] = $node; + } + } + + return $result; + } + + /** + * @param string $path + * @param array $info + * @return File|Folder + */ + protected function createNode($path, $info = array()) { + if (!isset($info['mimetype'])) { + $isDir = $this->view->is_dir($path); + } else { + $isDir = $info['mimetype'] === 'httpd/unix-directory'; + } + if ($isDir) { + return new Folder($this->root, $this->view, $path); + } else { + return new File($this->root, $this->view, $path); + } + } + + /** + * Get the node at $path + * + * @param string $path + * @return \OC\Files\Node\Node + * @throws \OCP\Files\NotFoundException + */ + public function get($path) { + return $this->root->get($this->getFullPath($path)); + } + + /** + * @param string $path + * @return bool + */ + public function nodeExists($path) { + try { + $this->get($path); + return true; + } catch (NotFoundException $e) { + return false; + } + } + + /** + * @param string $path + * @return \OC\Files\Node\Folder + * @throws \OCP\Files\NotPermittedException + */ + public function newFolder($path) { + if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { + $fullPath = $this->getFullPath($path); + $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->root->emit('\OC\Files', 'preCreate', array($nonExisting)); + $this->view->mkdir($fullPath); + $node = new Folder($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'postWrite', array($node)); + $this->root->emit('\OC\Files', 'postCreate', array($node)); + return $node; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $path + * @return \OC\Files\Node\File + * @throws \OCP\Files\NotPermittedException + */ + public function newFile($path) { + if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) { + $fullPath = $this->getFullPath($path); + $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->root->emit('\OC\Files', 'preCreate', array($nonExisting)); + $this->view->touch($fullPath); + $node = new File($this->root, $this->view, $fullPath); + $this->root->emit('\OC\Files', 'postWrite', array($node)); + $this->root->emit('\OC\Files', 'postCreate', array($node)); + return $node; + } else { + throw new NotPermittedException(); + } + } + + /** + * search for files with the name matching $query + * + * @param string $query + * @return \OC\Files\Node\Node[] + */ + public function search($query) { + return $this->searchCommon('%' . $query . '%', 'search'); + } + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return Node[] + */ + public function searchByMime($mimetype) { + return $this->searchCommon($mimetype, 'searchByMime'); + } + + /** + * @param string $query + * @param string $method + * @return \OC\Files\Node\Node[] + */ + private function searchCommon($query, $method) { + $files = array(); + $rootLength = strlen($this->path); + /** + * @var \OC\Files\Storage\Storage $storage + */ + list($storage, $internalPath) = $this->view->resolvePath($this->path); + $internalRootLength = strlen($internalPath); + + $cache = $storage->getCache(''); + + $results = $cache->$method($query); + foreach ($results as $result) { + if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) { + $result['internalPath'] = $result['path']; + $result['path'] = substr($result['path'], $internalRootLength); + $result['storage'] = $storage; + $files[] = $result; + } + } + + $mounts = $this->root->getMountsIn($this->path); + foreach ($mounts as $mount) { + $storage = $mount->getStorage(); + if ($storage) { + $cache = $storage->getCache(''); + + $relativeMountPoint = substr($mount->getMountPoint(), $rootLength); + $results = $cache->$method($query); + foreach ($results as $result) { + $result['internalPath'] = $result['path']; + $result['path'] = $relativeMountPoint . $result['path']; + $result['storage'] = $storage; + $files[] = $result; + } + } + } + + $result = array(); + foreach ($files as $file) { + $result[] = $this->createNode($this->normalizePath($this->path . '/' . $file['path']), $file); + } + + return $result; + } + + /** + * @param $id + * @return \OC\Files\Node\Node[] + */ + public function getById($id) { + $nodes = $this->root->getById($id); + $result = array(); + foreach ($nodes as $node) { + $pathPart = substr($node->getPath(), 0, strlen($this->getPath()) + 1); + if ($this->path === '/' or $pathPart === $this->getPath() . '/') { + $result[] = $node; + } + } + return $result; + } + + public function getFreeSpace() { + return $this->view->free_space($this->path); + } + + /** + * @return bool + */ + public function isCreatable() { + return $this->checkPermissions(\OCP\PERMISSION_CREATE); + } + + public function delete() { + if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) { + $this->sendHooks(array('preDelete')); + $this->view->rmdir($this->path); + $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path); + $this->root->emit('\OC\Files', 'postDelete', array($nonExisting)); + $this->exists = false; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OCP\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->copy($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + return $targetNode; + } else { + throw new NotPermittedException(); + } + } + + /** + * @param string $targetPath + * @throws \OCP\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function move($targetPath) { + $targetPath = $this->normalizePath($targetPath); + $parent = $this->root->get(dirname($targetPath)); + if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) { + $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath); + $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting)); + $this->root->emit('\OC\Files', 'preWrite', array($nonExisting)); + $this->view->rename($this->path, $targetPath); + $targetNode = $this->root->get($targetPath); + $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode)); + $this->root->emit('\OC\Files', 'postWrite', array($targetNode)); + $this->path = $targetPath; + return $targetNode; + } else { + throw new NotPermittedException(); + } + } +} diff --git a/lib/private/files/node/node.php b/lib/private/files/node/node.php new file mode 100644 index 00000000000..063e2424a64 --- /dev/null +++ b/lib/private/files/node/node.php @@ -0,0 +1,245 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; + +class Node implements \OCP\Files\Node { + /** + * @var \OC\Files\View $view + */ + protected $view; + + /** + * @var \OC\Files\Node\Root $root + */ + protected $root; + + /** + * @var string $path + */ + protected $path; + + /** + * @param \OC\Files\View $view + * @param \OC\Files\Node\Root Root $root + * @param string $path + */ + public function __construct($root, $view, $path) { + $this->view = $view; + $this->root = $root; + $this->path = $path; + } + + /** + * @param string[] $hooks + */ + protected function sendHooks($hooks) { + foreach ($hooks as $hook) { + $this->root->emit('\OC\Files', $hook, array($this)); + } + } + + /** + * @param int $permissions + * @return bool + */ + protected function checkPermissions($permissions) { + return ($this->getPermissions() & $permissions) === $permissions; + } + + /** + * @param string $targetPath + * @throws \OCP\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function move($targetPath) { + return; + } + + public function delete() { + return; + } + + /** + * @param string $targetPath + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + return; + } + + /** + * @param int $mtime + * @throws \OCP\Files\NotPermittedException + */ + public function touch($mtime = null) { + if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) { + $this->sendHooks(array('preTouch')); + $this->view->touch($this->path, $mtime); + $this->sendHooks(array('postTouch')); + } else { + throw new NotPermittedException(); + } + } + + /** + * @return \OC\Files\Storage\Storage + * @throws \OCP\Files\NotFoundException + */ + public function getStorage() { + list($storage,) = $this->view->resolvePath($this->path); + return $storage; + } + + /** + * @return string + */ + public function getPath() { + return $this->path; + } + + /** + * @return string + */ + public function getInternalPath() { + list(, $internalPath) = $this->view->resolvePath($this->path); + return $internalPath; + } + + /** + * @return int + */ + public function getId() { + $info = $this->view->getFileInfo($this->path); + return $info['fileid']; + } + + /** + * @return array + */ + public function stat() { + return $this->view->stat($this->path); + } + + /** + * @return int + */ + public function getMTime() { + return $this->view->filemtime($this->path); + } + + /** + * @return int + */ + public function getSize() { + return $this->view->filesize($this->path); + } + + /** + * @return string + */ + public function getEtag() { + $info = $this->view->getFileInfo($this->path); + return $info['etag']; + } + + /** + * @return int + */ + public function getPermissions() { + $info = $this->view->getFileInfo($this->path); + return $info['permissions']; + } + + /** + * @return bool + */ + public function isReadable() { + return $this->checkPermissions(\OCP\PERMISSION_READ); + } + + /** + * @return bool + */ + public function isUpdateable() { + return $this->checkPermissions(\OCP\PERMISSION_UPDATE); + } + + /** + * @return bool + */ + public function isDeletable() { + return $this->checkPermissions(\OCP\PERMISSION_DELETE); + } + + /** + * @return bool + */ + public function isShareable() { + return $this->checkPermissions(\OCP\PERMISSION_SHARE); + } + + /** + * @return Node + */ + public function getParent() { + return $this->root->get(dirname($this->path)); + } + + /** + * @return string + */ + public function getName() { + return basename($this->path); + } + + /** + * @param string $path + * @return string + */ + protected function normalizePath($path) { + if ($path === '' or $path === '/') { + return '/'; + } + //no windows style slashes + $path = str_replace('\\', '/', $path); + //add leading slash + if ($path[0] !== '/') { + $path = '/' . $path; + } + //remove duplicate slashes + while (strpos($path, '//') !== false) { + $path = str_replace('//', '/', $path); + } + //remove trailing slash + $path = rtrim($path, '/'); + + return $path; + } + + /** + * check if the requested path is valid + * + * @param string $path + * @return bool + */ + public function isValidPath($path) { + if (!$path || $path[0] !== '/') { + $path = '/' . $path; + } + if (strstr($path, '/../') || strrchr($path, '/') === '/..') { + return false; + } + return true; + } +} diff --git a/lib/private/files/node/nonexistingfile.php b/lib/private/files/node/nonexistingfile.php new file mode 100644 index 00000000000..d45076f7fee --- /dev/null +++ b/lib/private/files/node/nonexistingfile.php @@ -0,0 +1,89 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OCP\Files\NotFoundException; + +class NonExistingFile extends File { + /** + * @param string $newPath + * @throws \OCP\Files\NotFoundException + */ + public function rename($newPath) { + throw new NotFoundException(); + } + + public function delete() { + throw new NotFoundException(); + } + + public function copy($newPath) { + throw new NotFoundException(); + } + + public function touch($mtime = null) { + throw new NotFoundException(); + } + + public function getId() { + throw new NotFoundException(); + } + + public function stat() { + throw new NotFoundException(); + } + + public function getMTime() { + throw new NotFoundException(); + } + + public function getSize() { + throw new NotFoundException(); + } + + public function getEtag() { + throw new NotFoundException(); + } + + public function getPermissions() { + throw new NotFoundException(); + } + + public function isReadable() { + throw new NotFoundException(); + } + + public function isUpdateable() { + throw new NotFoundException(); + } + + public function isDeletable() { + throw new NotFoundException(); + } + + public function isShareable() { + throw new NotFoundException(); + } + + public function getContent() { + throw new NotFoundException(); + } + + public function putContent($data) { + throw new NotFoundException(); + } + + public function getMimeType() { + throw new NotFoundException(); + } + + public function fopen($mode) { + throw new NotFoundException(); + } +} diff --git a/lib/private/files/node/nonexistingfolder.php b/lib/private/files/node/nonexistingfolder.php new file mode 100644 index 00000000000..0346cbf1e21 --- /dev/null +++ b/lib/private/files/node/nonexistingfolder.php @@ -0,0 +1,113 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OCP\Files\NotFoundException; + +class NonExistingFolder extends Folder { + /** + * @param string $newPath + * @throws \OCP\Files\NotFoundException + */ + public function rename($newPath) { + throw new NotFoundException(); + } + + public function delete() { + throw new NotFoundException(); + } + + public function copy($newPath) { + throw new NotFoundException(); + } + + public function touch($mtime = null) { + throw new NotFoundException(); + } + + public function getId() { + throw new NotFoundException(); + } + + public function stat() { + throw new NotFoundException(); + } + + public function getMTime() { + throw new NotFoundException(); + } + + public function getSize() { + throw new NotFoundException(); + } + + public function getEtag() { + throw new NotFoundException(); + } + + public function getPermissions() { + throw new NotFoundException(); + } + + public function isReadable() { + throw new NotFoundException(); + } + + public function isUpdateable() { + throw new NotFoundException(); + } + + public function isDeletable() { + throw new NotFoundException(); + } + + public function isShareable() { + throw new NotFoundException(); + } + + public function get($path) { + throw new NotFoundException(); + } + + public function getDirectoryListing() { + throw new NotFoundException(); + } + + public function nodeExists($path) { + return false; + } + + public function newFolder($path) { + throw new NotFoundException(); + } + + public function newFile($path) { + throw new NotFoundException(); + } + + public function search($pattern) { + throw new NotFoundException(); + } + + public function searchByMime($mime) { + throw new NotFoundException(); + } + + public function getById($id) { + throw new NotFoundException(); + } + + public function getFreeSpace() { + throw new NotFoundException(); + } + + public function isCreatable() { + throw new NotFoundException(); + } +} diff --git a/lib/private/files/node/root.php b/lib/private/files/node/root.php new file mode 100644 index 00000000000..e3d58476e9c --- /dev/null +++ b/lib/private/files/node/root.php @@ -0,0 +1,337 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Node; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OC\Files\Mount\Manager; +use OC\Files\Mount\Mount; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; +use OC\Hooks\Emitter; +use OC\Hooks\PublicEmitter; + +/** + * Class Root + * + * Hooks available in scope \OC\Files + * - preWrite(\OCP\Files\Node $node) + * - postWrite(\OCP\Files\Node $node) + * - preCreate(\OCP\Files\Node $node) + * - postCreate(\OCP\Files\Node $node) + * - preDelete(\OCP\Files\Node $node) + * - postDelete(\OCP\Files\Node $node) + * - preTouch(\OC\FilesP\Node $node, int $mtime) + * - postTouch(\OCP\Files\Node $node) + * - preCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) + * - postCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) + * - preRename(\OCP\Files\Node $source, \OCP\Files\Node $target) + * - postRename(\OCP\Files\Node $source, \OCP\Files\Node $target) + * + * @package OC\Files\Node + */ +class Root extends Folder implements Emitter { + + /** + * @var \OC\Files\Mount\Manager $mountManager + */ + private $mountManager; + + /** + * @var \OC\Hooks\PublicEmitter + */ + private $emitter; + + /** + * @var \OC\User\User $user + */ + private $user; + + /** + * @param \OC\Files\Mount\Manager $manager + * @param \OC\Files\View $view + * @param \OC\User\User $user + */ + public function __construct($manager, $view, $user) { + parent::__construct($this, $view, ''); + $this->mountManager = $manager; + $this->user = $user; + $this->emitter = new PublicEmitter(); + } + + /** + * Get the user for which the filesystem is setup + * + * @return \OC\User\User + */ + public function getUser() { + return $this->user; + } + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback) { + $this->emitter->listen($scope, $method, $callback); + } + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, $callback = null) { + $this->emitter->removeListener($scope, $method, $callback); + } + + /** + * @param string $scope + * @param string $method + * @param array $arguments + */ + public function emit($scope, $method, $arguments = array()) { + $this->emitter->emit($scope, $method, $arguments); + } + + /** + * @param \OC\Files\Storage\Storage $storage + * @param string $mountPoint + * @param array $arguments + */ + public function mount($storage, $mountPoint, $arguments = array()) { + $mount = new Mount($storage, $mountPoint, $arguments); + $this->mountManager->addMount($mount); + } + + /** + * @param string $mountPoint + * @return \OC\Files\Mount\Mount + */ + public function getMount($mountPoint) { + return $this->mountManager->find($mountPoint); + } + + /** + * @param string $mountPoint + * @return \OC\Files\Mount\Mount[] + */ + public function getMountsIn($mountPoint) { + return $this->mountManager->findIn($mountPoint); + } + + /** + * @param string $storageId + * @return \OC\Files\Mount\Mount[] + */ + public function getMountByStorageId($storageId) { + return $this->mountManager->findByStorageId($storageId); + } + + /** + * @param int $numericId + * @return Mount[] + */ + public function getMountByNumericStorageId($numericId) { + return $this->mountManager->findByNumericId($numericId); + } + + /** + * @param \OC\Files\Mount\Mount $mount + */ + public function unMount($mount) { + $this->mountManager->remove($mount); + } + + /** + * @param string $path + * @throws \OCP\Files\NotFoundException + * @throws \OCP\Files\NotPermittedException + * @return Node + */ + public function get($path) { + $path = $this->normalizePath($path); + if ($this->isValidPath($path)) { + $fullPath = $this->getFullPath($path); + if ($this->view->file_exists($fullPath)) { + return $this->createNode($fullPath); + } else { + throw new NotFoundException(); + } + } else { + throw new NotPermittedException(); + } + } + + /** + * search file by id + * + * An array is returned because in the case where a single storage is mounted in different places the same file + * can exist in different places + * + * @param int $id + * @throws \OCP\Files\NotFoundException + * @return Node[] + */ + public function getById($id) { + $result = Cache::getById($id); + if (is_null($result)) { + throw new NotFoundException(); + } else { + list($storageId, $internalPath) = $result; + $nodes = array(); + $mounts = $this->mountManager->findByStorageId($storageId); + foreach ($mounts as $mount) { + $nodes[] = $this->get($mount->getMountPoint() . $internalPath); + } + return $nodes; + } + + } + + //most operations cant be done on the root + + /** + * @param string $targetPath + * @throws \OCP\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function rename($targetPath) { + throw new NotPermittedException(); + } + + public function delete() { + throw new NotPermittedException(); + } + + /** + * @param string $targetPath + * @throws \OCP\Files\NotPermittedException + * @return \OC\Files\Node\Node + */ + public function copy($targetPath) { + throw new NotPermittedException(); + } + + /** + * @param int $mtime + * @throws \OCP\Files\NotPermittedException + */ + public function touch($mtime = null) { + throw new NotPermittedException(); + } + + /** + * @return \OC\Files\Storage\Storage + * @throws \OCP\Files\NotFoundException + */ + public function getStorage() { + throw new NotFoundException(); + } + + /** + * @return string + */ + public function getPath() { + return '/'; + } + + /** + * @return string + */ + public function getInternalPath() { + return ''; + } + + /** + * @return int + */ + public function getId() { + return null; + } + + /** + * @return array + */ + public function stat() { + return null; + } + + /** + * @return int + */ + public function getMTime() { + return null; + } + + /** + * @return int + */ + public function getSize() { + return null; + } + + /** + * @return string + */ + public function getEtag() { + return null; + } + + /** + * @return int + */ + public function getPermissions() { + return \OCP\PERMISSION_CREATE; + } + + /** + * @return bool + */ + public function isReadable() { + return false; + } + + /** + * @return bool + */ + public function isUpdateable() { + return false; + } + + /** + * @return bool + */ + public function isDeletable() { + return false; + } + + /** + * @return bool + */ + public function isShareable() { + return false; + } + + /** + * @return Node + * @throws \OCP\Files\NotFoundException + */ + public function getParent() { + throw new NotFoundException(); + } + + /** + * @return string + */ + public function getName() { + return ''; + } +} diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php new file mode 100644 index 00000000000..a5b79f0e967 --- /dev/null +++ b/lib/private/files/storage/common.php @@ -0,0 +1,374 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +/** + * Storage backend class for providing common filesystem operation methods + * which are not storage-backend specific. + * + * \OC\Files\Storage\Common is never used directly; it is extended by all other + * storage backends, where its methods may be overridden, and additional + * (backend-specific) methods are defined. + * + * Some \OC\Files\Storage\Common methods call functions which are first defined + * in classes which extend it, e.g. $this->stat() . + */ + +abstract class Common implements \OC\Files\Storage\Storage { + private $cache; + private $scanner; + private $permissioncache; + private $watcher; + private $storageCache; + + public function __construct($parameters) { + } + + public function is_dir($path) { + return $this->filetype($path) == 'dir'; + } + + public function is_file($path) { + return $this->filetype($path) == 'file'; + } + + public function filesize($path) { + if ($this->is_dir($path)) { + return 0; //by definition + } else { + $stat = $this->stat($path); + if (isset($stat['size'])) { + return $stat['size']; + } else { + return 0; + } + } + } + + public function isCreatable($path) { + if ($this->is_dir($path) && $this->isUpdatable($path)) { + return true; + } + return false; + } + + public function isDeletable($path) { + return $this->isUpdatable($path); + } + + public function isSharable($path) { + return $this->isReadable($path); + } + + public function getPermissions($path) { + $permissions = 0; + if ($this->isCreatable($path)) { + $permissions |= \OCP\PERMISSION_CREATE; + } + if ($this->isReadable($path)) { + $permissions |= \OCP\PERMISSION_READ; + } + if ($this->isUpdatable($path)) { + $permissions |= \OCP\PERMISSION_UPDATE; + } + if ($this->isDeletable($path)) { + $permissions |= \OCP\PERMISSION_DELETE; + } + if ($this->isSharable($path)) { + $permissions |= \OCP\PERMISSION_SHARE; + } + return $permissions; + } + + public function filemtime($path) { + $stat = $this->stat($path); + if (isset($stat['mtime'])) { + return $stat['mtime']; + } else { + return 0; + } + } + + public function file_get_contents($path) { + $handle = $this->fopen($path, "r"); + if (!$handle) { + return false; + } + $size = $this->filesize($path); + if ($size == 0) { + return ''; + } + return fread($handle, $size); + } + + public function file_put_contents($path, $data) { + $handle = $this->fopen($path, "w"); + return fwrite($handle, $data); + } + + public function rename($path1, $path2) { + if ($this->copy($path1, $path2)) { + return $this->unlink($path1); + } else { + return false; + } + } + + public function copy($path1, $path2) { + $source = $this->fopen($path1, 'r'); + $target = $this->fopen($path2, 'w'); + list($count, $result) = \OC_Helper::streamCopy($source, $target); + return $result; + } + + /** + * @brief Deletes all files and folders recursively within a directory + * @param string $directory The directory whose contents will be deleted + * @param bool $empty Flag indicating whether directory will be emptied + * @returns bool + * + * @note By default the directory specified by $directory will be + * deleted together with its contents. To avoid this set $empty to true + */ + public function deleteAll($directory, $empty = false) { + $directory = trim($directory, '/'); + if (!$this->is_dir($directory) || !$this->isReadable($directory)) { + return false; + } else { + $directoryHandle = $this->opendir($directory); + if(is_resource($directoryHandle)) { + while (($contents = readdir($directoryHandle)) !== false) { + if (!\OC\Files\Filesystem::isIgnoredDir($contents)) { + $path = $directory . '/' . $contents; + if ($this->is_dir($path)) { + $this->deleteAll($path); + } else { + $this->unlink($path); + } + } + } + } + if ($empty === false) { + if (!$this->rmdir($directory)) { + return false; + } + } + return true; + } + + } + + public function getMimeType($path) { + if (!$this->file_exists($path)) { + return false; + } + if ($this->is_dir($path)) { + return 'httpd/unix-directory'; + } + $source = $this->fopen($path, 'r'); + if (!$source) { + return false; + } + $head = fread($source, 8192); //8kb should suffice to determine a mimetype + if ($pos = strrpos($path, '.')) { + $extension = substr($path, $pos); + } else { + $extension = ''; + } + $tmpFile = \OC_Helper::tmpFile($extension); + file_put_contents($tmpFile, $head); + $mime = \OC_Helper::getMimeType($tmpFile); + unlink($tmpFile); + return $mime; + } + + public function hash($type, $path, $raw = false) { + $tmpFile = $this->getLocalFile($path); + $hash = hash($type, $tmpFile, $raw); + unlink($tmpFile); + return $hash; + } + + public function search($query) { + return $this->searchInDir($query); + } + + public function getLocalFile($path) { + return $this->toTmpFile($path); + } + + private function toTmpFile($path) { //no longer in the storage api, still useful here + $source = $this->fopen($path, 'r'); + if (!$source) { + return false; + } + if ($pos = strrpos($path, '.')) { + $extension = substr($path, $pos); + } else { + $extension = ''; + } + $tmpFile = \OC_Helper::tmpFile($extension); + $target = fopen($tmpFile, 'w'); + \OC_Helper::streamCopy($source, $target); + return $tmpFile; + } + + public function getLocalFolder($path) { + $baseDir = \OC_Helper::tmpFolder(); + $this->addLocalFolder($path, $baseDir); + return $baseDir; + } + + private function addLocalFolder($path, $target) { + $dh = $this->opendir($path); + if(is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if ($file !== '.' and $file !== '..') { + if ($this->is_dir($path . '/' . $file)) { + mkdir($target . '/' . $file); + $this->addLocalFolder($path . '/' . $file, $target . '/' . $file); + } else { + $tmp = $this->toTmpFile($path . '/' . $file); + rename($tmp, $target . '/' . $file); + } + } + } + } + } + + protected function searchInDir($query, $dir = '') { + $files = array(); + $dh = $this->opendir($dir); + if (is_resource($dh)) { + while (($item = readdir($dh)) !== false) { + if ($item == '.' || $item == '..') continue; + if (strstr(strtolower($item), strtolower($query)) !== false) { + $files[] = $dir . '/' . $item; + } + if ($this->is_dir($dir . '/' . $item)) { + $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); + } + } + } + return $files; + } + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + */ + public function hasUpdated($path, $time) { + return $this->filemtime($path) > $time; + } + + public function getCache($path = '') { + if (!isset($this->cache)) { + $this->cache = new \OC\Files\Cache\Cache($this); + } + return $this->cache; + } + + public function getScanner($path = '') { + if (!isset($this->scanner)) { + $this->scanner = new \OC\Files\Cache\Scanner($this); + } + return $this->scanner; + } + + public function getPermissionsCache($path = '') { + if (!isset($this->permissioncache)) { + $this->permissioncache = new \OC\Files\Cache\Permissions($this); + } + return $this->permissioncache; + } + + public function getWatcher($path = '') { + if (!isset($this->watcher)) { + $this->watcher = new \OC\Files\Cache\Watcher($this); + } + return $this->watcher; + } + + public function getStorageCache(){ + if (!isset($this->storageCache)) { + $this->storageCache = new \OC\Files\Cache\Storage($this); + } + return $this->storageCache; + } + + /** + * get the owner of a path + * + * @param string $path The path to get the owner + * @return string uid or false + */ + public function getOwner($path) { + return \OC_User::getUser(); + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path) { + $ETagFunction = \OC_Connector_Sabre_Node::$ETagFunction; + if ($ETagFunction) { + $hash = call_user_func($ETagFunction, $path); + return $hash; + } else { + return uniqid(); + } + } + + /** + * clean a path, i.e. remove all redundant '.' and '..' + * making sure that it can't point to higher than '/' + * + * @param $path The path to clean + * @return string cleaned path + */ + public function cleanPath($path) { + if (strlen($path) == 0 or $path[0] != '/') { + $path = '/' . $path; + } + + $output = array(); + foreach (explode('/', $path) as $chunk) { + if ($chunk == '..') { + array_pop($output); + } else if ($chunk == '.') { + } else { + $output[] = $chunk; + } + } + return implode('/', $output); + } + + public function test() { + if ($this->stat('')) { + return true; + } + return false; + } + + /** + * get the free space in the storage + * + * @param $path + * @return int + */ + public function free_space($path) { + return \OC\Files\SPACE_UNKNOWN; + } +} diff --git a/lib/private/files/storage/commontest.php b/lib/private/files/storage/commontest.php new file mode 100644 index 00000000000..c3f1eb31955 --- /dev/null +++ b/lib/private/files/storage/commontest.php @@ -0,0 +1,80 @@ +. +* +*/ + +/** + * test implementation for \OC\Files\Storage\Common with \OC\Files\Storage\Local + */ + +namespace OC\Files\Storage; + +class CommonTest extends \OC\Files\Storage\Common{ + /** + * underlying local storage used for missing functions + * @var \OC\Files\Storage\Local + */ + private $storage; + + public function __construct($params) { + $this->storage=new \OC\Files\Storage\Local($params); + } + + public function getId(){ + return 'test::'.$this->storage->getId(); + } + public function mkdir($path) { + return $this->storage->mkdir($path); + } + public function rmdir($path) { + return $this->storage->rmdir($path); + } + public function opendir($path) { + return $this->storage->opendir($path); + } + public function stat($path) { + return $this->storage->stat($path); + } + public function filetype($path) { + return $this->storage->filetype($path); + } + public function isReadable($path) { + return $this->storage->isReadable($path); + } + public function isUpdatable($path) { + return $this->storage->isUpdatable($path); + } + public function file_exists($path) { + return $this->storage->file_exists($path); + } + public function unlink($path) { + return $this->storage->unlink($path); + } + public function fopen($path, $mode) { + return $this->storage->fopen($path, $mode); + } + public function free_space($path) { + return $this->storage->free_space($path); + } + public function touch($path, $mtime=null) { + return $this->storage->touch($path, $mtime); + } +} diff --git a/lib/private/files/storage/loader.php b/lib/private/files/storage/loader.php new file mode 100644 index 00000000000..2572ef443bc --- /dev/null +++ b/lib/private/files/storage/loader.php @@ -0,0 +1,38 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +class Loader { + /** + * @var callable[] $storageWrappers + */ + private $storageWrappers = array(); + + /** + * allow modifier storage behaviour by adding wrappers around storages + * + * $callback should be a function of type (string $mountPoint, Storage $storage) => Storage + * + * @param callable $callback + */ + public function addStorageWrapper($callback) { + $this->storageWrappers[] = $callback; + } + + public function load($mountPoint, $class, $arguments) { + return $this->wrap($mountPoint, new $class($arguments)); + } + + public function wrap($mountPoint, $storage) { + foreach ($this->storageWrappers as $wrapper) { + $storage = $wrapper($mountPoint, $storage); + } + return $storage; + } +} diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php new file mode 100644 index 00000000000..5209fabc30a --- /dev/null +++ b/lib/private/files/storage/local.php @@ -0,0 +1,310 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +if (\OC_Util::runningOnWindows()) { + class Local extends MappedLocal { + + } +} else { + + /** + * for local filestore, we only have to map the paths + */ + class Local extends \OC\Files\Storage\Common { + protected $datadir; + + public function __construct($arguments) { + $this->datadir = $arguments['datadir']; + if (substr($this->datadir, -1) !== '/') { + $this->datadir .= '/'; + } + } + + public function __destruct() { + } + + public function getId() { + return 'local::' . $this->datadir; + } + + public function mkdir($path) { + return @mkdir($this->datadir . $path); + } + + public function rmdir($path) { + try { + $it = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($this->datadir . $path), + \RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($it as $file) { + /** + * @var \SplFileInfo $file + */ + if (in_array($file->getBasename(), array('.', '..'))) { + continue; + } elseif ($file->isDir()) { + rmdir($file->getPathname()); + } elseif ($file->isFile() || $file->isLink()) { + unlink($file->getPathname()); + } + } + return rmdir($this->datadir . $path); + } catch (\UnexpectedValueException $e) { + return false; + } + } + + public function opendir($path) { + return opendir($this->datadir . $path); + } + + public function is_dir($path) { + if (substr($path, -1) == '/') { + $path = substr($path, 0, -1); + } + return is_dir($this->datadir . $path); + } + + public function is_file($path) { + return is_file($this->datadir . $path); + } + + public function stat($path) { + $fullPath = $this->datadir . $path; + $statResult = stat($fullPath); + + if ($statResult['size'] < 0) { + $size = self::getFileSizeFromOS($fullPath); + $statResult['size'] = $size; + $statResult[7] = $size; + } + return $statResult; + } + + public function filetype($path) { + $filetype = filetype($this->datadir . $path); + if ($filetype == 'link') { + $filetype = filetype(realpath($this->datadir . $path)); + } + return $filetype; + } + + public function filesize($path) { + if ($this->is_dir($path)) { + return 0; + } else { + $fullPath = $this->datadir . $path; + $fileSize = filesize($fullPath); + if ($fileSize < 0) { + return self::getFileSizeFromOS($fullPath); + } + + return $fileSize; + } + } + + public function isReadable($path) { + return is_readable($this->datadir . $path); + } + + public function isUpdatable($path) { + return is_writable($this->datadir . $path); + } + + public function file_exists($path) { + return file_exists($this->datadir . $path); + } + + public function filemtime($path) { + return filemtime($this->datadir . $path); + } + + public function touch($path, $mtime = null) { + // sets the modification time of the file to the given value. + // If mtime is nil the current time is set. + // note that the access time of the file always changes to the current time. + if ($this->file_exists($path) and !$this->isUpdatable($path)) { + return false; + } + if (!is_null($mtime)) { + $result = touch($this->datadir . $path, $mtime); + } else { + $result = touch($this->datadir . $path); + } + if ($result) { + clearstatcache(true, $this->datadir . $path); + } + + return $result; + } + + public function file_get_contents($path) { + return file_get_contents($this->datadir . $path); + } + + public function file_put_contents($path, $data) { //trigger_error("$path = ".var_export($path, 1)); + return file_put_contents($this->datadir . $path, $data); + } + + public function unlink($path) { + return $this->delTree($path); + } + + public function rename($path1, $path2) { + if (!$this->isUpdatable($path1)) { + \OC_Log::write('core', 'unable to rename, file is not writable : ' . $path1, \OC_Log::ERROR); + return false; + } + if (!$this->file_exists($path1)) { + \OC_Log::write('core', 'unable to rename, file does not exists : ' . $path1, \OC_Log::ERROR); + return false; + } + + if ($return = rename($this->datadir . $path1, $this->datadir . $path2)) { + } + return $return; + } + + public function copy($path1, $path2) { + if ($this->is_dir($path2)) { + if (!$this->file_exists($path2)) { + $this->mkdir($path2); + } + $source = substr($path1, strrpos($path1, '/') + 1); + $path2 .= $source; + } + return copy($this->datadir . $path1, $this->datadir . $path2); + } + + public function fopen($path, $mode) { + if ($return = fopen($this->datadir . $path, $mode)) { + switch ($mode) { + case 'r': + break; + case 'r+': + case 'w+': + case 'x+': + case 'a+': + break; + case 'w': + case 'x': + case 'a': + break; + } + } + return $return; + } + + public function getMimeType($path) { + if ($this->isReadable($path)) { + return \OC_Helper::getMimeType($this->datadir . $path); + } else { + return false; + } + } + + private function delTree($dir) { + $dirRelative = $dir; + $dir = $this->datadir . $dir; + if (!file_exists($dir)) return true; + if (!is_dir($dir) || is_link($dir)) return unlink($dir); + foreach (scandir($dir) as $item) { + if ($item == '.' || $item == '..') continue; + if (is_file($dir . '/' . $item)) { + if (unlink($dir . '/' . $item)) { + } + } elseif (is_dir($dir . '/' . $item)) { + if (!$this->delTree($dirRelative . "/" . $item)) { + return false; + }; + } + } + if ($return = rmdir($dir)) { + } + return $return; + } + + private static function getFileSizeFromOS($fullPath) { + $name = strtolower(php_uname('s')); + // Windows OS: we use COM to access the filesystem + if (strpos($name, 'win') !== false) { + if (class_exists('COM')) { + $fsobj = new \COM("Scripting.FileSystemObject"); + $f = $fsobj->GetFile($fullPath); + return $f->Size; + } + } else if (strpos($name, 'bsd') !== false) { + if (\OC_Helper::is_function_enabled('exec')) { + return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); + } + } else if (strpos($name, 'linux') !== false) { + if (\OC_Helper::is_function_enabled('exec')) { + return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); + } + } else { + \OC_Log::write('core', + 'Unable to determine file size of "' . $fullPath . '". Unknown OS: ' . $name, + \OC_Log::ERROR); + } + + return 0; + } + + public function hash($path, $type, $raw = false) { + return hash_file($type, $this->datadir . $path, $raw); + } + + public function free_space($path) { + $space = @disk_free_space($this->datadir . $path); + if ($space === false) { + return \OC\Files\SPACE_UNKNOWN; + } + return $space; + } + + public function search($query) { + return $this->searchInDir($query); + } + + public function getLocalFile($path) { + return $this->datadir . $path; + } + + public function getLocalFolder($path) { + return $this->datadir . $path; + } + + protected function searchInDir($query, $dir = '') { + $files = array(); + foreach (scandir($this->datadir . $dir) as $item) { + if ($item == '.' || $item == '..') continue; + if (strstr(strtolower($item), strtolower($query)) !== false) { + $files[] = $dir . '/' . $item; + } + if (is_dir($this->datadir . $dir . '/' . $item)) { + $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); + } + } + return $files; + } + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + */ + public function hasUpdated($path, $time) { + return $this->filemtime($path) > $time; + } + } +} diff --git a/lib/private/files/storage/mappedlocal.php b/lib/private/files/storage/mappedlocal.php new file mode 100644 index 00000000000..ba5ac4191c5 --- /dev/null +++ b/lib/private/files/storage/mappedlocal.php @@ -0,0 +1,365 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Files\Storage; + +/** + * for local filestore, we only have to map the paths + */ +class MappedLocal extends \OC\Files\Storage\Common{ + protected $datadir; + private $mapper; + + public function __construct($arguments) { + $this->datadir=$arguments['datadir']; + if(substr($this->datadir, -1)!=='/') { + $this->datadir.='/'; + } + + $this->mapper= new \OC\Files\Mapper($this->datadir); + } + public function __destruct() { + if (defined('PHPUNIT_RUN')) { + $this->mapper->removePath($this->datadir, true, true); + } + } + public function getId(){ + return 'local::'.$this->datadir; + } + public function mkdir($path) { + return @mkdir($this->buildPath($path)); + } + public function rmdir($path) { + try { + $it = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($this->buildPath($path)), + \RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($it as $file) { + /** + * @var \SplFileInfo $file + */ + if (in_array($file->getBasename(), array('.', '..'))) { + continue; + } elseif ($file->isDir()) { + rmdir($file->getPathname()); + } elseif ($file->isFile() || $file->isLink()) { + unlink($file->getPathname()); + } + } + if ($result = @rmdir($this->buildPath($path))) { + $this->cleanMapper($path); + } + return $result; + } catch (\UnexpectedValueException $e) { + return false; + } + } + public function opendir($path) { + $files = array('.', '..'); + $physicalPath= $this->buildPath($path); + + $logicalPath = $this->mapper->physicalToLogic($physicalPath); + $dh = opendir($physicalPath); + if(is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if ($file === '.' or $file === '..') { + continue; + } + + $logicalFilePath = $this->mapper->physicalToLogic($physicalPath.'/'.$file); + + $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath); + $file = $this->stripLeading($file); + $files[]= $file; + } + } + + \OC\Files\Stream\Dir::register('local-win32'.$path, $files); + return opendir('fakedir://local-win32'.$path); + } + public function is_dir($path) { + if(substr($path, -1)=='/') { + $path=substr($path, 0, -1); + } + return is_dir($this->buildPath($path)); + } + public function is_file($path) { + return is_file($this->buildPath($path)); + } + public function stat($path) { + $fullPath = $this->buildPath($path); + $statResult = stat($fullPath); + + if ($statResult['size'] < 0) { + $size = self::getFileSizeFromOS($fullPath); + $statResult['size'] = $size; + $statResult[7] = $size; + } + return $statResult; + } + public function filetype($path) { + $filetype=filetype($this->buildPath($path)); + if($filetype=='link') { + $filetype=filetype(realpath($this->buildPath($path))); + } + return $filetype; + } + public function filesize($path) { + if($this->is_dir($path)) { + return 0; + }else{ + $fullPath = $this->buildPath($path); + $fileSize = filesize($fullPath); + if ($fileSize < 0) { + return self::getFileSizeFromOS($fullPath); + } + + return $fileSize; + } + } + public function isReadable($path) { + return is_readable($this->buildPath($path)); + } + public function isUpdatable($path) { + return is_writable($this->buildPath($path)); + } + public function file_exists($path) { + return file_exists($this->buildPath($path)); + } + public function filemtime($path) { + return filemtime($this->buildPath($path)); + } + public function touch($path, $mtime=null) { + // sets the modification time of the file to the given value. + // If mtime is nil the current time is set. + // note that the access time of the file always changes to the current time. + if(!is_null($mtime)) { + $result=touch( $this->buildPath($path), $mtime ); + }else{ + $result=touch( $this->buildPath($path)); + } + if( $result ) { + clearstatcache( true, $this->buildPath($path) ); + } + + return $result; + } + public function file_get_contents($path) { + return file_get_contents($this->buildPath($path)); + } + public function file_put_contents($path, $data) { + return file_put_contents($this->buildPath($path), $data); + } + public function unlink($path) { + return $this->delTree($path); + } + public function rename($path1, $path2) { + if (!$this->isUpdatable($path1)) { + \OC_Log::write('core', 'unable to rename, file is not writable : '.$path1, \OC_Log::ERROR); + return false; + } + if(! $this->file_exists($path1)) { + \OC_Log::write('core', 'unable to rename, file does not exists : '.$path1, \OC_Log::ERROR); + return false; + } + + $physicPath1 = $this->buildPath($path1); + $physicPath2 = $this->buildPath($path2); + if($return=rename($physicPath1, $physicPath2)) { + // mapper needs to create copies or all children + $this->copyMapping($path1, $path2); + $this->cleanMapper($physicPath1, false, true); + } + return $return; + } + public function copy($path1, $path2) { + if($this->is_dir($path2)) { + if(!$this->file_exists($path2)) { + $this->mkdir($path2); + } + $source=substr($path1, strrpos($path1, '/')+1); + $path2.=$source; + } + if($return=copy($this->buildPath($path1), $this->buildPath($path2))) { + // mapper needs to create copies or all children + $this->copyMapping($path1, $path2); + } + return $return; + } + public function fopen($path, $mode) { + if($return=fopen($this->buildPath($path), $mode)) { + switch($mode) { + case 'r': + break; + case 'r+': + case 'w+': + case 'x+': + case 'a+': + break; + case 'w': + case 'x': + case 'a': + break; + } + } + return $return; + } + + public function getMimeType($path) { + if($this->isReadable($path)) { + return \OC_Helper::getMimeType($this->buildPath($path)); + }else{ + return false; + } + } + + private function delTree($dir, $isLogicPath=true) { + $dirRelative=$dir; + if ($isLogicPath) { + $dir=$this->buildPath($dir); + } + if (!file_exists($dir)) { + return true; + } + if (!is_dir($dir) || is_link($dir)) { + if($return=unlink($dir)) { + $this->cleanMapper($dir, false); + return $return; + } + } + foreach (scandir($dir) as $item) { + if ($item == '.' || $item == '..') { + continue; + } + if(is_file($dir.'/'.$item)) { + if(unlink($dir.'/'.$item)) { + $this->cleanMapper($dir.'/'.$item, false); + } + }elseif(is_dir($dir.'/'.$item)) { + if (!$this->delTree($dir. "/" . $item, false)) { + return false; + }; + } + } + if($return=rmdir($dir)) { + $this->cleanMapper($dir, false); + } + return $return; + } + + private static function getFileSizeFromOS($fullPath) { + $name = strtolower(php_uname('s')); + // Windows OS: we use COM to access the filesystem + if (strpos($name, 'win') !== false) { + if (class_exists('COM')) { + $fsobj = new \COM("Scripting.FileSystemObject"); + $f = $fsobj->GetFile($fullPath); + return $f->Size; + } + } else if (strpos($name, 'bsd') !== false) { + if (\OC_Helper::is_function_enabled('exec')) { + return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); + } + } else if (strpos($name, 'linux') !== false) { + if (\OC_Helper::is_function_enabled('exec')) { + return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); + } + } else { + \OC_Log::write('core', + 'Unable to determine file size of "'.$fullPath.'". Unknown OS: '.$name, + \OC_Log::ERROR); + } + + return 0; + } + + public function hash($path, $type, $raw=false) { + return hash_file($type, $this->buildPath($path), $raw); + } + + public function free_space($path) { + return @disk_free_space($this->buildPath($path)); + } + + public function search($query) { + return $this->searchInDir($query); + } + public function getLocalFile($path) { + return $this->buildPath($path); + } + public function getLocalFolder($path) { + return $this->buildPath($path); + } + + protected function searchInDir($query, $dir='') { + $files=array(); + $physicalDir = $this->buildPath($dir); + foreach (scandir($physicalDir) as $item) { + if ($item == '.' || $item == '..') + continue; + $physicalItem = $this->mapper->physicalToLogic($physicalDir.'/'.$item); + $item = substr($physicalItem, strlen($physicalDir)+1); + + if(strstr(strtolower($item), strtolower($query)) !== false) { + $files[]=$dir.'/'.$item; + } + if(is_dir($physicalItem)) { + $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item)); + } + } + return $files; + } + + /** + * check if a file or folder has been updated since $time + * @param string $path + * @param int $time + * @return bool + */ + public function hasUpdated($path, $time) { + return $this->filemtime($path)>$time; + } + + private function buildPath($path, $create=true) { + $path = $this->stripLeading($path); + $fullPath = $this->datadir.$path; + return $this->mapper->logicToPhysical($fullPath, $create); + } + + private function cleanMapper($path, $isLogicPath=true, $recursive=true) { + $fullPath = $path; + if ($isLogicPath) { + $fullPath = $this->datadir.$path; + } + $this->mapper->removePath($fullPath, $isLogicPath, $recursive); + } + + private function copyMapping($path1, $path2) { + $path1 = $this->stripLeading($path1); + $path2 = $this->stripLeading($path2); + + $fullPath1 = $this->datadir.$path1; + $fullPath2 = $this->datadir.$path2; + + $this->mapper->copy($fullPath1, $fullPath2); + } + + private function stripLeading($path) { + if(strpos($path, '/') === 0) { + $path = substr($path, 1); + } + if(strpos($path, '\\') === 0) { + $path = substr($path, 1); + } + if ($path === false) { + return ''; + } + + return $path; + } +} diff --git a/lib/private/files/storage/storage.php b/lib/private/files/storage/storage.php new file mode 100644 index 00000000000..b673bb9a32d --- /dev/null +++ b/lib/private/files/storage/storage.php @@ -0,0 +1,343 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +/** + * Provide a common interface to all different storage options + * + * All paths passed to the storage are relative to the storage and should NOT have a leading slash. + */ +interface Storage extends \OCP\Files\Storage { + /** + * $parameters is a free form array with the configuration options needed to construct the storage + * + * @param array $parameters + */ + public function __construct($parameters); + + /** + * Get the identifier for the storage, + * the returned id should be the same for every storage object that is created with the same parameters + * and two storage objects with the same id should refer to two storages that display the same files. + * + * @return string + */ + public function getId(); + + /** + * see http://php.net/manual/en/function.mkdir.php + * + * @param string $path + * @return bool + */ + public function mkdir($path); + + /** + * see http://php.net/manual/en/function.rmdir.php + * + * @param string $path + * @return bool + */ + public function rmdir($path); + + /** + * see http://php.net/manual/en/function.opendir.php + * + * @param string $path + * @return resource + */ + public function opendir($path); + + /** + * see http://php.net/manual/en/function.is_dir.php + * + * @param string $path + * @return bool + */ + public function is_dir($path); + + /** + * see http://php.net/manual/en/function.is_file.php + * + * @param string $path + * @return bool + */ + public function is_file($path); + + /** + * see http://php.net/manual/en/function.stat.php + * only the following keys are required in the result: size and mtime + * + * @param string $path + * @return array + */ + public function stat($path); + + /** + * see http://php.net/manual/en/function.filetype.php + * + * @param string $path + * @return bool + */ + public function filetype($path); + + /** + * see http://php.net/manual/en/function.filesize.php + * The result for filesize when called on a folder is required to be 0 + * + * @param string $path + * @return int + */ + public function filesize($path); + + /** + * check if a file can be created in $path + * + * @param string $path + * @return bool + */ + public function isCreatable($path); + + /** + * check if a file can be read + * + * @param string $path + * @return bool + */ + public function isReadable($path); + + /** + * check if a file can be written to + * + * @param string $path + * @return bool + */ + public function isUpdatable($path); + + /** + * check if a file can be deleted + * + * @param string $path + * @return bool + */ + public function isDeletable($path); + + /** + * check if a file can be shared + * + * @param string $path + * @return bool + */ + public function isSharable($path); + + /** + * get the full permissions of a path. + * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php + * + * @param string $path + * @return int + */ + public function getPermissions($path); + + /** + * see http://php.net/manual/en/function.file_exists.php + * + * @param string $path + * @return bool + */ + public function file_exists($path); + + /** + * see http://php.net/manual/en/function.filemtime.php + * + * @param string $path + * @return int + */ + public function filemtime($path); + + /** + * see http://php.net/manual/en/function.file_get_contents.php + * + * @param string $path + * @return string + */ + public function file_get_contents($path); + + /** + * see http://php.net/manual/en/function.file_put_contents.php + * + * @param string $path + * @param string $data + * @return bool + */ + public function file_put_contents($path, $data); + + /** + * see http://php.net/manual/en/function.unlink.php + * + * @param string $path + * @return bool + */ + public function unlink($path); + + /** + * see http://php.net/manual/en/function.rename.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function rename($path1, $path2); + + /** + * see http://php.net/manual/en/function.copy.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function copy($path1, $path2); + + /** + * see http://php.net/manual/en/function.fopen.php + * + * @param string $path + * @param string $mode + * @return resource + */ + public function fopen($path, $mode); + + /** + * get the mimetype for a file or folder + * The mimetype for a folder is required to be "httpd/unix-directory" + * + * @param string $path + * @return string + */ + public function getMimeType($path); + + /** + * see http://php.net/manual/en/function.hash.php + * + * @param string $type + * @param string $path + * @param bool $raw + * @return string + */ + public function hash($type, $path, $raw = false); + + /** + * see http://php.net/manual/en/function.free_space.php + * + * @param string $path + * @return int + */ + public function free_space($path); + + /** + * search for occurrences of $query in file names + * + * @param string $query + * @return array + */ + public function search($query); + + /** + * see http://php.net/manual/en/function.touch.php + * If the backend does not support the operation, false should be returned + * + * @param string $path + * @param int $mtime + * @return bool + */ + public function touch($path, $mtime = null); + + /** + * get the path to a local version of the file. + * The local version of the file can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFile($path); + + /** + * get the path to a local version of the folder. + * The local version of the folder can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFolder($path); + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + public function hasUpdated($path, $time); + + /** + * get a cache instance for the storage + * + * @param string $path + * @return \OC\Files\Cache\Cache + */ + public function getCache($path = ''); + + /** + * get a scanner instance for the storage + * + * @param string $path + * @return \OC\Files\Cache\Scanner + */ + public function getScanner($path = ''); + + + /** + * get the user id of the owner of a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path); + + /** + * get a permissions cache instance for the cache + * + * @param string $path + * @return \OC\Files\Cache\Permissions + */ + public function getPermissionsCache($path = ''); + + /** + * get a watcher instance for the cache + * + * @param string $path + * @return \OC\Files\Cache\Watcher + */ + public function getWatcher($path = ''); + + /** + * @return \OC\Files\Cache\Storage + */ + public function getStorageCache(); + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path); +} diff --git a/lib/private/files/storage/temporary.php b/lib/private/files/storage/temporary.php new file mode 100644 index 00000000000..d84dbda2e39 --- /dev/null +++ b/lib/private/files/storage/temporary.php @@ -0,0 +1,27 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +/** + * local storage backend in temporary folder for testing purpose + */ +class Temporary extends Local{ + public function __construct($arguments) { + parent::__construct(array('datadir' => \OC_Helper::tmpFolder())); + } + + public function cleanUp() { + \OC_Helper::rmdirr($this->datadir); + } + + public function __destruct() { + parent::__destruct(); + $this->cleanUp(); + } +} diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php new file mode 100644 index 00000000000..e2da8cf2e05 --- /dev/null +++ b/lib/private/files/storage/wrapper/quota.php @@ -0,0 +1,104 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage\Wrapper; + +class Quota extends Wrapper { + + /** + * @var int $quota + */ + protected $quota; + + /** + * @param array $parameters + */ + public function __construct($parameters) { + $this->storage = $parameters['storage']; + $this->quota = $parameters['quota']; + } + + protected function getSize($path) { + $cache = $this->getCache(); + $data = $cache->get($path); + if (is_array($data) and isset($data['size'])) { + return $data['size']; + } else { + return \OC\Files\SPACE_NOT_COMPUTED; + } + } + + /** + * Get free space as limited by the quota + * + * @param string $path + * @return int + */ + public function free_space($path) { + if ($this->quota < 0) { + return $this->storage->free_space($path); + } else { + $used = $this->getSize(''); + if ($used < 0) { + return \OC\Files\SPACE_NOT_COMPUTED; + } else { + $free = $this->storage->free_space($path); + return min($free, (max($this->quota - $used, 0))); + } + } + } + + /** + * see http://php.net/manual/en/function.file_put_contents.php + * + * @param string $path + * @param string $data + * @return bool + */ + public function file_put_contents($path, $data) { + $free = $this->free_space(''); + if ($free < 0 or strlen($data) < $free) { + return $this->storage->file_put_contents($path, $data); + } else { + return false; + } + } + + /** + * see http://php.net/manual/en/function.copy.php + * + * @param string $source + * @param string $target + * @return bool + */ + public function copy($source, $target) { + $free = $this->free_space(''); + if ($free < 0 or $this->getSize($source) < $free) { + return $this->storage->copy($source, $target); + } else { + return false; + } + } + + /** + * see http://php.net/manual/en/function.fopen.php + * + * @param string $path + * @param string $mode + * @return resource + */ + public function fopen($path, $mode) { + $source = $this->storage->fopen($path, $mode); + $free = $this->free_space(''); + if ($free >= 0) { + return \OC\Files\Stream\Quota::wrap($source, $free); + } else { + return $source; + } + } +} diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php new file mode 100644 index 00000000000..0336c27efa1 --- /dev/null +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -0,0 +1,427 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage\Wrapper; + +class Wrapper implements \OC\Files\Storage\Storage { + /** + * @var \OC\Files\Storage\Storage $storage + */ + protected $storage; + + /** + * @param array $parameters + */ + public function __construct($parameters) { + $this->storage = $parameters['storage']; + } + + /** + * @return \OC\Files\Storage\Storage + */ + public function getWrapperStorage() { + return $this->storage; + } + + /** + * Get the identifier for the storage, + * the returned id should be the same for every storage object that is created with the same parameters + * and two storage objects with the same id should refer to two storages that display the same files. + * + * @return string + */ + public function getId() { + return $this->storage->getId(); + } + + /** + * see http://php.net/manual/en/function.mkdir.php + * + * @param string $path + * @return bool + */ + public function mkdir($path) { + return $this->storage->mkdir($path); + } + + /** + * see http://php.net/manual/en/function.rmdir.php + * + * @param string $path + * @return bool + */ + public function rmdir($path) { + return $this->storage->rmdir($path); + } + + /** + * see http://php.net/manual/en/function.opendir.php + * + * @param string $path + * @return resource + */ + public function opendir($path) { + return $this->storage->opendir($path); + } + + /** + * see http://php.net/manual/en/function.is_dir.php + * + * @param string $path + * @return bool + */ + public function is_dir($path) { + return $this->storage->is_dir($path); + } + + /** + * see http://php.net/manual/en/function.is_file.php + * + * @param string $path + * @return bool + */ + public function is_file($path) { + return $this->storage->is_file($path); + } + + /** + * see http://php.net/manual/en/function.stat.php + * only the following keys are required in the result: size and mtime + * + * @param string $path + * @return array + */ + public function stat($path) { + return $this->storage->stat($path); + } + + /** + * see http://php.net/manual/en/function.filetype.php + * + * @param string $path + * @return bool + */ + public function filetype($path) { + return $this->storage->filetype($path); + } + + /** + * see http://php.net/manual/en/function.filesize.php + * The result for filesize when called on a folder is required to be 0 + * + * @param string $path + * @return int + */ + public function filesize($path) { + return $this->storage->filesize($path); + } + + /** + * check if a file can be created in $path + * + * @param string $path + * @return bool + */ + public function isCreatable($path) { + return $this->storage->isCreatable($path); + } + + /** + * check if a file can be read + * + * @param string $path + * @return bool + */ + public function isReadable($path) { + return $this->storage->isReadable($path); + } + + /** + * check if a file can be written to + * + * @param string $path + * @return bool + */ + public function isUpdatable($path) { + return $this->storage->isUpdatable($path); + } + + /** + * check if a file can be deleted + * + * @param string $path + * @return bool + */ + public function isDeletable($path) { + return $this->storage->isDeletable($path); + } + + /** + * check if a file can be shared + * + * @param string $path + * @return bool + */ + public function isSharable($path) { + return $this->storage->isSharable($path); + } + + /** + * get the full permissions of a path. + * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php + * + * @param string $path + * @return int + */ + public function getPermissions($path) { + return $this->storage->getPermissions($path); + } + + /** + * see http://php.net/manual/en/function.file_exists.php + * + * @param string $path + * @return bool + */ + public function file_exists($path) { + return $this->storage->file_exists($path); + } + + /** + * see http://php.net/manual/en/function.filemtime.php + * + * @param string $path + * @return int + */ + public function filemtime($path) { + return $this->storage->filemtime($path); + } + + /** + * see http://php.net/manual/en/function.file_get_contents.php + * + * @param string $path + * @return string + */ + public function file_get_contents($path) { + return $this->storage->file_get_contents($path); + } + + /** + * see http://php.net/manual/en/function.file_put_contents.php + * + * @param string $path + * @param string $data + * @return bool + */ + public function file_put_contents($path, $data) { + return $this->storage->file_put_contents($path, $data); + } + + /** + * see http://php.net/manual/en/function.unlink.php + * + * @param string $path + * @return bool + */ + public function unlink($path) { + return $this->storage->unlink($path); + } + + /** + * see http://php.net/manual/en/function.rename.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function rename($path1, $path2) { + return $this->storage->rename($path1, $path2); + } + + /** + * see http://php.net/manual/en/function.copy.php + * + * @param string $path1 + * @param string $path2 + * @return bool + */ + public function copy($path1, $path2) { + return $this->storage->copy($path1, $path2); + } + + /** + * see http://php.net/manual/en/function.fopen.php + * + * @param string $path + * @param string $mode + * @return resource + */ + public function fopen($path, $mode) { + return $this->storage->fopen($path, $mode); + } + + /** + * get the mimetype for a file or folder + * The mimetype for a folder is required to be "httpd/unix-directory" + * + * @param string $path + * @return string + */ + public function getMimeType($path) { + return $this->storage->getMimeType($path); + } + + /** + * see http://php.net/manual/en/function.hash.php + * + * @param string $type + * @param string $path + * @param bool $raw + * @return string + */ + public function hash($type, $path, $raw = false) { + return $this->storage->hash($type, $path, $raw); + } + + /** + * see http://php.net/manual/en/function.free_space.php + * + * @param string $path + * @return int + */ + public function free_space($path) { + return $this->storage->free_space($path); + } + + /** + * search for occurrences of $query in file names + * + * @param string $query + * @return array + */ + public function search($query) { + return $this->storage->search($query); + } + + /** + * see http://php.net/manual/en/function.touch.php + * If the backend does not support the operation, false should be returned + * + * @param string $path + * @param int $mtime + * @return bool + */ + public function touch($path, $mtime = null) { + return $this->storage->touch($path, $mtime); + } + + /** + * get the path to a local version of the file. + * The local version of the file can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFile($path) { + return $this->storage->getLocalFile($path); + } + + /** + * get the path to a local version of the folder. + * The local version of the folder can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFolder($path) { + return $this->storage->getLocalFolder($path); + } + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + public function hasUpdated($path, $time) { + return $this->storage->hasUpdated($path, $time); + } + + /** + * get a cache instance for the storage + * + * @param string $path + * @return \OC\Files\Cache\Cache + */ + public function getCache($path = '') { + return $this->storage->getCache($path); + } + + /** + * get a scanner instance for the storage + * + * @param string $path + * @return \OC\Files\Cache\Scanner + */ + public function getScanner($path = '') { + return $this->storage->getScanner($path); + } + + + /** + * get the user id of the owner of a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path) { + return $this->storage->getOwner($path); + } + + /** + * get a permissions cache instance for the cache + * + * @param string $path + * @return \OC\Files\Cache\Permissions + */ + public function getPermissionsCache($path = '') { + return $this->storage->getPermissionsCache($path); + } + + /** + * get a watcher instance for the cache + * + * @param string $path + * @return \OC\Files\Cache\Watcher + */ + public function getWatcher($path = '') { + return $this->storage->getWatcher($path); + } + + /** + * @return \OC\Files\Cache\Storage + */ + public function getStorageCache() { + return $this->storage->getStorageCache(); + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path) { + return $this->storage->getETag($path); + } +} diff --git a/lib/private/files/stream/close.php b/lib/private/files/stream/close.php new file mode 100644 index 00000000000..80de3497c36 --- /dev/null +++ b/lib/private/files/stream/close.php @@ -0,0 +1,100 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Stream; + +/** + * stream wrapper that provides a callback on stream close + */ +class Close { + private static $callBacks = array(); + private $path = ''; + private $source; + private static $open = array(); + + public function stream_open($path, $mode, $options, &$opened_path) { + $path = substr($path, strlen('close://')); + $this->path = $path; + $this->source = fopen($path, $mode); + if (is_resource($this->source)) { + $this->meta = stream_get_meta_data($this->source); + } + self::$open[] = $path; + return is_resource($this->source); + } + + public function stream_seek($offset, $whence = SEEK_SET) { + fseek($this->source, $offset, $whence); + } + + public function stream_tell() { + return ftell($this->source); + } + + public function stream_read($count) { + return fread($this->source, $count); + } + + public function stream_write($data) { + return fwrite($this->source, $data); + } + + public function stream_set_option($option, $arg1, $arg2) { + switch ($option) { + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->source, $arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->source, $arg1, $arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->source, $arg1, $arg2); + } + } + + public function stream_stat() { + return fstat($this->source); + } + + public function stream_lock($mode) { + flock($this->source, $mode); + } + + public function stream_flush() { + return fflush($this->source); + } + + public function stream_eof() { + return feof($this->source); + } + + public function url_stat($path) { + $path = substr($path, strlen('close://')); + if (file_exists($path)) { + return stat($path); + } else { + return false; + } + } + + public function stream_close() { + fclose($this->source); + if (isset(self::$callBacks[$this->path])) { + call_user_func(self::$callBacks[$this->path], $this->path); + } + } + + public function unlink($path) { + $path = substr($path, strlen('close://')); + return unlink($path); + } + + public static function registerCallback($path, $callback) { + self::$callBacks[$path] = $callback; + } +} diff --git a/lib/private/files/stream/dir.php b/lib/private/files/stream/dir.php new file mode 100644 index 00000000000..6ca884fc994 --- /dev/null +++ b/lib/private/files/stream/dir.php @@ -0,0 +1,47 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Stream; + +class Dir { + private static $dirs = array(); + private $name; + private $index; + + public function dir_opendir($path, $options) { + $this->name = substr($path, strlen('fakedir://')); + $this->index = 0; + if (!isset(self::$dirs[$this->name])) { + self::$dirs[$this->name] = array(); + } + return true; + } + + public function dir_readdir() { + if ($this->index >= count(self::$dirs[$this->name])) { + return false; + } + $filename = self::$dirs[$this->name][$this->index]; + $this->index++; + return $filename; + } + + public function dir_closedir() { + $this->name = ''; + return true; + } + + public function dir_rewinddir() { + $this->index = 0; + return true; + } + + public static function register($path, $content) { + self::$dirs[$path] = $content; + } +} diff --git a/lib/private/files/stream/oc.php b/lib/private/files/stream/oc.php new file mode 100644 index 00000000000..88e7e062df9 --- /dev/null +++ b/lib/private/files/stream/oc.php @@ -0,0 +1,129 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Stream; + +/** + * a stream wrappers for ownCloud's virtual filesystem + */ +class OC { + /** + * @var \OC\Files\View + */ + static private $rootView; + + private $path; + private $dirSource; + private $fileSource; + private $meta; + + private function setup(){ + if (!self::$rootView) { + self::$rootView = new \OC\Files\View(''); + } + } + + public function stream_open($path, $mode, $options, &$opened_path) { + $this->setup(); + $path = substr($path, strlen('oc://')); + $this->path = $path; + $this->fileSource = self::$rootView->fopen($path, $mode); + if (is_resource($this->fileSource)) { + $this->meta = stream_get_meta_data($this->fileSource); + } + return is_resource($this->fileSource); + } + + public function stream_seek($offset, $whence = SEEK_SET) { + fseek($this->fileSource, $offset, $whence); + } + + public function stream_tell() { + return ftell($this->fileSource); + } + + public function stream_read($count) { + return fread($this->fileSource, $count); + } + + public function stream_write($data) { + return fwrite($this->fileSource, $data); + } + + public function stream_set_option($option, $arg1, $arg2) { + switch ($option) { + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->fileSource, $arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->fileSource, $arg1, $arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->fileSource, $arg1, $arg2); + } + } + + public function stream_stat() { + return fstat($this->fileSource); + } + + public function stream_lock($mode) { + flock($this->fileSource, $mode); + } + + public function stream_flush() { + return fflush($this->fileSource); + } + + public function stream_eof() { + return feof($this->fileSource); + } + + public function url_stat($path) { + $this->setup(); + $path = substr($path, strlen('oc://')); + if (self::$rootView->file_exists($path)) { + return self::$rootView->stat($path); + } else { + return false; + } + } + + public function stream_close() { + fclose($this->fileSource); + } + + public function unlink($path) { + $this->setup(); + $path = substr($path, strlen('oc://')); + return self::$rootView->unlink($path); + } + + public function dir_opendir($path, $options) { + $this->setup(); + $path = substr($path, strlen('oc://')); + $this->path = $path; + $this->dirSource = self::$rootView->opendir($path); + if (is_resource($this->dirSource)) { + $this->meta = stream_get_meta_data($this->dirSource); + } + return is_resource($this->dirSource); + } + + public function dir_readdir() { + return readdir($this->dirSource); + } + + public function dir_closedir() { + closedir($this->dirSource); + } + + public function dir_rewinddir() { + rewinddir($this->dirSource); + } +} diff --git a/lib/private/files/stream/quota.php b/lib/private/files/stream/quota.php new file mode 100644 index 00000000000..53d8a03d30f --- /dev/null +++ b/lib/private/files/stream/quota.php @@ -0,0 +1,128 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Stream; + +/** + * stream wrapper limits the amount of data that can be written to a stream + * + * usage: void \OC\Files\Stream\Quota::register($id, $stream, $limit) + * or: resource \OC\Files\Stream\Quota::wrap($stream, $limit) + */ +class Quota { + private static $streams = array(); + + /** + * @var resource $source + */ + private $source; + + /** + * @var int $limit + */ + private $limit; + + /** + * @param string $id + * @param resource $stream + * @param int $limit + */ + public static function register($id, $stream, $limit) { + self::$streams[$id] = array($stream, $limit); + } + + /** + * remove all registered streams + */ + public static function clear() { + self::$streams = array(); + } + + /** + * @param resource $stream + * @param int $limit + * @return resource + */ + static public function wrap($stream, $limit) { + $id = uniqid(); + self::register($id, $stream, $limit); + $meta = stream_get_meta_data($stream); + return fopen('quota://' . $id, $meta['mode']); + } + + public function stream_open($path, $mode, $options, &$opened_path) { + $id = substr($path, strlen('quota://')); + if (isset(self::$streams[$id])) { + list($this->source, $this->limit) = self::$streams[$id]; + return true; + } else { + return false; + } + } + + public function stream_seek($offset, $whence = SEEK_SET) { + if ($whence === SEEK_SET) { + $this->limit += $this->stream_tell() - $offset; + } else { + $this->limit -= $offset; + } + fseek($this->source, $offset, $whence); + } + + public function stream_tell() { + return ftell($this->source); + } + + public function stream_read($count) { + $this->limit -= $count; + return fread($this->source, $count); + } + + public function stream_write($data) { + $size = strlen($data); + if ($size > $this->limit) { + $data = substr($data, 0, $this->limit); + $size = $this->limit; + } + $this->limit -= $size; + return fwrite($this->source, $data); + } + + public function stream_set_option($option, $arg1, $arg2) { + switch ($option) { + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->source, $arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->source, $arg1, $arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->source, $arg1, $arg2); + } + } + + public function stream_stat() { + return fstat($this->source); + } + + public function stream_lock($mode) { + flock($this->source, $mode); + } + + public function stream_flush() { + return fflush($this->source); + } + + public function stream_eof() { + return feof($this->source); + } + + public function stream_close() { + fclose($this->source); + } +} diff --git a/lib/private/files/stream/staticstream.php b/lib/private/files/stream/staticstream.php new file mode 100644 index 00000000000..45b1a7a81f8 --- /dev/null +++ b/lib/private/files/stream/staticstream.php @@ -0,0 +1,156 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Stream; + +class StaticStream { + const MODE_FILE = 0100000; + + public $context; + protected static $data = array(); + + protected $path = ''; + protected $pointer = 0; + protected $writable = false; + + public function stream_close() { + } + + public function stream_eof() { + return $this->pointer >= strlen(self::$data[$this->path]); + } + + public function stream_flush() { + } + + public static function clear() { + self::$data = array(); + } + + public function stream_open($path, $mode, $options, &$opened_path) { + switch ($mode[0]) { + case 'r': + if (!isset(self::$data[$path])) return false; + $this->path = $path; + $this->writable = isset($mode[1]) && $mode[1] == '+'; + break; + case 'w': + self::$data[$path] = ''; + $this->path = $path; + $this->writable = true; + break; + case 'a': + if (!isset(self::$data[$path])) self::$data[$path] = ''; + $this->path = $path; + $this->writable = true; + $this->pointer = strlen(self::$data[$path]); + break; + case 'x': + if (isset(self::$data[$path])) return false; + $this->path = $path; + $this->writable = true; + break; + case 'c': + if (!isset(self::$data[$path])) self::$data[$path] = ''; + $this->path = $path; + $this->writable = true; + break; + default: + return false; + } + $opened_path = $this->path; + return true; + } + + public function stream_read($count) { + $bytes = min(strlen(self::$data[$this->path]) - $this->pointer, $count); + $data = substr(self::$data[$this->path], $this->pointer, $bytes); + $this->pointer += $bytes; + return $data; + } + + public function stream_seek($offset, $whence = SEEK_SET) { + $len = strlen(self::$data[$this->path]); + switch ($whence) { + case SEEK_SET: + if ($offset <= $len) { + $this->pointer = $offset; + return true; + } + break; + case SEEK_CUR: + if ($this->pointer + $offset <= $len) { + $this->pointer += $offset; + return true; + } + break; + case SEEK_END: + if ($len + $offset <= $len) { + $this->pointer = $len + $offset; + return true; + } + break; + } + return false; + } + + public function stream_stat() { + return $this->url_stat($this->path); + } + + public function stream_tell() { + return $this->pointer; + } + + public function stream_write($data) { + if (!$this->writable) return 0; + $size = strlen($data); + if ($this->stream_eof()) { + self::$data[$this->path] .= $data; + } else { + self::$data[$this->path] = substr_replace( + self::$data[$this->path], + $data, + $this->pointer + ); + } + $this->pointer += $size; + return $size; + } + + public function unlink($path) { + if (isset(self::$data[$path])) { + unset(self::$data[$path]); + } + return true; + } + + public function url_stat($path) { + if (isset(self::$data[$path])) { + $size = strlen(self::$data[$path]); + $time = time(); + $data = array( + 'dev' => 0, + 'ino' => 0, + 'mode' => self::MODE_FILE | 0777, + 'nlink' => 1, + 'uid' => 0, + 'gid' => 0, + 'rdev' => '', + 'size' => $size, + 'atime' => $time, + 'mtime' => $time, + 'ctime' => $time, + 'blksize' => -1, + 'blocks' => -1, + ); + return array_values($data) + $data; + } + return false; + } +} diff --git a/lib/private/files/type/detection.php b/lib/private/files/type/detection.php new file mode 100644 index 00000000000..242a81cb5a4 --- /dev/null +++ b/lib/private/files/type/detection.php @@ -0,0 +1,121 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Type; + +/** + * Class Detection + * + * Mimetype detection + * + * @package OC\Files\Type + */ +class Detection { + protected $mimetypes = array(); + + /** + * add an extension -> mimetype mapping + * + * @param string $extension + * @param string $mimetype + */ + public function registerType($extension, $mimetype) { + $this->mimetypes[$extension] = $mimetype; + } + + /** + * add an array of extension -> mimetype mappings + * + * @param array $types + */ + public function registerTypeArray($types) { + $this->mimetypes = array_merge($this->mimetypes, $types); + } + + /** + * detect mimetype only based on filename, content of file is not used + * + * @param string $path + * @return string + */ + public function detectPath($path) { + if (strpos($path, '.')) { + //try to guess the type by the file extension + $extension = strtolower(strrchr(basename($path), ".")); + $extension = substr($extension, 1); //remove leading . + return (isset($this->mimetypes[$extension])) ? $this->mimetypes[$extension] : 'application/octet-stream'; + } else { + return 'application/octet-stream'; + } + } + + /** + * detect mimetype based on both filename and content + * + * @param string $path + * @return string + */ + public function detect($path) { + $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://'); + + if (@is_dir($path)) { + // directories are easy + return "httpd/unix-directory"; + } + + $mimeType = $this->detectPath($path); + + if ($mimeType === 'application/octet-stream' and function_exists('finfo_open') + and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME) + ) { + $info = @strtolower(finfo_file($finfo, $path)); + if ($info) { + $mimeType = substr($info, 0, strpos($info, ';')); + } + finfo_close($finfo); + } + if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) { + // use mime magic extension if available + $mimeType = mime_content_type($path); + } + if (!$isWrapped and $mimeType === 'application/octet-stream' && \OC_Helper::canExecute("file")) { + // it looks like we have a 'file' command, + // lets see if it does have mime support + $path = escapeshellarg($path); + $fp = popen("file -b --mime-type $path 2>/dev/null", "r"); + $reply = fgets($fp); + pclose($fp); + + //trim the newline + $mimeType = trim($reply); + + } + return $mimeType; + } + + /** + * detect mimetype based on the content of a string + * + * @param string $data + * @return string + */ + public function detectString($data) { + if (function_exists('finfo_open') and function_exists('finfo_file')) { + $finfo = finfo_open(FILEINFO_MIME); + return finfo_buffer($finfo, $data); + } else { + $tmpFile = \OC_Helper::tmpFile(); + $fh = fopen($tmpFile, 'wb'); + fwrite($fh, $data, 8024); + fclose($fh); + $mime = $this->detect($tmpFile); + unset($tmpFile); + return $mime; + } + } +} diff --git a/lib/private/files/type/templatemanager.php b/lib/private/files/type/templatemanager.php new file mode 100644 index 00000000000..cd1536d2732 --- /dev/null +++ b/lib/private/files/type/templatemanager.php @@ -0,0 +1,46 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Type; + +class TemplateManager { + protected $templates = array(); + + public function registerTemplate($mimetype, $path) { + $this->templates[$mimetype] = $path; + } + + /** + * get the path of the template for a mimetype + * + * @param string $mimetype + * @return string | null + */ + public function getTemplatePath($mimetype) { + if (isset($this->templates[$mimetype])) { + return $this->templates[$mimetype]; + } else { + return null; + } + } + + /** + * get the template content for a mimetype + * + * @param string $mimetype + * @return string + */ + public function getTemplate($mimetype) { + $path = $this->getTemplatePath($mimetype); + if ($path) { + return file_get_contents($path); + } else { + return ''; + } + } +} diff --git a/lib/private/files/utils/scanner.php b/lib/private/files/utils/scanner.php new file mode 100644 index 00000000000..2cad7dd77bd --- /dev/null +++ b/lib/private/files/utils/scanner.php @@ -0,0 +1,96 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Utils; + +use OC\Files\Filesystem; +use OC\Hooks\PublicEmitter; + +/** + * Class Scanner + * + * Hooks available in scope \OC\Utils\Scanner + * - scanFile(string $absolutePath) + * - scanFolder(string $absolutePath) + * + * @package OC\Files\Utils + */ +class Scanner extends PublicEmitter { + /** + * @var string $user + */ + private $user; + + /** + * @param string $user + */ + public function __construct($user) { + $this->user = $user; + } + + /** + * get all storages for $dir + * + * @param string $dir + * @return \OC\Files\Mount\Mount[] + */ + protected function getMounts($dir) { + //TODO: move to the node based fileapi once that's done + \OC_Util::tearDownFS(); + \OC_Util::setupFS($this->user); + $absolutePath = Filesystem::getView()->getAbsolutePath($dir); + + $mountManager = Filesystem::getMountManager(); + $mounts = $mountManager->findIn($absolutePath); + $mounts[] = $mountManager->find($absolutePath); + $mounts = array_reverse($mounts); //start with the mount of $dir + + return $mounts; + } + + /** + * attach listeners to the scanner + * + * @param \OC\Files\Mount\Mount $mount + */ + protected function attachListener($mount) { + $scanner = $mount->getStorage()->getScanner(); + $emitter = $this; + $scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function ($path) use ($mount, $emitter) { + $emitter->emit('\OC\Files\Utils\Scanner', 'scanFile', array($mount->getMountPoint() . $path)); + }); + $scanner->listen('\OC\Files\Cache\Scanner', 'scanFolder', function ($path) use ($mount, $emitter) { + $emitter->emit('\OC\Files\Utils\Scanner', 'scanFolder', array($mount->getMountPoint() . $path)); + }); + } + + public function backgroundScan($dir) { + $mounts = $this->getMounts($dir); + foreach ($mounts as $mount) { + if (is_null($mount->getStorage())) { + continue; + } + $scanner = $mount->getStorage()->getScanner(); + $this->attachListener($mount); + $scanner->backgroundScan(); + } + } + + public function scan($dir) { + $mounts = $this->getMounts($dir); + foreach ($mounts as $mount) { + if (is_null($mount->getStorage())) { + continue; + } + $scanner = $mount->getStorage()->getScanner(); + $this->attachListener($mount); + $scanner->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG); + } + } +} + diff --git a/lib/private/files/view.php b/lib/private/files/view.php new file mode 100644 index 00000000000..aa08a5f7cc9 --- /dev/null +++ b/lib/private/files/view.php @@ -0,0 +1,1078 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class to provide access to ownCloud filesystem via a "view", and methods for + * working with files within that view (e.g. read, write, delete, etc.). Each + * view is restricted to a set of directories via a virtual root. The default view + * uses the currently logged in user's data directory as root (parts of + * OC_Filesystem are merely a wrapper for OC_FilesystemView). + * + * Apps that need to access files outside of the user data folders (to modify files + * belonging to a user other than the one currently logged in, for example) should + * use this class directly rather than using OC_Filesystem, or making use of PHP's + * built-in file manipulation functions. This will ensure all hooks and proxies + * are triggered correctly. + * + * Filesystem functions are not called directly; they are passed to the correct + * \OC\Files\Storage\Storage object + */ + +namespace OC\Files; + +class View { + private $fakeRoot = ''; + private $internal_path_cache = array(); + private $storage_cache = array(); + + public function __construct($root = '') { + $this->fakeRoot = $root; + } + + public function getAbsolutePath($path = '/') { + if (!$path) { + $path = '/'; + } + if ($path[0] !== '/') { + $path = '/' . $path; + } + return $this->fakeRoot . $path; + } + + /** + * change the root to a fake root + * + * @param string $fakeRoot + * @return bool + */ + public function chroot($fakeRoot) { + if (!$fakeRoot == '') { + if ($fakeRoot[0] !== '/') { + $fakeRoot = '/' . $fakeRoot; + } + } + $this->fakeRoot = $fakeRoot; + } + + /** + * get the fake root + * + * @return string + */ + public function getRoot() { + return $this->fakeRoot; + } + + /** + * get path relative to the root of the view + * + * @param string $path + * @return string + */ + public function getRelativePath($path) { + if ($this->fakeRoot == '') { + return $path; + } + if (strpos($path, $this->fakeRoot) !== 0) { + return null; + } else { + $path = substr($path, strlen($this->fakeRoot)); + if (strlen($path) === 0) { + return '/'; + } else { + return $path; + } + } + } + + /** + * get the mountpoint of the storage object for a path + * ( note: because a storage is not always mounted inside the fakeroot, the + * returned mountpoint is relative to the absolute root of the filesystem + * and doesn't take the chroot into account ) + * + * @param string $path + * @return string + */ + public function getMountPoint($path) { + return Filesystem::getMountPoint($this->getAbsolutePath($path)); + } + + /** + * resolve a path to a storage and internal path + * + * @param string $path + * @return array consisting of the storage and the internal path + */ + public function resolvePath($path) { + return Filesystem::resolvePath($this->getAbsolutePath($path)); + } + + /** + * return the path to a local version of the file + * we need this because we can't know if a file is stored local or not from + * outside the filestorage and for some purposes a local file is needed + * + * @param string $path + * @return string + */ + public function getLocalFile($path) { + $parent = substr($path, 0, strrpos($path, '/')); + $path = $this->getAbsolutePath($path); + list($storage, $internalPath) = Filesystem::resolvePath($path); + if (Filesystem::isValidPath($parent) and $storage) { + return $storage->getLocalFile($internalPath); + } else { + return null; + } + } + + /** + * @param string $path + * @return string + */ + public function getLocalFolder($path) { + $parent = substr($path, 0, strrpos($path, '/')); + $path = $this->getAbsolutePath($path); + list($storage, $internalPath) = Filesystem::resolvePath($path); + if (Filesystem::isValidPath($parent) and $storage) { + return $storage->getLocalFolder($internalPath); + } else { + return null; + } + } + + /** + * the following functions operate with arguments and return values identical + * to those of their PHP built-in equivalents. Mostly they are merely wrappers + * for \OC\Files\Storage\Storage via basicOperation(). + */ + public function mkdir($path) { + return $this->basicOperation('mkdir', $path, array('create', 'write')); + } + + public function rmdir($path) { + return $this->basicOperation('rmdir', $path, array('delete')); + } + + public function opendir($path) { + return $this->basicOperation('opendir', $path, array('read')); + } + + public function readdir($handle) { + $fsLocal = new Storage\Local(array('datadir' => '/')); + return $fsLocal->readdir($handle); + } + + public function is_dir($path) { + if ($path == '/') { + return true; + } + return $this->basicOperation('is_dir', $path); + } + + public function is_file($path) { + if ($path == '/') { + return false; + } + return $this->basicOperation('is_file', $path); + } + + public function stat($path) { + return $this->basicOperation('stat', $path); + } + + public function filetype($path) { + return $this->basicOperation('filetype', $path); + } + + public function filesize($path) { + return $this->basicOperation('filesize', $path); + } + + public function readfile($path) { + @ob_end_clean(); + $handle = $this->fopen($path, 'rb'); + if ($handle) { + $chunkSize = 8192; // 8 kB chunks + while (!feof($handle)) { + echo fread($handle, $chunkSize); + flush(); + } + $size = $this->filesize($path); + return $size; + } + return false; + } + + public function isCreatable($path) { + return $this->basicOperation('isCreatable', $path); + } + + public function isReadable($path) { + return $this->basicOperation('isReadable', $path); + } + + public function isUpdatable($path) { + return $this->basicOperation('isUpdatable', $path); + } + + public function isDeletable($path) { + return $this->basicOperation('isDeletable', $path); + } + + public function isSharable($path) { + return $this->basicOperation('isSharable', $path); + } + + public function file_exists($path) { + if ($path == '/') { + return true; + } + return $this->basicOperation('file_exists', $path); + } + + public function filemtime($path) { + return $this->basicOperation('filemtime', $path); + } + + public function touch($path, $mtime = null) { + if (!is_null($mtime) and !is_numeric($mtime)) { + $mtime = strtotime($mtime); + } + + $hooks = array('touch'); + + if (!$this->file_exists($path)) { + $hooks[] = 'create'; + $hooks[] = 'write'; + } + $result = $this->basicOperation('touch', $path, $hooks, $mtime); + if (!$result) { //if native touch fails, we emulate it by changing the mtime in the cache + $this->putFileInfo($path, array('mtime' => $mtime)); + } + return true; + } + + public function file_get_contents($path) { + return $this->basicOperation('file_get_contents', $path, array('read')); + } + + public function file_put_contents($path, $data) { + if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier + $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); + if (\OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) + and Filesystem::isValidPath($path) + and !Filesystem::isFileBlacklisted($path) + ) { + $path = $this->getRelativePath($absolutePath); + $exists = $this->file_exists($path); + $run = true; + if ($this->shouldEmitHooks($path)) { + if (!$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_create, + array( + Filesystem::signal_param_path => $this->getHookPath($path), + Filesystem::signal_param_run => &$run + ) + ); + } + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_write, + array( + Filesystem::signal_param_path => $this->getHookPath($path), + Filesystem::signal_param_run => &$run + ) + ); + } + if (!$run) { + return false; + } + $target = $this->fopen($path, 'w'); + if ($target) { + list ($count, $result) = \OC_Helper::streamCopy($data, $target); + fclose($target); + fclose($data); + if ($this->shouldEmitHooks($path) && $result !== false) { + if (!$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_create, + array(Filesystem::signal_param_path => $this->getHookPath($path)) + ); + } + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_write, + array(Filesystem::signal_param_path => $this->getHookPath($path)) + ); + } + \OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); + return $result; + } else { + return false; + } + } else { + return false; + } + } else { + return $this->basicOperation('file_put_contents', $path, array('create', 'write'), $data); + } + } + + public function unlink($path) { + return $this->basicOperation('unlink', $path, array('delete')); + } + + public function deleteAll($directory, $empty = false) { + return $this->rmdir($directory); + } + + public function rename($path1, $path2) { + $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; + $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; + $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); + $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); + if ( + \OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2) + and Filesystem::isValidPath($path2) + and Filesystem::isValidPath($path1) + and !Filesystem::isFileBlacklisted($path2) + ) { + $path1 = $this->getRelativePath($absolutePath1); + $path2 = $this->getRelativePath($absolutePath2); + + if ($path1 == null or $path2 == null) { + return false; + } + $run = true; + if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) { + // if it was a rename from a part file to a regular file it was a write and not a rename operation + \OC_Hook::emit( + Filesystem::CLASSNAME, Filesystem::signal_write, + array( + Filesystem::signal_param_path => $this->getHookPath($path2), + Filesystem::signal_param_run => &$run + ) + ); + } elseif ($this->shouldEmitHooks()) { + \OC_Hook::emit( + Filesystem::CLASSNAME, Filesystem::signal_rename, + array( + Filesystem::signal_param_oldpath => $this->getHookPath($path1), + Filesystem::signal_param_newpath => $this->getHookPath($path2), + Filesystem::signal_param_run => &$run + ) + ); + } + if ($run) { + $mp1 = $this->getMountPoint($path1 . $postFix1); + $mp2 = $this->getMountPoint($path2 . $postFix2); + if ($mp1 == $mp2) { + list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); + list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); + if ($storage) { + $result = $storage->rename($internalPath1, $internalPath2); + \OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2); + } else { + $result = false; + } + } else { + if ($this->is_dir($path1)) { + $result = $this->copy($path1, $path2); + if ($result === true) { + list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); + $result = $storage1->deleteAll($internalPath1); + } + } else { + $source = $this->fopen($path1 . $postFix1, 'r'); + $target = $this->fopen($path2 . $postFix2, 'w'); + list($count, $result) = \OC_Helper::streamCopy($source, $target); + + // close open handle - especially $source is necessary because unlink below will + // throw an exception on windows because the file is locked + fclose($source); + fclose($target); + + if ($result !== false) { + list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); + $storage1->unlink($internalPath1); + } + } + } + if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { + // if it was a rename from a part file to a regular file it was a write and not a rename operation + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_write, + array( + Filesystem::signal_param_path => $this->getHookPath($path2), + ) + ); + } elseif ($this->shouldEmitHooks() && $result !== false) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_rename, + array( + Filesystem::signal_param_oldpath => $this->getHookPath($path1), + Filesystem::signal_param_newpath => $this->getHookPath($path2) + ) + ); + } + return $result; + } else { + return false; + } + } else { + return false; + } + } + + public function copy($path1, $path2) { + $postFix1 = (substr($path1, -1, 1) === '/') ? '/' : ''; + $postFix2 = (substr($path2, -1, 1) === '/') ? '/' : ''; + $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); + $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); + if ( + \OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) + and Filesystem::isValidPath($path2) + and Filesystem::isValidPath($path1) + and !Filesystem::isFileBlacklisted($path2) + ) { + $path1 = $this->getRelativePath($absolutePath1); + $path2 = $this->getRelativePath($absolutePath2); + + if ($path1 == null or $path2 == null) { + return false; + } + $run = true; + $exists = $this->file_exists($path2); + if ($this->shouldEmitHooks()) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_copy, + array( + Filesystem::signal_param_oldpath => $this->getHookPath($path1), + Filesystem::signal_param_newpath => $this->getHookPath($path2), + Filesystem::signal_param_run => &$run + ) + ); + if ($run and !$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_create, + array( + Filesystem::signal_param_path => $this->getHookPath($path2), + Filesystem::signal_param_run => &$run + ) + ); + } + if ($run) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_write, + array( + Filesystem::signal_param_path => $this->getHookPath($path2), + Filesystem::signal_param_run => &$run + ) + ); + } + } + if ($run) { + $mp1 = $this->getMountPoint($path1 . $postFix1); + $mp2 = $this->getMountPoint($path2 . $postFix2); + if ($mp1 == $mp2) { + list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1); + list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2); + if ($storage) { + $result = $storage->copy($internalPath1, $internalPath2); + } else { + $result = false; + } + } else { + if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) { + $result = $this->mkdir($path2); + if (is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if (!Filesystem::isIgnoredDir($file)) { + $result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file); + } + } + } + } else { + $source = $this->fopen($path1 . $postFix1, 'r'); + $target = $this->fopen($path2 . $postFix2, 'w'); + list($count, $result) = \OC_Helper::streamCopy($source, $target); + } + } + if ($this->shouldEmitHooks() && $result !== false) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_copy, + array( + Filesystem::signal_param_oldpath => $this->getHookPath($path1), + Filesystem::signal_param_newpath => $this->getHookPath($path2) + ) + ); + if (!$exists) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_create, + array(Filesystem::signal_param_path => $this->getHookPath($path2)) + ); + } + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_post_write, + array(Filesystem::signal_param_path => $this->getHookPath($path2)) + ); + } + return $result; + } else { + return false; + } + } else { + return false; + } + } + + public function fopen($path, $mode) { + $hooks = array(); + switch ($mode) { + case 'r': + case 'rb': + $hooks[] = 'read'; + break; + case 'r+': + case 'rb+': + case 'w+': + case 'wb+': + case 'x+': + case 'xb+': + case 'a+': + case 'ab+': + $hooks[] = 'read'; + $hooks[] = 'write'; + break; + case 'w': + case 'wb': + case 'x': + case 'xb': + case 'a': + case 'ab': + $hooks[] = 'write'; + break; + default: + \OC_Log::write('core', 'invalid mode (' . $mode . ') for ' . $path, \OC_Log::ERROR); + } + + return $this->basicOperation('fopen', $path, $hooks, $mode); + } + + public function toTmpFile($path) { + if (Filesystem::isValidPath($path)) { + $source = $this->fopen($path, 'r'); + if ($source) { + $extension = pathinfo($path, PATHINFO_EXTENSION); + $tmpFile = \OC_Helper::tmpFile($extension); + file_put_contents($tmpFile, $source); + return $tmpFile; + } else { + return false; + } + } else { + return false; + } + } + + public function fromTmpFile($tmpFile, $path) { + if (Filesystem::isValidPath($path)) { + if (!$tmpFile) { + debug_print_backtrace(); + } + $source = fopen($tmpFile, 'r'); + if ($source) { + $this->file_put_contents($path, $source); + unlink($tmpFile); + return true; + } else { + return false; + } + } else { + return false; + } + } + + public function getMimeType($path) { + return $this->basicOperation('getMimeType', $path); + } + + public function hash($type, $path, $raw = false) { + $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; + $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); + if (\OC_FileProxy::runPreProxies('hash', $absolutePath) && Filesystem::isValidPath($path)) { + $path = $this->getRelativePath($absolutePath); + if ($path == null) { + return false; + } + if ($this->shouldEmitHooks($path)) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + Filesystem::signal_read, + array(Filesystem::signal_param_path => $this->getHookPath($path)) + ); + } + list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); + if ($storage) { + $result = $storage->hash($type, $internalPath, $raw); + $result = \OC_FileProxy::runPostProxies('hash', $absolutePath, $result); + return $result; + } + } + return null; + } + + public function free_space($path = '/') { + return $this->basicOperation('free_space', $path); + } + + /** + * @brief abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage + * @param string $operation + * @param string $path + * @param array $hooks (optional) + * @param mixed $extraParam (optional) + * @return mixed + * + * This method takes requests for basic filesystem functions (e.g. reading & writing + * files), processes hooks and proxies, sanitises paths, and finally passes them on to + * \OC\Files\Storage\Storage for delegation to a storage backend for execution + */ + private function basicOperation($operation, $path, $hooks = array(), $extraParam = null) { + $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; + $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); + if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) + and Filesystem::isValidPath($path) + and !Filesystem::isFileBlacklisted($path) + ) { + $path = $this->getRelativePath($absolutePath); + if ($path == null) { + return false; + } + + $run = $this->runHooks($hooks, $path); + list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); + if ($run and $storage) { + if (!is_null($extraParam)) { + $result = $storage->$operation($internalPath, $extraParam); + } else { + $result = $storage->$operation($internalPath); + } + $result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result); + if ($this->shouldEmitHooks($path) && $result !== false) { + if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open + $this->runHooks($hooks, $path, true); + } + } + return $result; + } + } + return null; + } + + /** + * get the path relative to the default root for hook usage + * + * @param string $path + * @return string + */ + private function getHookPath($path) { + if (!Filesystem::getView()) { + return $path; + } + return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path)); + } + + private function shouldEmitHooks($path = '') { + if ($path && Cache\Scanner::isPartialFile($path)) { + return false; + } + if (!Filesystem::$loaded) { + return false; + } + $defaultRoot = Filesystem::getRoot(); + return (strlen($this->fakeRoot) >= strlen($defaultRoot)) && (substr($this->fakeRoot, 0, strlen($defaultRoot)) === $defaultRoot); + } + + private function runHooks($hooks, $path, $post = false) { + $path = $this->getHookPath($path); + $prefix = ($post) ? 'post_' : ''; + $run = true; + if ($this->shouldEmitHooks($path)) { + foreach ($hooks as $hook) { + if ($hook != 'read') { + \OC_Hook::emit( + Filesystem::CLASSNAME, + $prefix . $hook, + array( + Filesystem::signal_param_run => &$run, + Filesystem::signal_param_path => $path + ) + ); + } elseif (!$post) { + \OC_Hook::emit( + Filesystem::CLASSNAME, + $prefix . $hook, + array( + Filesystem::signal_param_path => $path + ) + ); + } + } + } + return $run; + } + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + */ + public function hasUpdated($path, $time) { + return $this->basicOperation('hasUpdated', $path, array(), $time); + } + + /** + * get the filesystem info + * + * @param string $path + * @return array + * + * returns an associative array with the following keys: + * - size + * - mtime + * - mimetype + * - encrypted + * - versioned + */ + public function getFileInfo($path) { + $data = array(); + if (!Filesystem::isValidPath($path)) { + return $data; + } + $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = Filesystem::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $permissionsCache = $storage->getPermissionsCache($internalPath); + $user = \OC_User::getUser(); + + if (!$cache->inCache($internalPath)) { + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); + } else { + $watcher = $storage->getWatcher($internalPath); + $watcher->checkUpdate($internalPath); + } + + $data = $cache->get($internalPath); + + if ($data and $data['fileid']) { + if ($data['mimetype'] === 'httpd/unix-directory') { + //add the sizes of other mountpoints to the folder + $mountPoints = Filesystem::getMountPoints($path); + foreach ($mountPoints as $mountPoint) { + $subStorage = Filesystem::getStorage($mountPoint); + if ($subStorage) { + $subCache = $subStorage->getCache(''); + $rootEntry = $subCache->get(''); + $data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0; + } + } + } + + $permissions = $permissionsCache->get($data['fileid'], $user); + if ($permissions === -1) { + $permissions = $storage->getPermissions($internalPath); + $permissionsCache->set($data['fileid'], $user, $permissions); + } + $data['permissions'] = $permissions; + } + } + + $data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data); + + return $data; + } + + /** + * get the content of a directory + * + * @param string $directory path under datadirectory + * @param string $mimetype_filter limit returned content to this mimetype or mimepart + * @return array + */ + public function getDirectoryContent($directory, $mimetype_filter = '') { + $result = array(); + if (!Filesystem::isValidPath($directory)) { + return $result; + } + $path = Filesystem::normalizePath($this->fakeRoot . '/' . $directory); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = Filesystem::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($internalPath); + $permissionsCache = $storage->getPermissionsCache($internalPath); + $user = \OC_User::getUser(); + + if ($cache->getStatus($internalPath) < Cache\Cache::COMPLETE) { + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); + } else { + $watcher = $storage->getWatcher($internalPath); + $watcher->checkUpdate($internalPath); + } + + $files = $cache->getFolderContents($internalPath); //TODO: mimetype_filter + $permissions = $permissionsCache->getDirectoryPermissions($cache->getId($internalPath), $user); + + $ids = array(); + foreach ($files as $i => $file) { + $files[$i]['type'] = $file['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; + $ids[] = $file['fileid']; + + if (!isset($permissions[$file['fileid']])) { + $permissions[$file['fileid']] = $storage->getPermissions($file['path']); + $permissionsCache->set($file['fileid'], $user, $permissions[$file['fileid']]); + } + $files[$i]['permissions'] = $permissions[$file['fileid']]; + } + + //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders + $mountPoints = Filesystem::getMountPoints($path); + $dirLength = strlen($path); + foreach ($mountPoints as $mountPoint) { + $subStorage = Filesystem::getStorage($mountPoint); + if ($subStorage) { + $subCache = $subStorage->getCache(''); + + if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) { + $subScanner = $subStorage->getScanner(''); + $subScanner->scanFile(''); + } + + $rootEntry = $subCache->get(''); + if ($rootEntry) { + $relativePath = trim(substr($mountPoint, $dirLength), '/'); + if ($pos = strpos($relativePath, '/')) { + //mountpoint inside subfolder add size to the correct folder + $entryName = substr($relativePath, 0, $pos); + foreach ($files as &$entry) { + if ($entry['name'] === $entryName) { + $entry['size'] += $rootEntry['size']; + } + } + } else { //mountpoint in this folder, add an entry for it + $rootEntry['name'] = $relativePath; + $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; + $subPermissionsCache = $subStorage->getPermissionsCache(''); + $permissions = $subPermissionsCache->get($rootEntry['fileid'], $user); + if ($permissions === -1) { + $permissions = $subStorage->getPermissions($rootEntry['path']); + $subPermissionsCache->set($rootEntry['fileid'], $user, $permissions); + } + $rootEntry['permissions'] = $permissions; + + //remove any existing entry with the same name + foreach ($files as $i => $file) { + if ($file['name'] === $rootEntry['name']) { + unset($files[$i]); + break; + } + } + $files[] = $rootEntry; + } + } + } + } + + if ($mimetype_filter) { + foreach ($files as $file) { + if (strpos($mimetype_filter, '/')) { + if ($file['mimetype'] === $mimetype_filter) { + $result[] = $file; + } + } else { + if ($file['mimepart'] === $mimetype_filter) { + $result[] = $file; + } + } + } + } else { + $result = $files; + } + } + return $result; + } + + /** + * change file metadata + * + * @param string $path + * @param array $data + * @return int + * + * returns the fileid of the updated file + */ + public function putFileInfo($path, $data) { + $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = Filesystem::resolvePath($path); + if ($storage) { + $cache = $storage->getCache($path); + + if (!$cache->inCache($internalPath)) { + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); + } + + return $cache->put($internalPath, $data); + } else { + return -1; + } + } + + /** + * search for files with the name matching $query + * + * @param string $query + * @return array + */ + public function search($query) { + return $this->searchCommon('%' . $query . '%', 'search'); + } + + /** + * search for files by mimetype + * + * @param string $mimetype + * @return array + */ + public function searchByMime($mimetype) { + return $this->searchCommon($mimetype, 'searchByMime'); + } + + /** + * @param string $query + * @param string $method + * @return array + */ + private function searchCommon($query, $method) { + $files = array(); + $rootLength = strlen($this->fakeRoot); + + $mountPoint = Filesystem::getMountPoint($this->fakeRoot); + $storage = Filesystem::getStorage($mountPoint); + if ($storage) { + $cache = $storage->getCache(''); + + $results = $cache->$method($query); + foreach ($results as $result) { + if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') { + $result['path'] = substr($mountPoint . $result['path'], $rootLength); + $files[] = $result; + } + } + + $mountPoints = Filesystem::getMountPoints($this->fakeRoot); + foreach ($mountPoints as $mountPoint) { + $storage = Filesystem::getStorage($mountPoint); + if ($storage) { + $cache = $storage->getCache(''); + + $relativeMountPoint = substr($mountPoint, $rootLength); + $results = $cache->$method($query); + if ($results) { + foreach ($results as $result) { + $result['path'] = $relativeMountPoint . $result['path']; + $files[] = $result; + } + } + } + } + } + return $files; + } + + /** + * Get the owner for a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path) { + return $this->basicOperation('getOwner', $path); + } + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string + */ + public function getETag($path) { + /** + * @var Storage\Storage $storage + * @var string $internalPath + */ + list($storage, $internalPath) = $this->resolvePath($path); + if ($storage) { + return $storage->getETag($internalPath); + } else { + return null; + } + } + + /** + * Get the path of a file by id, relative to the view + * + * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file + * + * @param int $id + * @return string + */ + public function getPath($id) { + list($storage, $internalPath) = Cache\Cache::getById($id); + $mounts = Filesystem::getMountByStorageId($storage); + foreach ($mounts as $mount) { + /** + * @var \OC\Files\Mount $mount + */ + $fullPath = $mount->getMountPoint() . $internalPath; + if (!is_null($path = $this->getRelativePath($fullPath))) { + return $path; + } + } + return null; + } +} diff --git a/lib/private/geo.php b/lib/private/geo.php new file mode 100644 index 00000000000..ed01ad0b616 --- /dev/null +++ b/lib/private/geo.php @@ -0,0 +1,31 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +class OC_Geo{ + /* + * @brief returns the closest timezone to coordinates + * @param (string) $latitude - Latitude + * @param (string) $longitude - Longitude + * @return (string) $timezone - closest timezone + */ + public static function timezone($latitude, $longitude) { + $alltimezones = DateTimeZone::listIdentifiers(); + $variances = array(); + //calculate for all timezones the system know + foreach($alltimezones as $timezone) { + $datetimezoneobj = new DateTimeZone($timezone); + $locationinformations = $datetimezoneobj->getLocation(); + $latitudeoftimezone = $locationinformations['latitude']; + $longitudeoftimezone = $locationinformations['longitude']; + $variances[abs($latitudeoftimezone - $latitude) + abs($longitudeoftimezone - $longitude)] = $timezone; + } + //sort array and return the timezone with the smallest difference + ksort($variances); + reset($variances); + return current($variances); + } +} diff --git a/lib/private/group.php b/lib/private/group.php new file mode 100644 index 00000000000..ba93dc129a1 --- /dev/null +++ b/lib/private/group.php @@ -0,0 +1,301 @@ +. + * + */ + +/** + * This class provides all methods needed for managing groups. + * + * Hooks provided: + * pre_createGroup(&run, gid) + * post_createGroup(gid) + * pre_deleteGroup(&run, gid) + * post_deleteGroup(gid) + * pre_addToGroup(&run, uid, gid) + * post_addToGroup(uid, gid) + * pre_removeFromGroup(&run, uid, gid) + * post_removeFromGroup(uid, gid) + */ +class OC_Group { + /** + * @var \OC\Group\Manager $manager + */ + private static $manager; + + /** + * @var \OC\User\Manager + */ + private static $userManager; + + /** + * @return \OC\Group\Manager + */ + public static function getManager() { + if (self::$manager) { + return self::$manager; + } + self::$userManager = \OC_User::getManager(); + self::$manager = new \OC\Group\Manager(self::$userManager); + return self::$manager; + } + + /** + * @brief set the group backend + * @param \OC_Group_Backend $backend The backend to use for user managment + * @return bool + */ + public static function useBackend($backend) { + self::getManager()->addBackend($backend); + return true; + } + + /** + * remove all used backends + */ + public static function clearBackends() { + self::getManager()->clearBackends(); + } + + /** + * @brief Try to create a new group + * @param string $gid The name of the group to create + * @return bool + * + * Tries to create a new group. If the group name already exists, false will + * be returned. Basic checking of Group name + */ + public static function createGroup($gid) { + OC_Hook::emit("OC_Group", "pre_createGroup", array("run" => true, "gid" => $gid)); + + if (self::getManager()->createGroup($gid)) { + OC_Hook::emit("OC_User", "post_createGroup", array("gid" => $gid)); + return true; + } else { + return false; + } + } + + /** + * @brief delete a group + * @param string $gid gid of the group to delete + * @return bool + * + * Deletes a group and removes it from the group_user-table + */ + public static function deleteGroup($gid) { + // Prevent users from deleting group admin + if ($gid == "admin") { + return false; + } + + OC_Hook::emit("OC_Group", "pre_deleteGroup", array("run" => true, "gid" => $gid)); + + $group = self::getManager()->get($gid); + if ($group) { + if ($group->delete()) { + OC_Hook::emit("OC_User", "post_deleteGroup", array("gid" => $gid)); + return true; + } + } + return false; + } + + /** + * @brief is user in group? + * @param string $uid uid of the user + * @param string $gid gid of the group + * @return bool + * + * Checks whether the user is member of a group or not. + */ + public static function inGroup($uid, $gid) { + $group = self::getManager()->get($gid); + $user = self::$userManager->get($uid); + if ($group and $user) { + return $group->inGroup($user); + } + return false; + } + + /** + * @brief Add a user to a group + * @param string $uid Name of the user to add to group + * @param string $gid Name of the group in which add the user + * @return bool + * + * Adds a user to a group. + */ + public static function addToGroup($uid, $gid) { + $group = self::getManager()->get($gid); + $user = self::$userManager->get($uid); + if ($group and $user) { + OC_Hook::emit("OC_Group", "pre_addToGroup", array("run" => true, "uid" => $uid, "gid" => $gid)); + $group->addUser($user); + OC_Hook::emit("OC_User", "post_addToGroup", array("uid" => $uid, "gid" => $gid)); + return true; + } else { + return false; + } + } + + /** + * @brief Removes a user from a group + * @param string $uid Name of the user to remove from group + * @param string $gid Name of the group from which remove the user + * @return bool + * + * removes the user from a group. + */ + public static function removeFromGroup($uid, $gid) { + $group = self::getManager()->get($gid); + $user = self::$userManager->get($uid); + if ($group and $user) { + OC_Hook::emit("OC_Group", "pre_removeFromGroup", array("run" => true, "uid" => $uid, "gid" => $gid)); + $group->removeUser($user); + OC_Hook::emit("OC_User", "post_removeFromGroup", array("uid" => $uid, "gid" => $gid)); + return true; + } else { + return false; + } + } + + /** + * @brief Get all groups a user belongs to + * @param string $uid Name of the user + * @return array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public static function getUserGroups($uid) { + $user = self::$userManager->get($uid); + if ($user) { + $groups = self::getManager()->getUserGroups($user); + $groupIds = array(); + foreach ($groups as $group) { + $groupIds[] = $group->getGID(); + } + return $groupIds; + } else { + return array(); + } + } + + /** + * @brief get a list of all groups + * @returns array with group names + * + * Returns a list with all groups + */ + public static function getGroups($search = '', $limit = null, $offset = null) { + $groups = self::getManager()->search($search, $limit, $offset); + $groupIds = array(); + foreach ($groups as $group) { + $groupIds[] = $group->getGID(); + } + return $groupIds; + } + + /** + * check if a group exists + * + * @param string $gid + * @return bool + */ + public static function groupExists($gid) { + return self::getManager()->groupExists($gid); + } + + /** + * @brief get a list of all users in a group + * @returns array with user ids + */ + public static function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { + $group = self::getManager()->get($gid); + if ($group) { + $users = $group->searchUsers($search, $limit, $offset); + $userIds = array(); + foreach ($users as $user) { + $userIds[] = $user->getUID(); + } + return $userIds; + } else { + return array(); + } + } + + /** + * @brief get a list of all users in several groups + * @param array $gids + * @param string $search + * @param int $limit + * @param int $offset + * @return array with user ids + */ + public static function usersInGroups($gids, $search = '', $limit = -1, $offset = 0) { + $users = array(); + foreach ($gids as $gid) { + // TODO Need to apply limits to groups as total + $users = array_merge(array_diff(self::usersInGroup($gid, $search, $limit, $offset), $users), $users); + } + return $users; + } + + /** + * @brief get a list of all display names in a group + * @returns array with display names (value) and user ids(key) + */ + public static function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) { + $group = self::getManager()->get($gid); + if ($group) { + $users = $group->searchDisplayName($search . $limit, $offset); + $displayNames = array(); + foreach ($users as $user) { + $displayNames[] = $user->getDisplayName(); + } + return $displayNames; + } else { + return array(); + } + } + + /** + * @brief get a list of all display names in several groups + * @param array $gids + * @param string $search + * @param int $limit + * @param int $offset + * @return array with display names (Key) user ids (value) + */ + public static function displayNamesInGroups($gids, $search = '', $limit = -1, $offset = 0) { + $displayNames = array(); + foreach ($gids as $gid) { + // TODO Need to apply limits to groups as total + $diff = array_diff( + self::displayNamesInGroup($gid, $search, $limit, $offset), + $displayNames + ); + if ($diff) { + $displayNames = array_merge($diff, $displayNames); + } + } + return $displayNames; + } +} diff --git a/lib/private/group/backend.php b/lib/private/group/backend.php new file mode 100644 index 00000000000..2e17b5d0b7f --- /dev/null +++ b/lib/private/group/backend.php @@ -0,0 +1,157 @@ +. +* +*/ + +/** + * error code for functions not provided by the group backend + */ +define('OC_GROUP_BACKEND_NOT_IMPLEMENTED', -501); + +/** + * actions that user backends can define + */ +define('OC_GROUP_BACKEND_CREATE_GROUP', 0x00000001); +define('OC_GROUP_BACKEND_DELETE_GROUP', 0x00000010); +define('OC_GROUP_BACKEND_ADD_TO_GROUP', 0x00000100); +define('OC_GROUP_BACKEND_REMOVE_FROM_GOUP', 0x00001000); +define('OC_GROUP_BACKEND_GET_DISPLAYNAME', 0x00010000); + +/** + * Abstract base class for user management + */ +abstract class OC_Group_Backend implements OC_Group_Interface { + protected $possibleActions = array( + OC_GROUP_BACKEND_CREATE_GROUP => 'createGroup', + OC_GROUP_BACKEND_DELETE_GROUP => 'deleteGroup', + OC_GROUP_BACKEND_ADD_TO_GROUP => 'addToGroup', + OC_GROUP_BACKEND_REMOVE_FROM_GOUP => 'removeFromGroup', + OC_GROUP_BACKEND_GET_DISPLAYNAME => 'displayNamesInGroup', + ); + + /** + * @brief Get all supported actions + * @return int bitwise-or'ed actions + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function getSupportedActions() { + $actions = 0; + foreach($this->possibleActions AS $action => $methodName) { + if(method_exists($this, $methodName)) { + $actions |= $action; + } + } + + return $actions; + } + + /** + * @brief Check if backend implements actions + * @param int $actions bitwise-or'ed actions + * @return boolean + * + * Returns the supported actions as int to be + * compared with OC_GROUP_BACKEND_CREATE_GROUP etc. + */ + public function implementsActions($actions) { + return (bool)($this->getSupportedActions() & $actions); + } + + /** + * @brief is user in group? + * @param string $uid uid of the user + * @param string $gid gid of the group + * @return bool + * + * Checks whether the user is member of a group or not. + */ + public function inGroup($uid, $gid) { + return in_array($gid, $this->getUserGroups($uid)); + } + + /** + * @brief Get all groups a user belongs to + * @param string $uid Name of the user + * @return array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public function getUserGroups($uid) { + return array(); + } + + /** + * @brief get a list of all groups + * @param string $search + * @param int $limit + * @param int $offset + * @return array with group names + * + * Returns a list with all groups + */ + + public function getGroups($search = '', $limit = -1, $offset = 0) { + return array(); + } + + /** + * check if a group exists + * @param string $gid + * @return bool + */ + public function groupExists($gid) { + return in_array($gid, $this->getGroups($gid, 1)); + } + + /** + * @brief get a list of all users in a group + * @param string $gid + * @param string $search + * @param int $limit + * @param int $offset + * @return array with user ids + */ + public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { + return array(); + } + + /** + * @brief get a list of all display names in a group + * @param string $gid + * @param string $search + * @param int $limit + * @param int $offset + * @return array with display names (value) and user ids (key) + */ + public function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) { + $displayNames = array(); + $users = $this->usersInGroup($gid, $search, $limit, $offset); + foreach ($users as $user) { + $displayNames[$user] = $user; + } + + return $displayNames; + } + +} diff --git a/lib/private/group/database.php b/lib/private/group/database.php new file mode 100644 index 00000000000..d0974685ff6 --- /dev/null +++ b/lib/private/group/database.php @@ -0,0 +1,239 @@ +. + * + */ +/* + * + * The following SQL statement is just a help for developers and will not be + * executed! + * + * CREATE TABLE `groups` ( + * `gid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, + * PRIMARY KEY (`gid`) + * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + * + * CREATE TABLE `group_user` ( + * `gid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, + * `uid` varchar(64) COLLATE utf8_unicode_ci NOT NULL + * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + * + */ + +/** + * Class for group management in a SQL Database (e.g. MySQL, SQLite) + */ +class OC_Group_Database extends OC_Group_Backend { + + /** + * @brief Try to create a new group + * @param string $gid The name of the group to create + * @return bool + * + * Tries to create a new group. If the group name already exists, false will + * be returned. + */ + public function createGroup( $gid ) { + // Check for existence + $stmt = OC_DB::prepare( "SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` = ?" ); + $result = $stmt->execute( array( $gid )); + + if( $result->fetchRow() ) { + // Can not add an existing group + return false; + } + else{ + // Add group and exit + $stmt = OC_DB::prepare( "INSERT INTO `*PREFIX*groups` ( `gid` ) VALUES( ? )" ); + $result = $stmt->execute( array( $gid )); + + return $result ? true : false; + } + } + + /** + * @brief delete a group + * @param string $gid gid of the group to delete + * @return bool + * + * Deletes a group and removes it from the group_user-table + */ + public function deleteGroup( $gid ) { + // Delete the group + $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*groups` WHERE `gid` = ?" ); + $stmt->execute( array( $gid )); + + // Delete the group-user relation + $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*group_user` WHERE `gid` = ?" ); + $stmt->execute( array( $gid )); + + return true; + } + + /** + * @brief is user in group? + * @param string $uid uid of the user + * @param string $gid gid of the group + * @return bool + * + * Checks whether the user is member of a group or not. + */ + public function inGroup( $uid, $gid ) { + // check + $stmt = OC_DB::prepare( "SELECT `uid` FROM `*PREFIX*group_user` WHERE `gid` = ? AND `uid` = ?" ); + $result = $stmt->execute( array( $gid, $uid )); + + return $result->fetchRow() ? true : false; + } + + /** + * @brief Add a user to a group + * @param string $uid Name of the user to add to group + * @param string $gid Name of the group in which add the user + * @return bool + * + * Adds a user to a group. + */ + public function addToGroup( $uid, $gid ) { + // No duplicate entries! + if( !$this->inGroup( $uid, $gid )) { + $stmt = OC_DB::prepare( "INSERT INTO `*PREFIX*group_user` ( `uid`, `gid` ) VALUES( ?, ? )" ); + $stmt->execute( array( $uid, $gid )); + return true; + }else{ + return false; + } + } + + /** + * @brief Removes a user from a group + * @param string $uid Name of the user to remove from group + * @param string $gid Name of the group from which remove the user + * @return bool + * + * removes the user from a group. + */ + public function removeFromGroup( $uid, $gid ) { + $stmt = OC_DB::prepare( "DELETE FROM `*PREFIX*group_user` WHERE `uid` = ? AND `gid` = ?" ); + $stmt->execute( array( $uid, $gid )); + + return true; + } + + /** + * @brief Get all groups a user belongs to + * @param string $uid Name of the user + * @return array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public function getUserGroups( $uid ) { + // No magic! + $stmt = OC_DB::prepare( "SELECT `gid` FROM `*PREFIX*group_user` WHERE `uid` = ?" ); + $result = $stmt->execute( array( $uid )); + + $groups = array(); + while( $row = $result->fetchRow()) { + $groups[] = $row["gid"]; + } + + return $groups; + } + + /** + * @brief get a list of all groups + * @param string $search + * @param int $limit + * @param int $offset + * @return array with group names + * + * Returns a list with all groups + */ + public function getGroups($search = '', $limit = null, $offset = null) { + $stmt = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` LIKE ?', $limit, $offset); + $result = $stmt->execute(array($search.'%')); + $groups = array(); + while ($row = $result->fetchRow()) { + $groups[] = $row['gid']; + } + return $groups; + } + + /** + * check if a group exists + * @param string $gid + * @return bool + */ + public function groupExists($gid) { + $query = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*groups` WHERE `gid` = ?'); + $result = $query->execute(array($gid))->fetchOne(); + if ($result) { + return true; + } + return false; + } + + /** + * @brief get a list of all users in a group + * @param string $gid + * @param string $search + * @param int $limit + * @param int $offset + * @return array with user ids + */ + public function usersInGroup($gid, $search = '', $limit = null, $offset = null) { + $stmt = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*group_user` WHERE `gid` = ? AND `uid` LIKE ?', + $limit, + $offset); + $result = $stmt->execute(array($gid, $search.'%')); + $users = array(); + while ($row = $result->fetchRow()) { + $users[] = $row['uid']; + } + return $users; + } + + /** + * @brief get a list of all display names in a group + * @param string $gid + * @param string $search + * @param int $limit + * @param int $offset + * @return array with display names (value) and user ids (key) + */ + public function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) { + $displayNames = array(); + + $stmt = OC_DB::prepare('SELECT `*PREFIX*users`.`uid`, `*PREFIX*users`.`displayname`' + .' FROM `*PREFIX*users`' + .' INNER JOIN `*PREFIX*group_user` ON `*PREFIX*group_user`.`uid` = `*PREFIX*users`.`uid`' + .' WHERE `gid` = ? AND `*PREFIX*group_user`.`uid` LIKE ?', + $limit, + $offset); + $result = $stmt->execute(array($gid, $search.'%')); + $users = array(); + while ($row = $result->fetchRow()) { + $displayName = trim($row['displayname'], ' '); + $displayNames[$row['uid']] = empty($displayName) ? $row['uid'] : $displayName; + } + return $displayNames; + } +} diff --git a/lib/private/group/dummy.php b/lib/private/group/dummy.php new file mode 100644 index 00000000000..9516fd52ff8 --- /dev/null +++ b/lib/private/group/dummy.php @@ -0,0 +1,160 @@ +. +* +*/ + +/** + * dummy group backend, does not keep state, only for testing use + */ +class OC_Group_Dummy extends OC_Group_Backend { + private $groups=array(); + /** + * @brief Try to create a new group + * @param $gid The name of the group to create + * @returns true/false + * + * Trys to create a new group. If the group name already exists, false will + * be returned. + */ + public function createGroup($gid) { + if(!isset($this->groups[$gid])) { + $this->groups[$gid]=array(); + return true; + }else{ + return false; + } + } + + /** + * @brief delete a group + * @param $gid gid of the group to delete + * @returns true/false + * + * Deletes a group and removes it from the group_user-table + */ + public function deleteGroup($gid) { + if(isset($this->groups[$gid])) { + unset($this->groups[$gid]); + return true; + }else{ + return false; + } + } + + /** + * @brief is user in group? + * @param $uid uid of the user + * @param $gid gid of the group + * @returns true/false + * + * Checks whether the user is member of a group or not. + */ + public function inGroup($uid, $gid) { + if(isset($this->groups[$gid])) { + return (array_search($uid, $this->groups[$gid])!==false); + }else{ + return false; + } + } + + /** + * @brief Add a user to a group + * @param $uid Name of the user to add to group + * @param $gid Name of the group in which add the user + * @returns true/false + * + * Adds a user to a group. + */ + public function addToGroup($uid, $gid) { + if(isset($this->groups[$gid])) { + if(array_search($uid, $this->groups[$gid])===false) { + $this->groups[$gid][]=$uid; + return true; + }else{ + return false; + } + }else{ + return false; + } + } + + /** + * @brief Removes a user from a group + * @param $uid NameUSER of the user to remove from group + * @param $gid Name of the group from which remove the user + * @returns true/false + * + * removes the user from a group. + */ + public function removeFromGroup($uid, $gid) { + if(isset($this->groups[$gid])) { + if(($index=array_search($uid, $this->groups[$gid]))!==false) { + unset($this->groups[$gid][$index]); + }else{ + return false; + } + }else{ + return false; + } + } + + /** + * @brief Get all groups a user belongs to + * @param $uid Name of the user + * @returns array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public function getUserGroups($uid) { + $groups=array(); + $allGroups=array_keys($this->groups); + foreach($allGroups as $group) { + if($this->inGroup($uid, $group)) { + $groups[]=$group; + } + } + return $groups; + } + + /** + * @brief get a list of all groups + * @returns array with group names + * + * Returns a list with all groups + */ + public function getGroups($search = '', $limit = -1, $offset = 0) { + return array_keys($this->groups); + } + + /** + * @brief get a list of all users in a group + * @returns array with user ids + */ + public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { + if(isset($this->groups[$gid])) { + return $this->groups[$gid]; + }else{ + return array(); + } + } + +} diff --git a/lib/private/group/example.php b/lib/private/group/example.php new file mode 100644 index 00000000000..3519b9ed92f --- /dev/null +++ b/lib/private/group/example.php @@ -0,0 +1,109 @@ +. +* +*/ + +/** + * abstract reference class for group management + * this class should only be used as a reference for method signatures and their descriptions + */ +abstract class OC_Group_Example { + /** + * @brief Try to create a new group + * @param $gid The name of the group to create + * @returns true/false + * + * Trys to create a new group. If the group name already exists, false will + * be returned. + */ + abstract public static function createGroup($gid); + + /** + * @brief delete a group + * @param $gid gid of the group to delete + * @returns true/false + * + * Deletes a group and removes it from the group_user-table + */ + abstract public static function deleteGroup($gid); + + /** + * @brief is user in group? + * @param $uid uid of the user + * @param $gid gid of the group + * @returns true/false + * + * Checks whether the user is member of a group or not. + */ + abstract public static function inGroup($uid, $gid); + + /** + * @brief Add a user to a group + * @param $uid Name of the user to add to group + * @param $gid Name of the group in which add the user + * @returns true/false + * + * Adds a user to a group. + */ + abstract public static function addToGroup($uid, $gid); + + /** + * @brief Removes a user from a group + * @param $uid NameUSER of the user to remove from group + * @param $gid Name of the group from which remove the user + * @returns true/false + * + * removes the user from a group. + */ + abstract public static function removeFromGroup($uid, $gid); + + /** + * @brief Get all groups a user belongs to + * @param $uid Name of the user + * @returns array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + abstract public static function getUserGroups($uid); + + /** + * @brief get a list of all groups + * @returns array with group names + * + * Returns a list with all groups + */ + abstract public static function getGroups($search = '', $limit = -1, $offset = 0); + + /** + * check if a group exists + * @param string $gid + * @return bool + */ + abstract public function groupExists($gid); + + /** + * @brief get a list of all users in a group + * @returns array with user ids + */ + abstract public static function usersInGroup($gid, $search = '', $limit = -1, $offset = 0); + +} diff --git a/lib/private/group/group.php b/lib/private/group/group.php new file mode 100644 index 00000000000..bcd2419b309 --- /dev/null +++ b/lib/private/group/group.php @@ -0,0 +1,248 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Group; + +class Group { + /** + * @var string $id + */ + private $gid; + + /** + * @var \OC\User\User[] $users + */ + private $users; + + /** + * @var \OC_Group_Backend[] | \OC_Group_Database[] $backend + */ + private $backends; + + /** + * @var \OC\Hooks\PublicEmitter $emitter; + */ + private $emitter; + + /** + * @var \OC\User\Manager $userManager + */ + private $userManager; + + /** + * @param string $gid + * @param \OC_Group_Backend[] $backends + * @param \OC\User\Manager $userManager + * @param \OC\Hooks\PublicEmitter $emitter + */ + public function __construct($gid, $backends, $userManager, $emitter = null) { + $this->gid = $gid; + $this->backends = $backends; + $this->userManager = $userManager; + $this->emitter = $emitter; + } + + public function getGID() { + return $this->gid; + } + + /** + * get all users in the group + * + * @return \OC\User\User[] + */ + public function getUsers() { + if ($this->users) { + return $this->users; + } + + $userIds = array(); + foreach ($this->backends as $backend) { + $diff = array_diff( + $backend->usersInGroup($this->gid), + $userIds + ); + if ($diff) { + $userIds = array_merge($userIds, $diff); + } + } + + $this->users = $this->getVerifiedUsers($userIds); + return $this->users; + } + + /** + * check if a user is in the group + * + * @param \OC\User\User $user + * @return bool + */ + public function inGroup($user) { + foreach ($this->backends as $backend) { + if ($backend->inGroup($user->getUID(), $this->gid)) { + return true; + } + } + return false; + } + + /** + * add a user to the group + * + * @param \OC\User\User $user + */ + public function addUser($user) { + if ($this->inGroup($user)) { + return; + } + + if ($this->emitter) { + $this->emitter->emit('\OC\Group', 'preAddUser', array($this, $user)); + } + foreach ($this->backends as $backend) { + if ($backend->implementsActions(OC_GROUP_BACKEND_ADD_TO_GROUP)) { + $backend->addToGroup($user->getUID(), $this->gid); + if ($this->users) { + $this->users[$user->getUID()] = $user; + } + if ($this->emitter) { + $this->emitter->emit('\OC\Group', 'postAddUser', array($this, $user)); + } + return; + } + } + } + + /** + * remove a user from the group + * + * @param \OC\User\User $user + */ + public function removeUser($user) { + $result = false; + if ($this->emitter) { + $this->emitter->emit('\OC\Group', 'preRemoveUser', array($this, $user)); + } + foreach ($this->backends as $backend) { + if ($backend->implementsActions(OC_GROUP_BACKEND_REMOVE_FROM_GOUP) and $backend->inGroup($user->getUID(), $this->gid)) { + $backend->removeFromGroup($user->getUID(), $this->gid); + $result = true; + } + } + if ($result) { + if ($this->emitter) { + $this->emitter->emit('\OC\Group', 'postRemoveUser', array($this, $user)); + } + if ($this->users) { + foreach ($this->users as $index => $groupUser) { + if ($groupUser->getUID() === $user->getUID()) { + unset($this->users[$index]); + return; + } + } + } + } + } + + /** + * search for users in the group by userid + * + * @param string $search + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function searchUsers($search, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset); + if (!is_null($limit)) { + $limit -= count($userIds); + } + if (!is_null($offset)) { + $offset -= count($userIds); + } + $users += $this->getVerifiedUsers($userIds); + if (!is_null($limit) and $limit <= 0) { + return array_values($users); + } + } + return array_values($users); + } + + /** + * search for users in the group by displayname + * + * @param string $search + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function searchDisplayName($search, $limit = null, $offset = null) { + foreach ($this->backends as $backend) { + if ($backend->implementsActions(OC_GROUP_BACKEND_GET_DISPLAYNAME)) { + $userIds = array_keys($backend->displayNamesInGroup($this->gid, $search, $limit, $offset)); + } else { + $userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset); + } + if (!is_null($limit)) { + $limit -= count($userIds); + } + if (!is_null($offset)) { + $offset -= count($userIds); + } + $users = $this->getVerifiedUsers($userIds); + if (!is_null($limit) and $limit <= 0) { + return array_values($users); + } + } + return array_values($users); + } + + /** + * delete the group + * + * @return bool + */ + public function delete() { + $result = false; + if ($this->emitter) { + $this->emitter->emit('\OC\Group', 'preDelete', array($this)); + } + foreach ($this->backends as $backend) { + if ($backend->implementsActions(OC_GROUP_BACKEND_DELETE_GROUP)) { + $result = true; + $backend->deleteGroup($this->gid); + } + } + if ($result and $this->emitter) { + $this->emitter->emit('\OC\Group', 'postDelete', array($this)); + } + return $result; + } + + /** + * @brief returns all the Users from an array that really exists + * @param $userIds an array containing user IDs + * @return an Array with the userId as Key and \OC\User\User as value + */ + private function getVerifiedUsers($userIds) { + if(!is_array($userIds)) { + return array(); + } + $users = array(); + foreach ($userIds as $userId) { + $user = $this->userManager->get($userId); + if(!is_null($user)) { + $users[$userId] = $user; + } + } + return $users; + } +} diff --git a/lib/private/group/interface.php b/lib/private/group/interface.php new file mode 100644 index 00000000000..4ef3663837f --- /dev/null +++ b/lib/private/group/interface.php @@ -0,0 +1,83 @@ +. + * + */ + +interface OC_Group_Interface { + /** + * @brief Check if backend implements actions + * @param int $actions bitwise-or'ed actions + * @return boolean + * + * Returns the supported actions as int to be + * compared with OC_GROUP_BACKEND_CREATE_GROUP etc. + */ + public function implementsActions($actions); + + /** + * @brief is user in group? + * @param string $uid uid of the user + * @param string $gid gid of the group + * @return bool + * + * Checks whether the user is member of a group or not. + */ + public function inGroup($uid, $gid); + + /** + * @brief Get all groups a user belongs to + * @param string $uid Name of the user + * @return array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public function getUserGroups($uid); + + /** + * @brief get a list of all groups + * @param string $search + * @param int $limit + * @param int $offset + * @return array with group names + * + * Returns a list with all groups + */ + public function getGroups($search = '', $limit = -1, $offset = 0); + + /** + * check if a group exists + * @param string $gid + * @return bool + */ + public function groupExists($gid); + + /** + * @brief get a list of all users in a group + * @param string $gid + * @param string $search + * @param int $limit + * @param int $offset + * @return array with user ids + */ + public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0); + +} diff --git a/lib/private/group/manager.php b/lib/private/group/manager.php new file mode 100644 index 00000000000..bf469d51d12 --- /dev/null +++ b/lib/private/group/manager.php @@ -0,0 +1,169 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Group; + +use OC\Hooks\PublicEmitter; + +/** + * Class Manager + * + * Hooks available in scope \OC\Group: + * - preAddUser(\OC\Group\Group $group, \OC\User\User $user) + * - postAddUser(\OC\Group\Group $group, \OC\User\User $user) + * - preRemoveUser(\OC\Group\Group $group, \OC\User\User $user) + * - postRemoveUser(\OC\Group\Group $group, \OC\User\User $user) + * - preDelete(\OC\Group\Group $group) + * - postDelete(\OC\Group\Group $group) + * - preCreate(string $groupId) + * - postCreate(\OC\Group\Group $group) + * + * @package OC\Group + */ +class Manager extends PublicEmitter { + /** + * @var \OC_Group_Backend[] | \OC_Group_Database[] $backends + */ + private $backends = array(); + + /** + * @var \OC\User\Manager $userManager + */ + private $userManager; + + /** + * @var \OC\Group\Group[] + */ + private $cachedGroups; + + /** + * @param \OC\User\Manager $userManager + */ + public function __construct($userManager) { + $this->userManager = $userManager; + $cache = & $this->cachedGroups; + $this->listen('\OC\Group', 'postDelete', function ($group) use (&$cache) { + /** + * @var \OC\Group\Group $group + */ + unset($cache[$group->getGID()]); + }); + } + + /** + * @param \OC_Group_Backend $backend + */ + public function addBackend($backend) { + $this->backends[] = $backend; + } + + public function clearBackends() { + $this->backends = array(); + $this->cachedGroups = array(); + } + + /** + * @param string $gid + * @return \OC\Group\Group + */ + public function get($gid) { + if (isset($this->cachedGroups[$gid])) { + return $this->cachedGroups[$gid]; + } + foreach ($this->backends as $backend) { + if ($backend->groupExists($gid)) { + return $this->getGroupObject($gid); + } + } + return null; + } + + protected function getGroupObject($gid) { + $backends = array(); + foreach ($this->backends as $backend) { + if ($backend->groupExists($gid)) { + $backends[] = $backend; + } + } + $this->cachedGroups[$gid] = new Group($gid, $backends, $this->userManager, $this); + return $this->cachedGroups[$gid]; + } + + /** + * @param string $gid + * @return bool + */ + public function groupExists($gid) { + return !is_null($this->get($gid)); + } + + /** + * @param string $gid + * @return \OC\Group\Group + */ + public function createGroup($gid) { + if (!$gid) { + return false; + } else if ($this->groupExists($gid)) { + return $this->get($gid); + } else { + $this->emit('\OC\Group', 'preCreate', array($gid)); + foreach ($this->backends as $backend) { + if ($backend->implementsActions(OC_GROUP_BACKEND_CREATE_GROUP)) { + $backend->createGroup($gid); + $group = $this->getGroupObject($gid); + $this->emit('\OC\Group', 'postCreate', array($group)); + return $group; + } + } + return null; + } + } + + /** + * @param string $search + * @param int $limit + * @param int $offset + * @return \OC\Group\Group[] + */ + public function search($search, $limit = null, $offset = null) { + $groups = array(); + foreach ($this->backends as $backend) { + $groupIds = $backend->getGroups($search, $limit, $offset); + if (!is_null($limit)) { + $limit -= count($groupIds); + } + if (!is_null($offset)) { + $offset -= count($groupIds); + } + foreach ($groupIds as $groupId) { + $groups[$groupId] = $this->getGroupObject($groupId); + } + if (!is_null($limit) and $limit <= 0) { + return array_values($groups); + } + } + return array_values($groups); + } + + /** + * @param \OC\User\User $user + * @return \OC\Group\Group[] + */ + public function getUserGroups($user) { + $groups = array(); + foreach ($this->backends as $backend) { + $groupIds = $backend->getUserGroups($user->getUID()); + foreach ($groupIds as $groupId) { + $groups[$groupId] = $this->getGroupObject($groupId); + } + } + return array_values($groups); + } +} diff --git a/lib/private/helper.php b/lib/private/helper.php new file mode 100644 index 00000000000..66e7acb407a --- /dev/null +++ b/lib/private/helper.php @@ -0,0 +1,934 @@ +. + * + */ + +/** + * Collection of useful functions + */ +class OC_Helper { + private static $tmpFiles = array(); + private static $mimetypeIcons = array(); + private static $mimetypeDetector; + private static $templateManager; + + /** + * @brief Creates an url using a defined route + * @param $route + * @param array $parameters + * @return + * @internal param array $args with param=>value, will be appended to the returned url + * @returns the url + * + * Returns a url to the given app and file. + */ + public static function linkToRoute($route, $parameters = array()) { + $urlLinkTo = OC::getRouter()->generate($route, $parameters); + return $urlLinkTo; + } + + /** + * @brief Creates an url + * @param string $app app + * @param string $file file + * @param array $args array with param=>value, will be appended to the returned url + * The value of $args will be urlencoded + * @return string the url + * + * Returns a url to the given app and file. + */ + public static function linkTo( $app, $file, $args = array() ) { + if( $app != '' ) { + $app_path = OC_App::getAppPath($app); + // Check if the app is in the app folder + if ($app_path && file_exists($app_path . '/' . $file)) { + if (substr($file, -3) == 'php' || substr($file, -3) == 'css') { + $urlLinkTo = OC::$WEBROOT . '/index.php/apps/' . $app; + $urlLinkTo .= ($file != 'index.php') ? '/' . $file : ''; + } else { + $urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file; + } + } else { + $urlLinkTo = OC::$WEBROOT . '/' . $app . '/' . $file; + } + } else { + if (file_exists(OC::$SERVERROOT . '/core/' . $file)) { + $urlLinkTo = OC::$WEBROOT . '/core/' . $file; + } else { + $urlLinkTo = OC::$WEBROOT . '/' . $file; + } + } + + if ($args && $query = http_build_query($args, '', '&')) { + $urlLinkTo .= '?' . $query; + } + + return $urlLinkTo; + } + + /** + * @brief Creates an absolute url + * @param string $app app + * @param string $file file + * @param array $args array with param=>value, will be appended to the returned url + * The value of $args will be urlencoded + * @return string the url + * + * Returns a absolute url to the given app and file. + */ + public static function linkToAbsolute($app, $file, $args = array()) { + $urlLinkTo = self::linkTo($app, $file, $args); + return self::makeURLAbsolute($urlLinkTo); + } + + /** + * @brief Makes an $url absolute + * @param string $url the url + * @return string the absolute url + * + * Returns a absolute url to the given app and file. + */ + public static function makeURLAbsolute($url) { + return OC_Request::serverProtocol() . '://' . OC_Request::serverHost() . $url; + } + + /** + * @brief Creates an url for remote use + * @param string $service id + * @return string the url + * + * Returns a url to the given service. + */ + public static function linkToRemoteBase($service) { + return self::linkTo('', 'remote.php') . '/' . $service; + } + + /** + * @brief Creates an absolute url for remote use + * @param string $service id + * @param bool $add_slash + * @return string the url + * + * Returns a absolute url to the given service. + */ + public static function linkToRemote($service, $add_slash = true) { + return self::makeURLAbsolute(self::linkToRemoteBase($service)) + . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); + } + + /** + * @brief Creates an absolute url for public use + * @param string $service id + * @param bool $add_slash + * @return string the url + * + * Returns a absolute url to the given service. + */ + public static function linkToPublic($service, $add_slash = false) { + return self::linkToAbsolute('', 'public.php') . '?service=' . $service + . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); + } + + /** + * @brief Creates path to an image + * @param string $app app + * @param string $image image name + * @return string the url + * + * Returns the path to the image. + */ + public static function imagePath($app, $image) { + // Read the selected theme from the config file + $theme = OC_Util::getTheme(); + + // Check if the app is in the app folder + if (file_exists(OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$image")) { + return OC::$WEBROOT . "/themes/$theme/apps/$app/img/$image"; + } elseif (file_exists(OC_App::getAppPath($app) . "/img/$image")) { + return OC_App::getAppWebPath($app) . "/img/$image"; + } elseif (!empty($app) and file_exists(OC::$SERVERROOT . "/themes/$theme/$app/img/$image")) { + return OC::$WEBROOT . "/themes/$theme/$app/img/$image"; + } elseif (!empty($app) and file_exists(OC::$SERVERROOT . "/$app/img/$image")) { + return OC::$WEBROOT . "/$app/img/$image"; + } elseif (file_exists(OC::$SERVERROOT . "/themes/$theme/core/img/$image")) { + return OC::$WEBROOT . "/themes/$theme/core/img/$image"; + } elseif (file_exists(OC::$SERVERROOT . "/core/img/$image")) { + return OC::$WEBROOT . "/core/img/$image"; + } else { + throw new RuntimeException('image not found: image:' . $image . ' webroot:' . OC::$WEBROOT . ' serverroot:' . OC::$SERVERROOT); + } + } + + /** + * @brief get path to icon of file type + * @param string $mimetype mimetype + * @return string the url + * + * Returns the path to the image of this file type. + */ + public static function mimetypeIcon($mimetype) { + $alias = array( + 'application/xml' => 'code/xml', + 'application/msword' => 'x-office/document', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'x-office/document', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'x-office/document', + 'application/vnd.ms-word.document.macroEnabled.12' => 'x-office/document', + 'application/vnd.ms-word.template.macroEnabled.12' => 'x-office/document', + 'application/vnd.oasis.opendocument.text' => 'x-office/document', + 'application/vnd.oasis.opendocument.text-template' => 'x-office/document', + 'application/vnd.oasis.opendocument.text-web' => 'x-office/document', + 'application/vnd.oasis.opendocument.text-master' => 'x-office/document', + 'application/vnd.ms-powerpoint' => 'x-office/presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'x-office/presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.addin.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.template.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation', + 'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation', + 'application/vnd.ms-excel' => 'x-office/spreadsheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.sheet.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.template.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.addin.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet', + ); + + if (isset($alias[$mimetype])) { + $mimetype = $alias[$mimetype]; + } + if (isset(self::$mimetypeIcons[$mimetype])) { + return self::$mimetypeIcons[$mimetype]; + } + // Replace slash and backslash with a minus + $icon = str_replace('/', '-', $mimetype); + $icon = str_replace('\\', '-', $icon); + + // Is it a dir? + if ($mimetype === 'dir') { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder.png'; + return OC::$WEBROOT . '/core/img/filetypes/folder.png'; + } + if ($mimetype === 'dir-shared') { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-shared.png'; + return OC::$WEBROOT . '/core/img/filetypes/folder-shared.png'; + } + if ($mimetype === 'dir-external') { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-external.png'; + return OC::$WEBROOT . '/core/img/filetypes/folder-external.png'; + } + + // Icon exists? + if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $icon . '.png')) { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png'; + return OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png'; + } + + // Try only the first part of the filetype + $mimePart = substr($icon, 0, strpos($icon, '-')); + if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $mimePart . '.png')) { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png'; + return OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png'; + } else { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/file.png'; + return OC::$WEBROOT . '/core/img/filetypes/file.png'; + } + } + + /** + * @brief get path to preview of file + * @param string $path path + * @return string the url + * + * Returns the path to the preview of the file. + */ + public static function previewIcon($path) { + return self::linkToRoute( 'core_ajax_preview', array('x' => 36, 'y' => 36, 'file' => urlencode($path) )); + } + + public static function publicPreviewIcon( $path, $token ) { + return self::linkToRoute( 'core_ajax_public_preview', array('x' => 36, 'y' => 36, 'file' => urlencode($path), 't' => $token)); + } + + /** + * @brief Make a human file size + * @param int $bytes file size in bytes + * @return string a human readable file size + * + * Makes 2048 to 2 kB. + */ + public static function humanFileSize($bytes) { + if ($bytes < 0) { + return "?"; + } + if ($bytes < 1024) { + return "$bytes B"; + } + $bytes = round($bytes / 1024, 1); + if ($bytes < 1024) { + return "$bytes kB"; + } + $bytes = round($bytes / 1024, 1); + if ($bytes < 1024) { + return "$bytes MB"; + } + $bytes = round($bytes / 1024, 1); + if ($bytes < 1024) { + return "$bytes GB"; + } + $bytes = round($bytes / 1024, 1); + if ($bytes < 1024) { + return "$bytes TB"; + } + + $bytes = round($bytes / 1024, 1); + return "$bytes PB"; + } + + /** + * @brief Make a computer file size + * @param string $str file size in a fancy format + * @return int a file size in bytes + * + * Makes 2kB to 2048. + * + * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418 + */ + public static function computerFileSize($str) { + $str = strtolower($str); + + $bytes_array = array( + 'b' => 1, + 'k' => 1024, + 'kb' => 1024, + 'mb' => 1024 * 1024, + 'm' => 1024 * 1024, + 'gb' => 1024 * 1024 * 1024, + 'g' => 1024 * 1024 * 1024, + 'tb' => 1024 * 1024 * 1024 * 1024, + 't' => 1024 * 1024 * 1024 * 1024, + 'pb' => 1024 * 1024 * 1024 * 1024 * 1024, + 'p' => 1024 * 1024 * 1024 * 1024 * 1024, + ); + + $bytes = floatval($str); + + if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) { + $bytes *= $bytes_array[$matches[1]]; + } + + $bytes = round($bytes, 2); + + return $bytes; + } + + /** + * @brief Recursive editing of file permissions + * @param string $path path to file or folder + * @param int $filemode unix style file permissions + * @return bool + */ + static function chmodr($path, $filemode) { + if (!is_dir($path)) + return chmod($path, $filemode); + $dh = opendir($path); + if(is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if ($file != '.' && $file != '..') { + $fullpath = $path . '/' . $file; + if (is_link($fullpath)) + return false; + elseif (!is_dir($fullpath) && !@chmod($fullpath, $filemode)) + return false; elseif (!self::chmodr($fullpath, $filemode)) + return false; + } + } + closedir($dh); + } + if (@chmod($path, $filemode)) + return true; + else + return false; + } + + /** + * @brief Recursive copying of folders + * @param string $src source folder + * @param string $dest target folder + * + */ + static function copyr($src, $dest) { + if (is_dir($src)) { + if (!is_dir($dest)) { + mkdir($dest); + } + $files = scandir($src); + foreach ($files as $file) { + if ($file != "." && $file != "..") { + self::copyr("$src/$file", "$dest/$file"); + } + } + } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) { + copy($src, $dest); + } + } + + /** + * @brief Recursive deletion of folders + * @param string $dir path to the folder + * @return bool + */ + static function rmdirr($dir) { + if (is_dir($dir)) { + $files = scandir($dir); + foreach ($files as $file) { + if ($file != "." && $file != "..") { + self::rmdirr("$dir/$file"); + } + } + rmdir($dir); + } elseif (file_exists($dir)) { + unlink($dir); + } + if (file_exists($dir)) { + return false; + } else { + return true; + } + } + + /** + * @return \OC\Files\Type\Detection + */ + static public function getMimetypeDetector() { + if (!self::$mimetypeDetector) { + self::$mimetypeDetector = new \OC\Files\Type\Detection(); + self::$mimetypeDetector->registerTypeArray(include 'mimetypes.list.php'); + } + return self::$mimetypeDetector; + } + + /** + * @return \OC\Files\Type\TemplateManager + */ + static public function getFileTemplateManager() { + if (!self::$templateManager) { + self::$templateManager = new \OC\Files\Type\TemplateManager(); + } + return self::$templateManager; + } + + /** + * Try to guess the mimetype based on filename + * + * @param string $path + * @return string + */ + static public function getFileNameMimeType($path) { + return self::getMimetypeDetector()->detectPath($path); + } + + /** + * get the mimetype form a local file + * + * @param string $path + * @return string + * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead + */ + static function getMimeType($path) { + return self::getMimetypeDetector()->detect($path); + } + + /** + * get the mimetype form a data string + * + * @param string $data + * @return string + */ + static function getStringMimeType($data) { + return self::getMimetypeDetector()->detectString($data); + } + + /** + * @brief Checks $_REQUEST contains a var for the $s key. If so, returns the html-escaped value of this var; otherwise returns the default value provided by $d. + * @param string $s name of the var to escape, if set. + * @param string $d default value. + * @return string the print-safe value. + * + */ + + //FIXME: should also check for value validation (i.e. the email is an email). + public static function init_var($s, $d = "") { + $r = $d; + if (isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) { + $r = OC_Util::sanitizeHTML($_REQUEST[$s]); + } + + return $r; + } + + /** + * returns "checked"-attribute if request contains selected radio element + * OR if radio element is the default one -- maybe? + * + * @param string $s Name of radio-button element name + * @param string $v Value of current radio-button element + * @param string $d Value of default radio-button element + */ + public static function init_radio($s, $v, $d) { + if ((isset($_REQUEST[$s]) && $_REQUEST[$s] == $v) || (!isset($_REQUEST[$s]) && $v == $d)) + print "checked=\"checked\" "; + } + + /** + * detect if a given program is found in the search PATH + * + * @param $name + * @param bool $path + * @internal param string $program name + * @internal param string $optional search path, defaults to $PATH + * @return bool true if executable program found in path + */ + public static function canExecute($name, $path = false) { + // path defaults to PATH from environment if not set + if ($path === false) { + $path = getenv("PATH"); + } + // check method depends on operating system + if (!strncmp(PHP_OS, "WIN", 3)) { + // on Windows an appropriate COM or EXE file needs to exist + $exts = array(".exe", ".com"); + $check_fn = "file_exists"; + } else { + // anywhere else we look for an executable file of that name + $exts = array(""); + $check_fn = "is_executable"; + } + // Default check will be done with $path directories : + $dirs = explode(PATH_SEPARATOR, $path); + // WARNING : We have to check if open_basedir is enabled : + $obd = ini_get('open_basedir'); + if ($obd != "none") { + $obd_values = explode(PATH_SEPARATOR, $obd); + if (count($obd_values) > 0 and $obd_values[0]) { + // open_basedir is in effect ! + // We need to check if the program is in one of these dirs : + $dirs = $obd_values; + } + } + foreach ($dirs as $dir) { + foreach ($exts as $ext) { + if ($check_fn("$dir/$name" . $ext)) + return true; + } + } + return false; + } + + /** + * copy the contents of one stream to another + * + * @param resource $source + * @param resource $target + * @return int the number of bytes copied + */ + public static function streamCopy($source, $target) { + if (!$source or !$target) { + return false; + } + $result = true; + $count = 0; + while (!feof($source)) { + if (($c = fwrite($target, fread($source, 8192))) === false) { + $result = false; + } else { + $count += $c; + } + } + return array($count, $result); + } + + /** + * create a temporary file with an unique filename + * + * @param string $postfix + * @return string + * + * temporary files are automatically cleaned up after the script is finished + */ + public static function tmpFile($postfix = '') { + $file = get_temp_dir() . '/' . md5(time() . rand()) . $postfix; + $fh = fopen($file, 'w'); + fclose($fh); + self::$tmpFiles[] = $file; + return $file; + } + + /** + * move a file to oc-noclean temp dir + * + * @param string $filename + * @return mixed + * + */ + public static function moveToNoClean($filename = '') { + if ($filename == '') { + return false; + } + $tmpDirNoClean = get_temp_dir() . '/oc-noclean/'; + if (!file_exists($tmpDirNoClean) || !is_dir($tmpDirNoClean)) { + if (file_exists($tmpDirNoClean)) { + unlink($tmpDirNoClean); + } + mkdir($tmpDirNoClean); + } + $newname = $tmpDirNoClean . basename($filename); + if (rename($filename, $newname)) { + return $newname; + } else { + return false; + } + } + + /** + * create a temporary folder with an unique filename + * + * @return string + * + * temporary files are automatically cleaned up after the script is finished + */ + public static function tmpFolder() { + $path = get_temp_dir() . '/' . md5(time() . rand()); + mkdir($path); + self::$tmpFiles[] = $path; + return $path . '/'; + } + + /** + * remove all files created by self::tmpFile + */ + public static function cleanTmp() { + $leftoversFile = get_temp_dir() . '/oc-not-deleted'; + if (file_exists($leftoversFile)) { + $leftovers = file($leftoversFile); + foreach ($leftovers as $file) { + self::rmdirr($file); + } + unlink($leftoversFile); + } + + foreach (self::$tmpFiles as $file) { + if (file_exists($file)) { + if (!self::rmdirr($file)) { + file_put_contents($leftoversFile, $file . "\n", FILE_APPEND); + } + } + } + } + + /** + * remove all files in PHP /oc-noclean temp dir + */ + public static function cleanTmpNoClean() { + $tmpDirNoCleanName=get_temp_dir() . '/oc-noclean/'; + if(file_exists($tmpDirNoCleanName) && is_dir($tmpDirNoCleanName)) { + $files=scandir($tmpDirNoCleanName); + foreach($files as $file) { + $fileName = $tmpDirNoCleanName . $file; + if (!\OC\Files\Filesystem::isIgnoredDir($file) && filemtime($fileName) + 600 < time()) { + unlink($fileName); + } + } + // if oc-noclean is empty delete it + $isTmpDirNoCleanEmpty = true; + $tmpDirNoClean = opendir($tmpDirNoCleanName); + if(is_resource($tmpDirNoClean)) { + while (false !== ($file = readdir($tmpDirNoClean))) { + if (!\OC\Files\Filesystem::isIgnoredDir($file)) { + $isTmpDirNoCleanEmpty = false; + } + } + } + if ($isTmpDirNoCleanEmpty) { + rmdir($tmpDirNoCleanName); + } + } + } + + /** + * Adds a suffix to the name in case the file exists + * + * @param $path + * @param $filename + * @return string + */ + public static function buildNotExistingFileName($path, $filename) { + $view = \OC\Files\Filesystem::getView(); + return self::buildNotExistingFileNameForView($path, $filename, $view); + } + + /** + * Adds a suffix to the name in case the file exists + * + * @param $path + * @param $filename + * @return string + */ + public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) { + if ($path === '/') { + $path = ''; + } + if ($pos = strrpos($filename, '.')) { + $name = substr($filename, 0, $pos); + $ext = substr($filename, $pos); + } else { + $name = $filename; + $ext = ''; + } + + $newpath = $path . '/' . $filename; + if ($view->file_exists($newpath)) { + if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) { + //Replace the last "(number)" with "(number+1)" + $last_match = count($matches[0]) - 1; + $counter = $matches[1][$last_match][0] + 1; + $offset = $matches[0][$last_match][1]; + $match_length = strlen($matches[0][$last_match][0]); + } else { + $counter = 2; + $offset = false; + } + do { + if ($offset) { + //Replace the last "(number)" with "(number+1)" + $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length); + } else { + $newname = $name . ' (' . $counter . ')'; + } + $newpath = $path . '/' . $newname . $ext; + $counter++; + } while ($view->file_exists($newpath)); + } + + return $newpath; + } + + /** + * @brief Checks if $sub is a subdirectory of $parent + * + * @param string $sub + * @param string $parent + * @return bool + */ + public static function issubdirectory($sub, $parent) { + if (strpos(realpath($sub), realpath($parent)) === 0) { + return true; + } + return false; + } + + /** + * @brief Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. + * + * @param array $input The array to work on + * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @return array + * + * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. + * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715 + * + */ + public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') { + $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER; + $ret = array(); + foreach ($input as $k => $v) { + $ret[mb_convert_case($k, $case, $encoding)] = $v; + } + return $ret; + } + + /** + * @brief replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement. + * + * @param $string + * @param string $replacement The replacement string. + * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string. + * @param int $length Length of the part to be replaced + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @internal param string $input The input string. .Opposite to the PHP build-in function does not accept an array. + * @return string + */ + public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') { + $start = intval($start); + $length = intval($length); + $string = mb_substr($string, 0, $start, $encoding) . + $replacement . + mb_substr($string, $start + $length, mb_strlen($string, 'UTF-8') - $start, $encoding); + + return $string; + } + + /** + * @brief Replace all occurrences of the search string with the replacement string + * + * @param string $search The value being searched for, otherwise known as the needle. + * @param string $replace The replacement + * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack. + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @param int $count If passed, this will be set to the number of replacements performed. + * @return string + * + */ + public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) { + $offset = -1; + $length = mb_strlen($search, $encoding); + while (($i = mb_strrpos($subject, $search, $offset, $encoding)) !== false) { + $subject = OC_Helper::mb_substr_replace($subject, $replace, $i, $length); + $offset = $i - mb_strlen($subject, $encoding); + $count++; + } + return $subject; + } + + /** + * @brief performs a search in a nested array + * @param array $haystack the array to be searched + * @param string $needle the search string + * @param string $index optional, only search this key name + * @return mixed the key of the matching field, otherwise false + * + * performs a search in a nested array + * + * taken from http://www.php.net/manual/en/function.array-search.php#97645 + */ + public static function recursiveArraySearch($haystack, $needle, $index = null) { + $aIt = new RecursiveArrayIterator($haystack); + $it = new RecursiveIteratorIterator($aIt); + + while ($it->valid()) { + if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) { + return $aIt->key(); + } + + $it->next(); + } + + return false; + } + + /** + * Shortens str to maxlen by replacing characters in the middle with '...', eg. + * ellipsis('a very long string with lots of useless info to make a better example', 14) becomes 'a very ...example' + * + * @param string $str the string + * @param string $maxlen the maximum length of the result + * @return string with at most maxlen characters + */ + public static function ellipsis($str, $maxlen) { + if (strlen($str) > $maxlen) { + $characters = floor($maxlen / 2); + return substr($str, 0, $characters) . '...' . substr($str, -1 * $characters); + } + return $str; + } + + /** + * @brief calculates the maximum upload size respecting system settings, free space and user quota + * + * @param $dir the current folder where the user currently operates + * @return number of bytes representing + */ + public static function maxUploadFilesize($dir) { + $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); + $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); + $freeSpace = \OC\Files\Filesystem::free_space($dir); + if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { + $maxUploadFilesize = \OC\Files\SPACE_UNLIMITED; + } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { + $maxUploadFilesize = max($upload_max_filesize, $post_max_size); //only the non 0 value counts + } else { + $maxUploadFilesize = min($upload_max_filesize, $post_max_size); + } + + if ($freeSpace !== \OC\Files\SPACE_UNKNOWN) { + $freeSpace = max($freeSpace, 0); + + return min($maxUploadFilesize, $freeSpace); + } else { + return $maxUploadFilesize; + } + } + + /** + * Checks if a function is available + * + * @param string $function_name + * @return bool + */ + public static function is_function_enabled($function_name) { + if (!function_exists($function_name)) { + return false; + } + $disabled = explode(', ', ini_get('disable_functions')); + if (in_array($function_name, $disabled)) { + return false; + } + $disabled = explode(', ', ini_get('suhosin.executor.func.blacklist')); + if (in_array($function_name, $disabled)) { + return false; + } + return true; + } + + /** + * Calculate the disc space for the given path + * + * @param string $path + * @return array + */ + public static function getStorageInfo($path) { + $rootInfo = \OC\Files\Filesystem::getFileInfo($path); + $used = $rootInfo['size']; + if ($used < 0) { + $used = 0; + } + $free = \OC\Files\Filesystem::free_space($path); + if ($free >= 0) { + $total = $free + $used; + } else { + $total = $free; //either unknown or unlimited + } + if ($total > 0) { + // prevent division by zero or error codes (negative values) + $relative = round(($used / $total) * 10000) / 100; + } else { + $relative = 0; + } + + return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); + } +} diff --git a/lib/private/hintexception.php b/lib/private/hintexception.php new file mode 100644 index 00000000000..3934ae2a4c2 --- /dev/null +++ b/lib/private/hintexception.php @@ -0,0 +1,27 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +class HintException extends \Exception { + + private $hint; + + public function __construct($message, $hint = '', $code = 0, Exception $previous = null) { + $this->hint = $hint; + parent::__construct($message, $code, $previous); + } + + public function __toString() { + return __CLASS__ . ": [{$this->code}]: {$this->message} ({$this->hint})\n"; + } + + public function getHint() { + return $this->hint; + } +} diff --git a/lib/private/hook.php b/lib/private/hook.php new file mode 100644 index 00000000000..8516cf0dcff --- /dev/null +++ b/lib/private/hook.php @@ -0,0 +1,100 @@ + $slotclass, + "name" => $slotname + ); + + // No chance for failure ;-) + return true; + } + + /** + * @brief emits a signal + * @param string $signalclass class name of emitter + * @param string $signalname name of signal + * @param array $params defautl: array() array with additional data + * @return bool, true if slots exists or false if not + * + * Emits a signal. To get data from the slot use references! + * + * TODO: write example + */ + static public function emit( $signalclass, $signalname, $params = array()) { + + // Return false if no hook handlers are listening to this + // emitting class + if( !array_key_exists( $signalclass, self::$registered )) { + return false; + } + + // Return false if no hook handlers are listening to this + // emitting method + if( !array_key_exists( $signalname, self::$registered[$signalclass] )) { + return false; + } + + // Call all slots + foreach( self::$registered[$signalclass][$signalname] as $i ) { + try { + call_user_func( array( $i["class"], $i["name"] ), $params ); + } catch (Exception $e){ + OC_Log::write('hook', + 'error while running hook (' . $i["class"] . '::' . $i["name"] . '): '.$e->getMessage(), + OC_Log::ERROR); + } + } + + // return true + return true; + } + + /** + * clear hooks + * @param string $signalclass + * @param string $signalname + */ + static public function clear($signalclass='', $signalname='') { + if($signalclass) { + if($signalname) { + self::$registered[$signalclass][$signalname]=array(); + }else{ + self::$registered[$signalclass]=array(); + } + }else{ + self::$registered=array(); + } + } +} diff --git a/lib/private/hooks/basicemitter.php b/lib/private/hooks/basicemitter.php new file mode 100644 index 00000000000..9ffe1af2314 --- /dev/null +++ b/lib/private/hooks/basicemitter.php @@ -0,0 +1,89 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Hooks; + +abstract class BasicEmitter implements Emitter { + + /** + * @var (callable[])[] $listeners + */ + protected $listeners = array(); + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback) { + $eventName = $scope . '::' . $method; + if (!isset($this->listeners[$eventName])) { + $this->listeners[$eventName] = array(); + } + if (array_search($callback, $this->listeners[$eventName]) === false) { + $this->listeners[$eventName][] = $callback; + } + } + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, $callback = null) { + $names = array(); + $allNames = array_keys($this->listeners); + if ($scope and $method) { + $name = $scope . '::' . $method; + if (isset($this->listeners[$name])) { + $names[] = $name; + } + } elseif ($scope) { + foreach ($allNames as $name) { + $parts = explode('::', $name, 2); + if ($parts[0] == $scope) { + $names[] = $name; + } + } + } elseif ($method) { + foreach ($allNames as $name) { + $parts = explode('::', $name, 2); + if ($parts[1] == $method) { + $names[] = $name; + } + } + } else { + $names = $allNames; + } + + foreach ($names as $name) { + if ($callback) { + $index = array_search($callback, $this->listeners[$name]); + if ($index !== false) { + unset($this->listeners[$name][$index]); + } + } else { + $this->listeners[$name] = array(); + } + } + } + + /** + * @param string $scope + * @param string $method + * @param array $arguments optional + */ + protected function emit($scope, $method, $arguments = array()) { + $eventName = $scope . '::' . $method; + if (isset($this->listeners[$eventName])) { + foreach ($this->listeners[$eventName] as $callback) { + call_user_func_array($callback, $arguments); + } + } + } +} diff --git a/lib/private/hooks/emitter.php b/lib/private/hooks/emitter.php new file mode 100644 index 00000000000..8e9074bad67 --- /dev/null +++ b/lib/private/hooks/emitter.php @@ -0,0 +1,32 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Hooks; + +/** + * Class Emitter + * + * interface for all classes that are able to emit events + * + * @package OC\Hooks + */ +interface Emitter { + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback); + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, $callback = null); +} diff --git a/lib/private/hooks/forwardingemitter.php b/lib/private/hooks/forwardingemitter.php new file mode 100644 index 00000000000..1aacc4012e0 --- /dev/null +++ b/lib/private/hooks/forwardingemitter.php @@ -0,0 +1,50 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Hooks; + +/** + * Class ForwardingEmitter + * + * allows forwarding all listen calls to other emitters + * + * @package OC\Hooks + */ +abstract class ForwardingEmitter extends BasicEmitter { + /** + * @var \OC\Hooks\Emitter[] array + */ + private $forwardEmitters = array(); + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback) { + parent::listen($scope, $method, $callback); + foreach ($this->forwardEmitters as $emitter) { + $emitter->listen($scope, $method, $callback); + } + } + + /** + * @param \OC\Hooks\Emitter $emitter + */ + protected function forward($emitter) { + $this->forwardEmitters[] = $emitter; + + //forward all previously connected hooks + foreach ($this->listeners as $key => $listeners) { + list($scope, $method) = explode('::', $key, 2); + foreach ($listeners as $listener) { + $emitter->listen($scope, $method, $listener); + } + } + } +} diff --git a/lib/private/hooks/legacyemitter.php b/lib/private/hooks/legacyemitter.php new file mode 100644 index 00000000000..a2d16ace9a7 --- /dev/null +++ b/lib/private/hooks/legacyemitter.php @@ -0,0 +1,16 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Hooks; + +abstract class LegacyEmitter extends BasicEmitter { + protected function emit($scope, $method, $arguments = array()) { + \OC_Hook::emit($scope, $method, $arguments); + parent::emit($scope, $method, $arguments); + } +} diff --git a/lib/private/hooks/publicemitter.php b/lib/private/hooks/publicemitter.php new file mode 100644 index 00000000000..e2371713ac3 --- /dev/null +++ b/lib/private/hooks/publicemitter.php @@ -0,0 +1,20 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Hooks; + +class PublicEmitter extends BasicEmitter { + /** + * @param string $scope + * @param string $method + * @param array $arguments optional + */ + public function emit($scope, $method, $arguments = array()) { + parent::emit($scope, $method, $arguments); + } +} diff --git a/lib/private/image.php b/lib/private/image.php new file mode 100644 index 00000000000..7761a3c7737 --- /dev/null +++ b/lib/private/image.php @@ -0,0 +1,1020 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ +/** + * Class for basic image manipulation + */ +class OC_Image { + protected $resource = false; // tmp resource. + protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident. + protected $mimeType = "image/png"; // Default to png + protected $bitDepth = 24; + protected $filePath = null; + + private $fileInfo; + + /** + * @brief Get mime type for an image file. + * @param $filepath The path to a local image file. + * @returns string The mime type if the it could be determined, otherwise an empty string. + */ + static public function getMimeTypeForFile($filePath) { + // exif_imagetype throws "read error!" if file is less than 12 byte + if (filesize($filePath) > 11) { + $imageType = exif_imagetype($filePath); + } + else { + $imageType = false; + } + return $imageType ? image_type_to_mime_type($imageType) : ''; + } + + /** + * @brief Constructor. + * @param $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function. + * @returns bool False on error + */ + public function __construct($imageRef = null) { + //OC_Log::write('core',__METHOD__.'(): start', OC_Log::DEBUG); + if(!extension_loaded('gd') || !function_exists('gd_info')) { + OC_Log::write('core', __METHOD__.'(): GD module not installed', OC_Log::ERROR); + return false; + } + + if (\OC_Util::fileInfoLoaded()) { + $this->fileInfo = new finfo(FILEINFO_MIME_TYPE); + } + + if(!is_null($imageRef)) { + $this->load($imageRef); + } + } + + /** + * @brief Determine whether the object contains an image resource. + * @returns bool + */ + public function valid() { // apparently you can't name a method 'empty'... + return is_resource($this->resource); + } + + /** + * @brief Returns the MIME type of the image or an empty string if no image is loaded. + * @returns int + */ + public function mimeType() { + return $this->valid() ? $this->mimeType : ''; + } + + /** + * @brief Returns the width of the image or -1 if no image is loaded. + * @returns int + */ + public function width() { + return $this->valid() ? imagesx($this->resource) : -1; + } + + /** + * @brief Returns the height of the image or -1 if no image is loaded. + * @returns int + */ + public function height() { + return $this->valid() ? imagesy($this->resource) : -1; + } + + /** + * @brief Returns the width when the image orientation is top-left. + * @returns int + */ + public function widthTopLeft() { + $o = $this->getOrientation(); + OC_Log::write('core', 'OC_Image->widthTopLeft() Orientation: '.$o, OC_Log::DEBUG); + switch($o) { + case -1: + case 1: + case 2: // Not tested + case 3: + case 4: // Not tested + return $this->width(); + break; + case 5: // Not tested + case 6: + case 7: // Not tested + case 8: + return $this->height(); + break; + } + return $this->width(); + } + + /** + * @brief Returns the height when the image orientation is top-left. + * @returns int + */ + public function heightTopLeft() { + $o = $this->getOrientation(); + OC_Log::write('core', 'OC_Image->heightTopLeft() Orientation: '.$o, OC_Log::DEBUG); + switch($o) { + case -1: + case 1: + case 2: // Not tested + case 3: + case 4: // Not tested + return $this->height(); + break; + case 5: // Not tested + case 6: + case 7: // Not tested + case 8: + return $this->width(); + break; + } + return $this->height(); + } + + /** + * @brief Outputs the image. + * @returns bool + */ + public function show() { + header('Content-Type: '.$this->mimeType()); + return $this->_output(); + } + + /** + * @brief Saves the image. + * @returns bool + */ + + public function save($filePath=null) { + if($filePath === null && $this->filePath === null) { + OC_Log::write('core', __METHOD__.'(): called with no path.', OC_Log::ERROR); + return false; + } elseif($filePath === null && $this->filePath !== null) { + $filePath = $this->filePath; + } + return $this->_output($filePath); + } + + /** + * @brief Outputs/saves the image. + */ + private function _output($filePath=null) { + if($filePath) { + if (!file_exists(dirname($filePath))) + mkdir(dirname($filePath), 0777, true); + if(!is_writable(dirname($filePath))) { + OC_Log::write('core', + __METHOD__.'(): Directory \''.dirname($filePath).'\' is not writable.', + OC_Log::ERROR); + return false; + } elseif(is_writable(dirname($filePath)) && file_exists($filePath) && !is_writable($filePath)) { + OC_Log::write('core', __METHOD__.'(): File \''.$filePath.'\' is not writable.', OC_Log::ERROR); + return false; + } + } + if (!$this->valid()) { + return false; + } + + $retVal = false; + switch($this->imageType) { + case IMAGETYPE_GIF: + $retVal = imagegif($this->resource, $filePath); + break; + case IMAGETYPE_JPEG: + $retVal = imagejpeg($this->resource, $filePath); + break; + case IMAGETYPE_PNG: + $retVal = imagepng($this->resource, $filePath); + break; + case IMAGETYPE_XBM: + $retVal = imagexbm($this->resource, $filePath); + break; + case IMAGETYPE_WBMP: + $retVal = imagewbmp($this->resource, $filePath); + break; + case IMAGETYPE_BMP: + $retVal = imagebmp($this->resource, $filePath, $this->bitDepth); + break; + default: + $retVal = imagepng($this->resource, $filePath); + } + return $retVal; + } + + /** + * @brief Prints the image when called as $image(). + */ + public function __invoke() { + return $this->show(); + } + + /** + * @returns Returns the image resource in any. + */ + public function resource() { + return $this->resource; + } + + /** + * @returns Returns the raw image data. + */ + function data() { + ob_start(); + switch ($this->mimeType) { + case "image/png": + $res = imagepng($this->resource); + break; + case "image/jpeg": + $res = imagejpeg($this->resource); + break; + case "image/gif": + $res = imagegif($this->resource); + break; + default: + $res = imagepng($this->resource); + OC_Log::write('core', 'OC_Image->data. Couldn\'t guess mimetype, defaulting to png', OC_Log::INFO); + break; + } + if (!$res) { + OC_Log::write('core', 'OC_Image->data. Error getting image data.', OC_Log::ERROR); + } + return ob_get_clean(); + } + + /** + * @returns Returns a base64 encoded string suitable for embedding in a VCard. + */ + function __toString() { + return base64_encode($this->data()); + } + + /** + * (I'm open for suggestions on better method name ;) + * @brief Get the orientation based on EXIF data. + * @returns The orientation or -1 if no EXIF data is available. + */ + public function getOrientation() { + if(!is_callable('exif_read_data')) { + OC_Log::write('core', 'OC_Image->fixOrientation() Exif module not enabled.', OC_Log::DEBUG); + return -1; + } + if(!$this->valid()) { + OC_Log::write('core', 'OC_Image->fixOrientation() No image loaded.', OC_Log::DEBUG); + return -1; + } + if(is_null($this->filePath) || !is_readable($this->filePath)) { + OC_Log::write('core', 'OC_Image->fixOrientation() No readable file path set.', OC_Log::DEBUG); + return -1; + } + $exif = @exif_read_data($this->filePath, 'IFD0'); + if(!$exif) { + return -1; + } + if(!isset($exif['Orientation'])) { + return -1; + } + return $exif['Orientation']; + } + + /** + * (I'm open for suggestions on better method name ;) + * @brief Fixes orientation based on EXIF data. + * @returns bool. + */ + public function fixOrientation() { + $o = $this->getOrientation(); + OC_Log::write('core', 'OC_Image->fixOrientation() Orientation: '.$o, OC_Log::DEBUG); + $rotate = 0; + $flip = false; + switch($o) { + case -1: + return false; //Nothing to fix + break; + case 1: + $rotate = 0; + $flip = false; + break; + case 2: // Not tested + $rotate = 0; + $flip = true; + break; + case 3: + $rotate = 180; + $flip = false; + break; + case 4: // Not tested + $rotate = 180; + $flip = true; + break; + case 5: // Not tested + $rotate = 90; + $flip = true; + break; + case 6: + //$rotate = 90; + $rotate = 270; + $flip = false; + break; + case 7: // Not tested + $rotate = 270; + $flip = true; + break; + case 8: + $rotate = 90; + $flip = false; + break; + } + if($rotate) { + $res = imagerotate($this->resource, $rotate, -1); + if($res) { + if(imagealphablending($res, true)) { + if(imagesavealpha($res, true)) { + imagedestroy($this->resource); + $this->resource = $res; + return true; + } else { + OC_Log::write('core', 'OC_Image->fixOrientation() Error during alphasaving.', OC_Log::DEBUG); + return false; + } + } else { + OC_Log::write('core', 'OC_Image->fixOrientation() Error during alphablending.', OC_Log::DEBUG); + return false; + } + } else { + OC_Log::write('core', 'OC_Image->fixOrientation() Error during oriention fixing.', OC_Log::DEBUG); + return false; + } + } + } + + /** + * @brief Loads an image from a local file, a base64 encoded string or a resource created by an imagecreate* function. + * @param $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function or a file resource (file handle ). + * @returns An image resource or false on error + */ + public function load($imageRef) { + if(is_resource($imageRef)) { + if(get_resource_type($imageRef) == 'gd') { + $this->resource = $imageRef; + return $this->resource; + } elseif(in_array(get_resource_type($imageRef), array('file', 'stream'))) { + return $this->loadFromFileHandle($imageRef); + } + } elseif($this->loadFromFile($imageRef) !== false) { + return $this->resource; + } elseif($this->loadFromBase64($imageRef) !== false) { + return $this->resource; + } elseif($this->loadFromData($imageRef) !== false) { + return $this->resource; + } else { + OC_Log::write('core', __METHOD__.'(): couldn\'t load anything. Giving up!', OC_Log::DEBUG); + return false; + } + } + + /** + * @brief Loads an image from an open file handle. + * It is the responsibility of the caller to position the pointer at the correct place and to close the handle again. + * @param $handle + * @returns An image resource or false on error + */ + public function loadFromFileHandle($handle) { + OC_Log::write('core', __METHOD__.'(): Trying', OC_Log::DEBUG); + $contents = stream_get_contents($handle); + if($this->loadFromData($contents)) { + return $this->resource; + } + } + + /** + * @brief Loads an image from a local file. + * @param $imageref The path to a local file. + * @returns An image resource or false on error + */ + public function loadFromFile($imagePath=false) { + // exif_imagetype throws "read error!" if file is less than 12 byte + if(!@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) { + // Debug output disabled because this method is tried before loadFromBase64? + OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: '.$imagePath, OC_Log::DEBUG); + return false; + } + $iType = exif_imagetype($imagePath); + switch ($iType) { + case IMAGETYPE_GIF: + if (imagetypes() & IMG_GIF) { + $this->resource = imagecreatefromgif($imagePath); + } else { + OC_Log::write('core', + 'OC_Image->loadFromFile, GIF images not supported: '.$imagePath, + OC_Log::DEBUG); + } + break; + case IMAGETYPE_JPEG: + if (imagetypes() & IMG_JPG) { + $this->resource = imagecreatefromjpeg($imagePath); + } else { + OC_Log::write('core', + 'OC_Image->loadFromFile, JPG images not supported: '.$imagePath, + OC_Log::DEBUG); + } + break; + case IMAGETYPE_PNG: + if (imagetypes() & IMG_PNG) { + $this->resource = imagecreatefrompng($imagePath); + } else { + OC_Log::write('core', + 'OC_Image->loadFromFile, PNG images not supported: '.$imagePath, + OC_Log::DEBUG); + } + break; + case IMAGETYPE_XBM: + if (imagetypes() & IMG_XPM) { + $this->resource = imagecreatefromxbm($imagePath); + } else { + OC_Log::write('core', + 'OC_Image->loadFromFile, XBM/XPM images not supported: '.$imagePath, + OC_Log::DEBUG); + } + break; + case IMAGETYPE_WBMP: + if (imagetypes() & IMG_WBMP) { + $this->resource = imagecreatefromwbmp($imagePath); + } else { + OC_Log::write('core', + 'OC_Image->loadFromFile, WBMP images not supported: '.$imagePath, + OC_Log::DEBUG); + } + break; + case IMAGETYPE_BMP: + $this->resource = $this->imagecreatefrombmp($imagePath); + break; + /* + case IMAGETYPE_TIFF_II: // (intel byte order) + break; + case IMAGETYPE_TIFF_MM: // (motorola byte order) + break; + case IMAGETYPE_JPC: + break; + case IMAGETYPE_JP2: + break; + case IMAGETYPE_JPX: + break; + case IMAGETYPE_JB2: + break; + case IMAGETYPE_SWC: + break; + case IMAGETYPE_IFF: + break; + case IMAGETYPE_ICO: + break; + case IMAGETYPE_SWF: + break; + case IMAGETYPE_PSD: + break; + */ + default: + + // this is mostly file created from encrypted file + $this->resource = imagecreatefromstring(\OC\Files\Filesystem::file_get_contents(\OC\Files\Filesystem::getLocalPath($imagePath))); + $iType = IMAGETYPE_PNG; + OC_Log::write('core', 'OC_Image->loadFromFile, Default', OC_Log::DEBUG); + break; + } + if($this->valid()) { + $this->imageType = $iType; + $this->mimeType = image_type_to_mime_type($iType); + $this->filePath = $imagePath; + } + return $this->resource; + } + + /** + * @brief Loads an image from a string of data. + * @param $str A string of image data as read from a file. + * @returns An image resource or false on error + */ + public function loadFromData($str) { + if(is_resource($str)) { + return false; + } + $this->resource = @imagecreatefromstring($str); + if ($this->fileInfo) { + $this->mimeType = $this->fileInfo->buffer($str); + } + if(is_resource($this->resource)) { + imagealphablending($this->resource, false); + imagesavealpha($this->resource, true); + } + + if(!$this->resource) { + OC_Log::write('core', 'OC_Image->loadFromData, couldn\'t load', OC_Log::DEBUG); + return false; + } + return $this->resource; + } + + /** + * @brief Loads an image from a base64 encoded string. + * @param $str A string base64 encoded string of image data. + * @returns An image resource or false on error + */ + public function loadFromBase64($str) { + if(!is_string($str)) { + return false; + } + $data = base64_decode($str); + if($data) { // try to load from string data + $this->resource = @imagecreatefromstring($data); + if ($this->fileInfo) { + $this->mimeType = $this->fileInfo->buffer($data); + } + if(!$this->resource) { + OC_Log::write('core', 'OC_Image->loadFromBase64, couldn\'t load', OC_Log::DEBUG); + return false; + } + return $this->resource; + } else { + return false; + } + } + + /** + * Create a new image from file or URL + * @link http://www.programmierer-forum.de/function-imagecreatefrombmp-laeuft-mit-allen-bitraten-t143137.htm + * @version 1.00 + * @param string $filename

+ * Path to the BMP image. + *

+ * @return resource an image resource identifier on success, FALSE on errors. + */ + private function imagecreatefrombmp($fileName) { + if (!($fh = fopen($fileName, 'rb'))) { + trigger_error('imagecreatefrombmp: Can not open ' . $fileName, E_USER_WARNING); + return false; + } + // read file header + $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14)); + // check for bitmap + if ($meta['type'] != 19778) { + trigger_error('imagecreatefrombmp: ' . $fileName . ' is not a bitmap!', E_USER_WARNING); + return false; + } + // read image header + $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40)); + // read additional 16bit header + if ($meta['bits'] == 16) { + $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12)); + } + // set bytes and padding + $meta['bytes'] = $meta['bits'] / 8; + $this->bitDepth = $meta['bits']; //remember the bit depth for the imagebmp call + $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4))); + if ($meta['decal'] == 4) { + $meta['decal'] = 0; + } + // obtain imagesize + if ($meta['imagesize'] < 1) { + $meta['imagesize'] = $meta['filesize'] - $meta['offset']; + // in rare cases filesize is equal to offset so we need to read physical size + if ($meta['imagesize'] < 1) { + $meta['imagesize'] = @filesize($filename) - $meta['offset']; + if ($meta['imagesize'] < 1) { + trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING); + return false; + } + } + } + // calculate colors + $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors']; + // read color palette + $palette = array(); + if ($meta['bits'] < 16) { + $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4)); + // in rare cases the color value is signed + if ($palette[1] < 0) { + foreach ($palette as $i => $color) { + $palette[$i] = $color + 16777216; + } + } + } + // create gd image + $im = imagecreatetruecolor($meta['width'], $meta['height']); + $data = fread($fh, $meta['imagesize']); + $p = 0; + $vide = chr(0); + $y = $meta['height'] - 1; + $error = 'imagecreatefrombmp: ' . $fileName . ' has not enough data!'; + // loop through the image data beginning with the lower left corner + while ($y >= 0) { + $x = 0; + while ($x < $meta['width']) { + switch ($meta['bits']) { + case 32: + case 24: + if (!($part = substr($data, $p, 3))) { + trigger_error($error, E_USER_WARNING); + return $im; + } + $color = unpack('V', $part . $vide); + break; + case 16: + if (!($part = substr($data, $p, 2))) { + trigger_error($error, E_USER_WARNING); + return $im; + } + $color = unpack('v', $part); + $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3); + break; + case 8: + $color = unpack('n', $vide . substr($data, $p, 1)); + $color[1] = $palette[ $color[1] + 1 ]; + break; + case 4: + $color = unpack('n', $vide . substr($data, floor($p), 1)); + $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F; + $color[1] = $palette[ $color[1] + 1 ]; + break; + case 1: + $color = unpack('n', $vide . substr($data, floor($p), 1)); + switch (($p * 8) % 8) { + case 0: + $color[1] = $color[1] >> 7; + break; + case 1: + $color[1] = ($color[1] & 0x40) >> 6; + break; + case 2: + $color[1] = ($color[1] & 0x20) >> 5; + break; + case 3: + $color[1] = ($color[1] & 0x10) >> 4; + break; + case 4: + $color[1] = ($color[1] & 0x8) >> 3; + break; + case 5: + $color[1] = ($color[1] & 0x4) >> 2; + break; + case 6: + $color[1] = ($color[1] & 0x2) >> 1; + break; + case 7: + $color[1] = ($color[1] & 0x1); + break; + } + $color[1] = $palette[ $color[1] + 1 ]; + break; + default: + trigger_error('imagecreatefrombmp: ' + . $fileName . ' has ' . $meta['bits'] . ' bits and this is not supported!', + E_USER_WARNING); + return false; + } + imagesetpixel($im, $x, $y, $color[1]); + $x++; + $p += $meta['bytes']; + } + $y--; + $p += $meta['decal']; + } + fclose($fh); + return $im; + } + + /** + * @brief Resizes the image preserving ratio. + * @param $maxsize The maximum size of either the width or height. + * @returns bool + */ + public function resize($maxSize) { + if(!$this->valid()) { + OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); + return false; + } + $widthOrig=imageSX($this->resource); + $heightOrig=imageSY($this->resource); + $ratioOrig = $widthOrig/$heightOrig; + + if ($ratioOrig > 1) { + $newHeight = round($maxSize/$ratioOrig); + $newWidth = $maxSize; + } else { + $newWidth = round($maxSize*$ratioOrig); + $newHeight = $maxSize; + } + + $this->preciseResize(round($newWidth), round($newHeight)); + return true; + } + + public function preciseResize($width, $height) { + if (!$this->valid()) { + OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); + return false; + } + $widthOrig=imageSX($this->resource); + $heightOrig=imageSY($this->resource); + $process = imagecreatetruecolor($width, $height); + + if ($process == false) { + OC_Log::write('core', __METHOD__.'(): Error creating true color image', OC_Log::ERROR); + imagedestroy($process); + return false; + } + + // preserve transparency + if($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) { + imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127)); + imagealphablending($process, false); + imagesavealpha($process, true); + } + + imagecopyresampled($process, $this->resource, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig); + if ($process == false) { + OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$width.'x'.$height, OC_Log::ERROR); + imagedestroy($process); + return false; + } + imagedestroy($this->resource); + $this->resource = $process; + return true; + } + + /** + * @brief Crops the image to the middle square. If the image is already square it just returns. + * @param int maximum size for the result (optional) + * @returns bool for success or failure + */ + public function centerCrop($size=0) { + if(!$this->valid()) { + OC_Log::write('core', 'OC_Image->centerCrop, No image loaded', OC_Log::ERROR); + return false; + } + $widthOrig=imageSX($this->resource); + $heightOrig=imageSY($this->resource); + if($widthOrig === $heightOrig and $size==0) { + return true; + } + $ratioOrig = $widthOrig/$heightOrig; + $width = $height = min($widthOrig, $heightOrig); + + if ($ratioOrig > 1) { + $x = ($widthOrig/2) - ($width/2); + $y = 0; + } else { + $y = ($heightOrig/2) - ($height/2); + $x = 0; + } + if($size>0) { + $targetWidth=$size; + $targetHeight=$size; + }else{ + $targetWidth=$width; + $targetHeight=$height; + } + $process = imagecreatetruecolor($targetWidth, $targetHeight); + if ($process == false) { + OC_Log::write('core', 'OC_Image->centerCrop. Error creating true color image', OC_Log::ERROR); + imagedestroy($process); + return false; + } + + // preserve transparency + if($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) { + imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127)); + imagealphablending($process, false); + imagesavealpha($process, true); + } + + imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height); + if ($process == false) { + OC_Log::write('core', + 'OC_Image->centerCrop. Error resampling process image '.$width.'x'.$height, + OC_Log::ERROR); + imagedestroy($process); + return false; + } + imagedestroy($this->resource); + $this->resource = $process; + return true; + } + + /** + * @brief Crops the image from point $x$y with dimension $wx$h. + * @param $x Horizontal position + * @param $y Vertical position + * @param $w Width + * @param $h Height + * @returns bool for success or failure + */ + public function crop($x, $y, $w, $h) { + if(!$this->valid()) { + OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); + return false; + } + $process = imagecreatetruecolor($w, $h); + if ($process == false) { + OC_Log::write('core', __METHOD__.'(): Error creating true color image', OC_Log::ERROR); + imagedestroy($process); + return false; + } + imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h); + if ($process == false) { + OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$w.'x'.$h, OC_Log::ERROR); + imagedestroy($process); + return false; + } + imagedestroy($this->resource); + $this->resource = $process; + return true; + } + + /** + * @brief Resizes the image to fit within a boundry while preserving ratio. + * @param $maxWidth + * @param $maxHeight + * @returns bool + */ + public function fitIn($maxWidth, $maxHeight) { + if(!$this->valid()) { + OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); + return false; + } + $widthOrig=imageSX($this->resource); + $heightOrig=imageSY($this->resource); + $ratio = $widthOrig/$heightOrig; + + $newWidth = min($maxWidth, $ratio*$maxHeight); + $newHeight = min($maxHeight, $maxWidth/$ratio); + + $this->preciseResize(round($newWidth), round($newHeight)); + return true; + } + + public function destroy() { + if($this->valid()) { + imagedestroy($this->resource); + } + $this->resource=null; + } + + public function __destruct() { + $this->destroy(); + } +} +if ( ! function_exists( 'imagebmp') ) { + /** + * Output a BMP image to either the browser or a file + * @link http://www.ugia.cn/wp-data/imagebmp.php + * @author legend + * @link http://www.programmierer-forum.de/imagebmp-gute-funktion-gefunden-t143716.htm + * @author mgutt + * @version 1.00 + * @param resource $image + * @param string $filename [optional]

The path to save the file to.

+ * @param int $bit [optional]

Bit depth, (default is 24).

+ * @param int $compression [optional] + * @return bool TRUE on success or FALSE on failure. + */ + function imagebmp($im, $fileName='', $bit=24, $compression=0) { + if (!in_array($bit, array(1, 4, 8, 16, 24, 32))) { + $bit = 24; + } + else if ($bit == 32) { + $bit = 24; + } + $bits = pow(2, $bit); + imagetruecolortopalette($im, true, $bits); + $width = imagesx($im); + $height = imagesy($im); + $colorsNum = imagecolorstotal($im); + $rgbQuad = ''; + if ($bit <= 8) { + for ($i = 0; $i < $colorsNum; $i++) { + $colors = imagecolorsforindex($im, $i); + $rgbQuad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0"; + } + $bmpData = ''; + if ($compression == 0 || $bit < 8) { + $compression = 0; + $extra = ''; + $padding = 4 - ceil($width / (8 / $bit)) % 4; + if ($padding % 4 != 0) { + $extra = str_repeat("\0", $padding); + } + for ($j = $height - 1; $j >= 0; $j --) { + $i = 0; + while ($i < $width) { + $bin = 0; + $limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0; + for ($k = 8 - $bit; $k >= $limit; $k -= $bit) { + $index = imagecolorat($im, $i, $j); + $bin |= $index << $k; + $i++; + } + $bmpData .= chr($bin); + } + $bmpData .= $extra; + } + } + // RLE8 + else if ($compression == 1 && $bit == 8) { + for ($j = $height - 1; $j >= 0; $j--) { + $lastIndex = "\0"; + $sameNum = 0; + for ($i = 0; $i <= $width; $i++) { + $index = imagecolorat($im, $i, $j); + if ($index !== $lastIndex || $sameNum > 255) { + if ($sameNum != 0) { + $bmpData .= chr($same_num) . chr($lastIndex); + } + $lastIndex = $index; + $sameNum = 1; + } + else { + $sameNum++; + } + } + $bmpData .= "\0\0"; + } + $bmpData .= "\0\1"; + } + $sizeQuad = strlen($rgbQuad); + $sizeData = strlen($bmpData); + } + else { + $extra = ''; + $padding = 4 - ($width * ($bit / 8)) % 4; + if ($padding % 4 != 0) { + $extra = str_repeat("\0", $padding); + } + $bmpData = ''; + for ($j = $height - 1; $j >= 0; $j--) { + for ($i = 0; $i < $width; $i++) { + $index = imagecolorat($im, $i, $j); + $colors = imagecolorsforindex($im, $index); + if ($bit == 16) { + $bin = 0 << $bit; + $bin |= ($colors['red'] >> 3) << 10; + $bin |= ($colors['green'] >> 3) << 5; + $bin |= $colors['blue'] >> 3; + $bmpData .= pack("v", $bin); + } + else { + $bmpData .= pack("c*", $colors['blue'], $colors['green'], $colors['red']); + } + } + $bmpData .= $extra; + } + $sizeQuad = 0; + $sizeData = strlen($bmpData); + $colorsNum = 0; + } + $fileHeader = 'BM' . pack('V3', 54 + $sizeQuad + $sizeData, 0, 54 + $sizeQuad); + $infoHeader = pack('V3v2V*', 0x28, $width, $height, 1, $bit, $compression, $sizeData, 0, 0, $colorsNum, 0); + if ($fileName != '') { + $fp = fopen($fileName, 'wb'); + fwrite($fp, $fileHeader . $infoHeader . $rgbQuad . $bmpData); + fclose($fp); + return true; + } + echo $fileHeader . $infoHeader. $rgbQuad . $bmpData; + return true; + } +} + +if ( ! function_exists( 'exif_imagetype' ) ) { + /** + * Workaround if exif_imagetype does not exist + * @link http://www.php.net/manual/en/function.exif-imagetype.php#80383 + * @param string $filename + * @return string|boolean + */ + function exif_imagetype ( $fileName ) { + if ( ( $info = getimagesize( $fileName ) ) !== false ) { + return $info[2]; + } + return false; + } +} diff --git a/lib/private/installer.php b/lib/private/installer.php new file mode 100644 index 00000000000..e082c7eeee9 --- /dev/null +++ b/lib/private/installer.php @@ -0,0 +1,481 @@ +. + * + */ + +/** + * This class provides the functionality needed to install, update and remove plugins/apps + */ +class OC_Installer{ + /** + * @brief Installs an app + * @param $data array with all information + * @throws \Exception + * @returns integer + * + * This function installs an app. All information needed are passed in the + * associative array $data. + * The following keys are required: + * - source: string, can be "path" or "http" + * + * One of the following keys is required: + * - path: path to the file containing the app + * - href: link to the downloadable file containing the app + * + * The following keys are optional: + * - pretend: boolean, if set true the system won't do anything + * - noinstall: boolean, if true appinfo/install.php won't be loaded + * - inactive: boolean, if set true the appconfig/app.sample.php won't be + * renamed + * + * This function works as follows + * -# fetching the file + * -# unzipping it + * -# check the code + * -# installing the database at appinfo/database.xml + * -# including appinfo/install.php + * -# setting the installed version + * + * It is the task of oc_app_install to create the tables and do whatever is + * needed to get the app working. + */ + public static function installApp( $data = array()) { + $l = \OC_L10N::get('lib'); + + if(!isset($data['source'])) { + throw new \Exception($l->t("No source specified when installing app")); + } + + //download the file if necesary + if($data['source']=='http') { + $path=OC_Helper::tmpFile(); + if(!isset($data['href'])) { + throw new \Exception($l->t("No href specified when installing app from http")); + } + copy($data['href'], $path); + }else{ + if(!isset($data['path'])) { + throw new \Exception($l->t("No path specified when installing app from local file")); + } + $path=$data['path']; + } + + //detect the archive type + $mime=OC_Helper::getMimeType($path); + if($mime=='application/zip') { + rename($path, $path.'.zip'); + $path.='.zip'; + }elseif($mime=='application/x-gzip') { + rename($path, $path.'.tgz'); + $path.='.tgz'; + }else{ + throw new \Exception($l->t("Archives of type %s are not supported", array($mime))); + } + + //extract the archive in a temporary folder + $extractDir=OC_Helper::tmpFolder(); + OC_Helper::rmdirr($extractDir); + mkdir($extractDir); + if($archive=OC_Archive::open($path)) { + $archive->extract($extractDir); + } else { + OC_Helper::rmdirr($extractDir); + if($data['source']=='http') { + unlink($path); + } + throw new \Exception($l->t("Failed to open archive when installing app")); + } + + //load the info.xml file of the app + if(!is_file($extractDir.'/appinfo/info.xml')) { + //try to find it in a subdir + $dh=opendir($extractDir); + if(is_resource($dh)) { + while (($folder = readdir($dh)) !== false) { + if($folder[0]!='.' and is_dir($extractDir.'/'.$folder)) { + if(is_file($extractDir.'/'.$folder.'/appinfo/info.xml')) { + $extractDir.='/'.$folder; + } + } + } + } + } + if(!is_file($extractDir.'/appinfo/info.xml')) { + OC_Helper::rmdirr($extractDir); + if($data['source']=='http') { + unlink($path); + } + throw new \Exception($l->t("App does not provide an info.xml file")); + } + $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml', true); + // check the code for not allowed calls + if(!OC_Installer::checkCode($info['id'], $extractDir)) { + OC_Helper::rmdirr($extractDir); + throw new \Exception($l->t("App can't be installed because of not allowed code in the App")); + } + + // check if the app is compatible with this version of ownCloud + if( + !isset($info['require']) + or !OC_App::isAppVersionCompatible(OC_Util::getVersion(), $info['require']) + ) { + OC_Helper::rmdirr($extractDir); + throw new \Exception($l->t("App can't be installed because it is not compatible with this version of ownCloud")); + } + + // check if shipped tag is set which is only allowed for apps that are shipped with ownCloud + if(isset($info['shipped']) and ($info['shipped']=='true')) { + OC_Helper::rmdirr($extractDir); + throw new \Exception($l->t("App can't be installed because it contains the true tag which is not allowed for non shipped apps")); + } + + // check if the ocs version is the same as the version in info.xml/version + if(!isset($info['version']) or ($info['version']<>$data['appdata']['version'])) { + OC_Helper::rmdirr($extractDir); + throw new \Exception($l->t("App can't be installed because the version in info.xml/version is not the same as the version reported from the app store")); + } + + $basedir=OC_App::getInstallPath().'/'.$info['id']; + //check if the destination directory already exists + if(is_dir($basedir)) { + OC_Helper::rmdirr($extractDir); + if($data['source']=='http') { + unlink($path); + } + throw new \Exception($l->t("App directory already exists")); + } + + if(isset($data['pretent']) and $data['pretent']==true) { + return false; + } + + //copy the app to the correct place + if(@!mkdir($basedir)) { + OC_Helper::rmdirr($extractDir); + if($data['source']=='http') { + unlink($path); + } + throw new \Exception($l->t("Can't create app folder. Please fix permissions. %s", array($basedir))); + } + OC_Helper::copyr($extractDir, $basedir); + + //remove temporary files + OC_Helper::rmdirr($extractDir); + + //install the database + if(is_file($basedir.'/appinfo/database.xml')) { + OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml'); + } + + //run appinfo/install.php + if((!isset($data['noinstall']) or $data['noinstall']==false) and file_exists($basedir.'/appinfo/install.php')) { + include $basedir.'/appinfo/install.php'; + } + + //set the installed version + OC_Appconfig::setValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'])); + OC_Appconfig::setValue($info['id'], 'enabled', 'no'); + + //set remote/public handelers + foreach($info['remote'] as $name=>$path) { + OCP\CONFIG::setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); + } + foreach($info['public'] as $name=>$path) { + OCP\CONFIG::setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); + } + + OC_App::setAppTypes($info['id']); + + return $info['id']; + } + + /** + * @brief checks whether or not an app is installed + * @param $app app + * @returns true/false + * + * Checks whether or not an app is installed, i.e. registered in apps table. + */ + public static function isInstalled( $app ) { + + if( null == OC_Appconfig::getValue( $app, "installed_version" )) { + return false; + } + + return true; + } + + /** + * @brief Update an application + * @param $data array with all information + * + * This function installs an app. All information needed are passed in the + * associative array $data. + * The following keys are required: + * - source: string, can be "path" or "http" + * + * One of the following keys is required: + * - path: path to the file containing the app + * - href: link to the downloadable file containing the app + * + * The following keys are optional: + * - pretend: boolean, if set true the system won't do anything + * - noupgrade: boolean, if true appinfo/upgrade.php won't be loaded + * + * This function works as follows + * -# fetching the file + * -# removing the old files + * -# unzipping new file + * -# including appinfo/upgrade.php + * -# setting the installed version + * + * upgrade.php can determine the current installed version of the app using + * "OC_Appconfig::getValue($appid, 'installed_version')" + */ + public static function updateApp( $app ) { + $ocsid=OC_Appconfig::getValue( $app, 'ocsid'); + OC_App::disable($app); + OC_App::enable($ocsid); + return(true); + } + + /** + * @brief Check if an update for the app is available + * @param $name name of the application + * @returns empty string is no update available or the version number of the update + * + * The function will check if an update for a version is available + */ + public static function isUpdateAvailable( $app ) { + $ocsid=OC_Appconfig::getValue( $app, 'ocsid', ''); + + if($ocsid<>'') { + + $ocsdata=OC_OCSClient::getApplication($ocsid); + $ocsversion= (string) $ocsdata['version']; + $currentversion=OC_App::getAppVersion($app); + if($ocsversion<>$currentversion) { + return($ocsversion); + + }else{ + return(''); + } + + }else{ + return(''); + } + + } + + /** + * @brief Check if app is already downloaded + * @param $name name of the application to remove + * @returns true/false + * + * The function will check if the app is already downloaded in the apps repository + */ + public static function isDownloaded( $name ) { + + $downloaded=false; + foreach(OC::$APPSROOTS as $dir) { + if(is_dir($dir['path'].'/'.$name)) $downloaded=true; + } + return($downloaded); + } + + /** + * @brief Removes an app + * @param $name name of the application to remove + * @param $options array with options + * @returns true/false + * + * This function removes an app. $options is an associative array. The + * following keys are optional:ja + * - keeppreferences: boolean, if true the user preferences won't be deleted + * - keepappconfig: boolean, if true the config will be kept + * - keeptables: boolean, if true the database will be kept + * - keepfiles: boolean, if true the user files will be kept + * + * This function works as follows + * -# including appinfo/remove.php + * -# removing the files + * + * The function will not delete preferences, tables and the configuration, + * this has to be done by the function oc_app_uninstall(). + */ + public static function removeApp( $name, $options = array()) { + + if(isset($options['keeppreferences']) and $options['keeppreferences']==false ) { + // todo + // remove preferences + } + + if(isset($options['keepappconfig']) and $options['keepappconfig']==false ) { + // todo + // remove app config + } + + if(isset($options['keeptables']) and $options['keeptables']==false ) { + // todo + // remove app database tables + } + + if(isset($options['keepfiles']) and $options['keepfiles']==false ) { + // todo + // remove user files + } + + if(OC_Installer::isDownloaded( $name )) { + $appdir=OC_App::getInstallPath().'/'.$name; + OC_Helper::rmdirr($appdir); + + }else{ + OC_Log::write('core', 'can\'t remove app '.$name.'. It is not installed.', OC_Log::ERROR); + + } + + } + + /** + * @brief Installs shipped apps + * + * This function installs all apps found in the 'apps' directory that should be enabled by default; + */ + public static function installShippedApps() { + foreach(OC::$APPSROOTS as $app_dir) { + if($dir = opendir( $app_dir['path'] )) { + while( false !== ( $filename = readdir( $dir ))) { + if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) { + if( file_exists( $app_dir['path']."/$filename/appinfo/app.php" )) { + if(!OC_Installer::isInstalled($filename)) { + $info=OC_App::getAppInfo($filename); + $enabled = isset($info['default_enable']); + if( $enabled ) { + OC_Installer::installShippedApp($filename); + OC_Appconfig::setValue($filename, 'enabled', 'yes'); + } + } + } + } + } + closedir( $dir ); + } + } + } + + /** + * install an app already placed in the app folder + * @param string $app id of the app to install + * @returns array see OC_App::getAppInfo + */ + public static function installShippedApp($app) { + //install the database + if(is_file(OC_App::getAppPath($app)."/appinfo/database.xml")) { + OC_DB::createDbFromStructure(OC_App::getAppPath($app)."/appinfo/database.xml"); + } + + //run appinfo/install.php + if(is_file(OC_App::getAppPath($app)."/appinfo/install.php")) { + include OC_App::getAppPath($app)."/appinfo/install.php"; + } + $info=OC_App::getAppInfo($app); + OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app)); + + //set remote/public handelers + foreach($info['remote'] as $name=>$path) { + OCP\CONFIG::setAppValue('core', 'remote_'.$name, $app.'/'.$path); + } + foreach($info['public'] as $name=>$path) { + OCP\CONFIG::setAppValue('core', 'public_'.$name, $app.'/'.$path); + } + + OC_App::setAppTypes($info['id']); + + return $info['id']; + } + + + /** + * check the code of an app with some static code checks + * @param string $folder the folder of the app to check + * @returns true for app is o.k. and false for app is not o.k. + */ + public static function checkCode($appname, $folder) { + + $blacklist=array( + 'exec(', + 'eval(', + // more evil pattern will go here later + + // classes replaced by the public api + 'OC_API::', + 'OC_App::', + 'OC_AppConfig::', + 'OC_Avatar', + 'OC_BackgroundJob::', + 'OC_Config::', + 'OC_DB::', + 'OC_Files::', + 'OC_Helper::', + 'OC_Hook::', + 'OC_Image::', + 'OC_JSON::', + 'OC_L10N::', + 'OC_Log::', + 'OC_Mail::', + 'OC_Preferences::', + 'OC_Request::', + 'OC_Response::', + 'OC_Template::', + 'OC_User::', + 'OC_Util::', + ); + + // is the code checker enabled? + if(OC_Config::getValue('appcodechecker', false)) { + + // check if grep is installed + $grep = exec('which grep'); + if($grep=='') { + OC_Log::write('core', + 'grep not installed. So checking the code of the app "'.$appname.'" was not possible', + OC_Log::ERROR); + return true; + } + + // iterate the bad patterns + foreach($blacklist as $bl) { + $cmd = 'grep -ri '.escapeshellarg($bl).' '.$folder.''; + $result = exec($cmd); + // bad pattern found + if($result<>'') { + OC_Log::write('core', + 'App "'.$appname.'" is using a not allowed call "'.$bl.'". Installation refused.', + OC_Log::ERROR); + return false; + } + } + return true; + + }else{ + return true; + } + } +} diff --git a/lib/private/json.php b/lib/private/json.php new file mode 100644 index 00000000000..6ba0b13806b --- /dev/null +++ b/lib/private/json.php @@ -0,0 +1,115 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_JSON{ + static protected $send_content_type_header = false; + /** + * set Content-Type header to jsonrequest + */ + public static function setContentTypeHeader($type='application/json') { + if (!self::$send_content_type_header) { + // We send json data + header( 'Content-Type: '.$type . '; charset=utf-8'); + self::$send_content_type_header = true; + } + } + + /** + * Check if the app is enabled, send json error msg if not + */ + public static function checkAppEnabled($app) { + if( !OC_App::isEnabled($app)) { + $l = OC_L10N::get('lib'); + self::error(array( 'data' => array( 'message' => $l->t('Application is not enabled') ))); + exit(); + } + } + + /** + * Check if the user is logged in, send json error msg if not + */ + public static function checkLoggedIn() { + if( !OC_User::isLoggedIn()) { + $l = OC_L10N::get('lib'); + self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); + exit(); + } + } + + /** + * @brief Check an ajax get/post call if the request token is valid. + * @return json Error msg if not valid. + */ + public static function callCheck() { + if( !OC_Util::isCallRegistered()) { + $l = OC_L10N::get('lib'); + self::error(array( 'data' => array( 'message' => $l->t('Token expired. Please reload page.') ))); + exit(); + } + } + + /** + * Check if the user is a admin, send json error msg if not + */ + public static function checkAdminUser() { + if( !OC_User::isAdminUser(OC_User::getUser())) { + $l = OC_L10N::get('lib'); + self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); + exit(); + } + } + + /** + * Check if the user is a subadmin, send json error msg if not + */ + public static function checkSubAdminUser() { + if(!OC_SubAdmin::isSubAdmin(OC_User::getUser())) { + $l = OC_L10N::get('lib'); + self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); + exit(); + } + } + + /** + * Send json error msg + */ + public static function error($data = array()) { + $data['status'] = 'error'; + self::encodedPrint($data); + } + + /** + * Send json success msg + */ + public static function success($data = array()) { + $data['status'] = 'success'; + self::encodedPrint($data); + } + + /** + * Convert OC_L10N_String to string, for use in json encodings + */ + protected static function to_string(&$value) { + if ($value instanceof OC_L10N_String) { + $value = (string)$value; + } + } + + /** + * Encode and print $data in json format + */ + public static function encodedPrint($data, $setContentType=true) { + // Disable mimesniffing, don't move this to setContentTypeHeader! + header( 'X-Content-Type-Options: nosniff' ); + if($setContentType) { + self::setContentTypeHeader(); + } + array_walk_recursive($data, array('OC_JSON', 'to_string')); + echo json_encode($data); + } +} diff --git a/lib/private/l10n.php b/lib/private/l10n.php new file mode 100644 index 00000000000..f93443b886a --- /dev/null +++ b/lib/private/l10n.php @@ -0,0 +1,546 @@ +. + * + */ + +/** + * This class is for i18n and l10n + */ +class OC_L10N { + /** + * cached instances + */ + protected static $instances=array(); + + /** + * cache + */ + protected static $cache = array(); + + /** + * The best language + */ + protected static $language = ''; + + /** + * App of this object + */ + protected $app; + + /** + * Language of this object + */ + protected $lang; + + /** + * Translations + */ + private $translations = array(); + + /** + * Plural forms (string) + */ + private $plural_form_string = 'nplurals=2; plural=(n != 1);'; + + /** + * Plural forms (function) + */ + private $plural_form_function = null; + + /** + * Localization + */ + private $localizations = array( + 'jsdate' => 'dd.mm.yy', + 'date' => '%d.%m.%Y', + 'datetime' => '%d.%m.%Y %H:%M:%S', + 'time' => '%H:%M:%S', + 'firstday' => 0); + + /** + * get an L10N instance + * @param $app string + * @param $lang string|null + * @return OC_L10N + */ + public static function get($app, $lang=null) { + if(is_null($lang)) { + if(!isset(self::$instances[$app])) { + self::$instances[$app]=new OC_L10N($app); + } + return self::$instances[$app]; + }else{ + return new OC_L10N($app, $lang); + } + } + + /** + * @brief The constructor + * @param $app string app requesting l10n + * @param $lang string default: null Language + * @returns OC_L10N-Object + * + * If language is not set, the constructor tries to find the right + * language. + */ + public function __construct($app, $lang = null) { + $this->app = $app; + $this->lang = $lang; + } + + public function load($transFile) { + $this->app = true; + include $transFile; + if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)) { + $this->translations = $TRANSLATIONS; + } + if(isset($PLURAL_FORMS)) { + $this->plural_form_string = $PLURAL_FORMS; + } + } + + protected function init() { + if ($this->app === true) { + return; + } + $app = OC_App::cleanAppId($this->app); + $lang = $this->lang; + $this->app = true; + // Find the right language + if(is_null($lang) || $lang == '') { + $lang = self::findLanguage($app); + } + + // Use cache if possible + if(array_key_exists($app.'::'.$lang, self::$cache)) { + + $this->translations = self::$cache[$app.'::'.$lang]['t']; + $this->localizations = self::$cache[$app.'::'.$lang]['l']; + } + else{ + $i18ndir = self::findI18nDir($app); + // Localization is in /l10n, Texts are in $i18ndir + // (Just no need to define date/time format etc. twice) + if((OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC_App::getAppPath($app).'/l10n/') + || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/core/l10n/') + || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/lib/l10n/') + || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/settings') + ) + && file_exists($i18ndir.$lang.'.php')) { + // Include the file, save the data from $CONFIG + $transFile = strip_tags($i18ndir).strip_tags($lang).'.php'; + include $transFile; + if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)) { + $this->translations = $TRANSLATIONS; + //merge with translations from theme + $theme = OC_Config::getValue( "theme" ); + if (!is_null($theme)) { + $transFile = OC::$SERVERROOT.'/themes/'.$theme.substr($transFile, strlen(OC::$SERVERROOT)); + if (file_exists($transFile)) { + include $transFile; + if (isset($TRANSLATIONS) && is_array($TRANSLATIONS)) { + $this->translations = array_merge($this->translations, $TRANSLATIONS); + } + } + } + } + if(isset($PLURAL_FORMS)) { + $this->plural_form_string = $PLURAL_FORMS; + } + } + + if(file_exists(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php')) { + // Include the file, save the data from $CONFIG + include OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php'; + if(isset($LOCALIZATIONS) && is_array($LOCALIZATIONS)) { + $this->localizations = array_merge($this->localizations, $LOCALIZATIONS); + } + } + + self::$cache[$app.'::'.$lang]['t'] = $this->translations; + self::$cache[$app.'::'.$lang]['l'] = $this->localizations; + } + } + + /** + * @brief Creates a function that The constructor + * + * If language is not set, the constructor tries to find the right + * language. + * + * Parts of the code is copied from Habari: + * https://github.com/habari/system/blob/master/classes/locale.php + * @param $string string + * @return string + */ + protected function createPluralFormFunction($string){ + if(preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) { + // sanitize + $nplurals = preg_replace( '/[^0-9]/', '', $matches[1] ); + $plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] ); + + $body = str_replace( + array( 'plural', 'n', '$n$plurals', ), + array( '$plural', '$n', '$nplurals', ), + 'nplurals='. $nplurals . '; plural=' . $plural + ); + + // add parents + // important since PHP's ternary evaluates from left to right + $body .= ';'; + $res = ''; + $p = 0; + for($i = 0; $i < strlen($body); $i++) { + $ch = $body[$i]; + switch ( $ch ) { + case '?': + $res .= ' ? ('; + $p++; + break; + case ':': + $res .= ') : ('; + break; + case ';': + $res .= str_repeat( ')', $p ) . ';'; + $p = 0; + break; + default: + $res .= $ch; + } + } + + $body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);'; + return create_function('$n', $body); + } + else { + // default: one plural form for all cases but n==1 (english) + return create_function( + '$n', + '$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);' + ); + } + } + + /** + * @brief Translating + * @param $text String The text we need a translation for + * @param array $parameters default:array() Parameters for sprintf + * @return \OC_L10N_String Translation or the same text + * + * Returns the translation. If no translation is found, $text will be + * returned. + */ + public function t($text, $parameters = array()) { + return new OC_L10N_String($this, $text, $parameters); + } + + /** + * @brief Translating + * @param $text_singular String the string to translate for exactly one object + * @param $text_plural String the string to translate for n objects + * @param $count Integer Number of objects + * @param array $parameters default:array() Parameters for sprintf + * @return \OC_L10N_String Translation or the same text + * + * Returns the translation. If no translation is found, $text will be + * returned. %n will be replaced with the number of objects. + * + * The correct plural is determined by the plural_forms-function + * provided by the po file. + * + */ + public function n($text_singular, $text_plural, $count, $parameters = array()) { + $this->init(); + $identifier = "_${text_singular}__${text_plural}_"; + if( array_key_exists($identifier, $this->translations)) { + return new OC_L10N_String( $this, $identifier, $parameters, $count ); + } + else{ + if($count === 1) { + return new OC_L10N_String($this, $text_singular, $parameters, $count); + } + else{ + return new OC_L10N_String($this, $text_plural, $parameters, $count); + } + } + } + + /** + * @brief Translating + * @param $textArray The text array we need a translation for + * @returns Translation or the same text + * + * Returns the translation. If no translation is found, $textArray will be + * returned. + * + * + * @deprecated deprecated since ownCloud version 5.0 + * This method will probably be removed with ownCloud 6.0 + * + * + */ + public function tA($textArray) { + OC_Log::write('core', 'DEPRECATED: the method tA is deprecated and will be removed soon.', OC_Log::WARN); + $result = array(); + foreach($textArray as $key => $text) { + $result[$key] = (string)$this->t($text); + } + return $result; + } + + /** + * @brief getTranslations + * @returns Fetch all translations + * + * Returns an associative array with all translations + */ + public function getTranslations() { + $this->init(); + return $this->translations; + } + + /** + * @brief getPluralFormString + * @returns string containing the gettext "Plural-Forms"-string + * + * Returns a string like "nplurals=2; plural=(n != 1);" + */ + public function getPluralFormString() { + $this->init(); + return $this->plural_form_string; + } + + /** + * @brief getPluralFormFunction + * @returns string the plural form function + * + * returned function accepts the argument $n + */ + public function getPluralFormFunction() { + $this->init(); + if(is_null($this->plural_form_function)) { + $this->plural_form_function = $this->createPluralFormFunction($this->plural_form_string); + } + return $this->plural_form_function; + } + + /** + * @brief get localizations + * @returns Fetch all localizations + * + * Returns an associative array with all localizations + */ + public function getLocalizations() { + $this->init(); + return $this->localizations; + } + + /** + * @brief Localization + * @param $type Type of localization + * @param $params parameters for this localization + * @returns String or false + * + * Returns the localized data. + * + * Implemented types: + * - date + * - Creates a date + * - l10n-field: date + * - params: timestamp (int/string) + * - datetime + * - Creates date and time + * - l10n-field: datetime + * - params: timestamp (int/string) + * - time + * - Creates a time + * - l10n-field: time + * - params: timestamp (int/string) + */ + public function l($type, $data) { + $this->init(); + switch($type) { + // If you add something don't forget to add it to $localizations + // at the top of the page + case 'date': + case 'datetime': + case 'time': + if($data instanceof DateTime) { + return $data->format($this->localizations[$type]); + } elseif(is_string($data) && !is_numeric($data)) { + $data = strtotime($data); + } + $locales = array(self::findLanguage()); + if (strlen($locales[0]) == 2) { + $locales[] = $locales[0].'_'.strtoupper($locales[0]); + } + setlocale(LC_TIME, $locales); + $format = $this->localizations[$type]; + // Check for Windows to find and replace the %e modifier correctly + if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { + $format = preg_replace('#(?localizations[$type]; + default: + return false; + } + } + + /** + * @brief Choose a language + * @param $texts Associative Array with possible strings + * @returns String + * + * $text is an array 'de' => 'hallo welt', 'en' => 'hello world', ... + * + * This function is useful to avoid loading thousands of files if only one + * simple string is needed, for example in appinfo.php + */ + public static function selectLanguage($text) { + $lang = self::findLanguage(array_keys($text)); + return $text[$lang]; + } + + /** + * @brief find the best language + * @param $app Array or string, details below + * @returns language + * + * If $app is an array, ownCloud assumes that these are the available + * languages. Otherwise ownCloud tries to find the files in the l10n + * folder. + * + * If nothing works it returns 'en' + */ + public static function findLanguage($app = null) { + if(!is_array($app) && self::$language != '') { + return self::$language; + } + + if(OC_User::getUser() && OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang')) { + $lang = OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang'); + self::$language = $lang; + if(is_array($app)) { + $available = $app; + $lang_exists = array_search($lang, $available) !== false; + } + else { + $lang_exists = self::languageExists($app, $lang); + } + if($lang_exists) { + return $lang; + } + } + + $default_language = OC_Config::getValue('default_language', false); + + if($default_language !== false) { + return $default_language; + } + + if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { + $accepted_languages = preg_split('/,\s*/', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); + if(is_array($app)) { + $available = $app; + } + else{ + $available = self::findAvailableLanguages($app); + } + foreach($accepted_languages as $i) { + $temp = explode(';', $i); + $temp[0] = str_replace('-', '_', $temp[0]); + if( ($key = array_search($temp[0], $available)) !== false) { + if (is_null($app)) { + self::$language = $available[$key]; + } + return $available[$key]; + } + foreach($available as $l) { + if ( $temp[0] == substr($l, 0, 2) ) { + if (is_null($app)) { + self::$language = $l; + } + return $l; + } + } + } + } + + // Last try: English + return 'en'; + } + + /** + * @brief find the l10n directory + * @param $app App that needs to be translated + * @returns directory + */ + protected static function findI18nDir($app) { + // find the i18n dir + $i18ndir = OC::$SERVERROOT.'/core/l10n/'; + if($app != '') { + // Check if the app is in the app folder + if(file_exists(OC_App::getAppPath($app).'/l10n/')) { + $i18ndir = OC_App::getAppPath($app).'/l10n/'; + } + else{ + $i18ndir = OC::$SERVERROOT.'/'.$app.'/l10n/'; + } + } + return $i18ndir; + } + + /** + * @brief find all available languages for an app + * @param $app App that needs to be translated + * @returns array an array of available languages + */ + public static function findAvailableLanguages($app=null) { + $available=array('en');//english is always available + $dir = self::findI18nDir($app); + if(is_dir($dir)) { + $files=scandir($dir); + foreach($files as $file) { + if(substr($file, -4, 4) === '.php' && substr($file, 0, 4) !== 'l10n') { + $i = substr($file, 0, -4); + $available[] = $i; + } + } + } + return $available; + } + + public static function languageExists($app, $lang) { + if ($lang == 'en') {//english is always available + return true; + } + $dir = self::findI18nDir($app); + if(is_dir($dir)) { + return file_exists($dir.'/'.$lang.'.php'); + } + return false; + } +} diff --git a/lib/private/l10n/ach.php b/lib/private/l10n/ach.php new file mode 100644 index 00000000000..406ff5f5a26 --- /dev/null +++ b/lib/private/l10n/ach.php @@ -0,0 +1,8 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/private/l10n/af_ZA.php b/lib/private/l10n/af_ZA.php new file mode 100644 index 00000000000..d6bf5771e8d --- /dev/null +++ b/lib/private/l10n/af_ZA.php @@ -0,0 +1,14 @@ + "Hulp", +"Personal" => "Persoonlik", +"Settings" => "Instellings", +"Users" => "Gebruikers", +"Admin" => "Admin", +"web services under your control" => "webdienste onder jou beheer", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/ar.php b/lib/private/l10n/ar.php new file mode 100644 index 00000000000..f626dcdfda6 --- /dev/null +++ b/lib/private/l10n/ar.php @@ -0,0 +1,50 @@ + "المساعدة", +"Personal" => "شخصي", +"Settings" => "إعدادات", +"Users" => "المستخدمين", +"Admin" => "المدير", +"web services under your control" => "خدمات الشبكة تحت سيطرتك", +"ZIP download is turned off." => "تحميل ملفات ZIP متوقف", +"Files need to be downloaded one by one." => "الملفات بحاجة الى ان يتم تحميلها واحد تلو الاخر", +"Back to Files" => "العودة الى الملفات", +"Selected files too large to generate zip file." => "الملفات المحددة كبيرة جدا ليتم ضغطها في ملف zip", +"Application is not enabled" => "التطبيق غير مفعّل", +"Authentication error" => "لم يتم التأكد من الشخصية بنجاح", +"Token expired. Please reload page." => "انتهت صلاحية الكلمة , يرجى اعادة تحميل الصفحة", +"Files" => "الملفات", +"Text" => "معلومات إضافية", +"Images" => "صور", +"%s enter the database username." => "%s ادخل اسم المستخدم الخاص بقاعدة البيانات.", +"%s enter the database name." => "%s ادخل اسم فاعدة البيانات", +"%s you may not use dots in the database name" => "%s لا يسمح لك باستخدام نقطه (.) في اسم قاعدة البيانات", +"MS SQL username and/or password not valid: %s" => "اسم المستخدم و/أو كلمة المرور لنظام MS SQL غير صحيح : %s", +"You need to enter either an existing account or the administrator." => "انت بحاجة لكتابة اسم مستخدم موجود أو حساب المدير.", +"MySQL username and/or password not valid" => "اسم المستخدم و/أو كلمة المرور لنظام MySQL غير صحيح", +"DB Error: \"%s\"" => "خطأ في قواعد البيانات : \"%s\"", +"Offending command was: \"%s\"" => "الأمر المخالف كان : \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "أسم المستخدم '%s'@'localhost' الخاص بـ MySQL موجود مسبقا", +"Drop this user from MySQL" => "احذف اسم المستخدم هذا من الـ MySQL", +"MySQL user '%s'@'%%' already exists" => "أسم المستخدم '%s'@'%%' الخاص بـ MySQL موجود مسبقا", +"Drop this user from MySQL." => "احذف اسم المستخدم هذا من الـ MySQL.", +"Oracle username and/or password not valid" => "اسم المستخدم و/أو كلمة المرور لنظام Oracle غير صحيح", +"Offending command was: \"%s\", name: %s, password: %s" => "الأمر المخالف كان : \"%s\", اسم المستخدم : %s, كلمة المرور: %s", +"PostgreSQL username and/or password not valid" => "اسم المستخدم / أو كلمة المرور الخاصة بـPostgreSQL غير صحيحة", +"Set an admin username." => "اعداد اسم مستخدم للمدير", +"Set an admin password." => "اعداد كلمة مرور للمدير", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "اعدادات خادمك غير صحيحة بشكل تسمح لك بمزامنة ملفاتك وذلك بسبب أن واجهة WebDAV تبدو معطلة", +"Please double check the installation guides." => "الرجاء التحقق من دليل التنصيب.", +"seconds ago" => "منذ ثواني", +"_%n minute ago_::_%n minutes ago_" => array("","","","","",""), +"_%n hour ago_::_%n hours ago_" => array("","","","","",""), +"today" => "اليوم", +"yesterday" => "يوم أمس", +"_%n day go_::_%n days ago_" => array("","","","","",""), +"last month" => "الشهر الماضي", +"_%n month ago_::_%n months ago_" => array("","","","","",""), +"last year" => "السنةالماضية", +"years ago" => "سنة مضت", +"Could not find category \"%s\"" => "تعذر العثور على المجلد \"%s\"" +); +$PLURAL_FORMS = "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"; diff --git a/lib/private/l10n/be.php b/lib/private/l10n/be.php new file mode 100644 index 00000000000..1570411eb86 --- /dev/null +++ b/lib/private/l10n/be.php @@ -0,0 +1,8 @@ + array("","","",""), +"_%n hour ago_::_%n hours ago_" => array("","","",""), +"_%n day go_::_%n days ago_" => array("","","",""), +"_%n month ago_::_%n months ago_" => array("","","","") +); +$PLURAL_FORMS = "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/bg_BG.php b/lib/private/l10n/bg_BG.php new file mode 100644 index 00000000000..b6cc949eb8a --- /dev/null +++ b/lib/private/l10n/bg_BG.php @@ -0,0 +1,51 @@ + "Помощ", +"Personal" => "Лични", +"Settings" => "Настройки", +"Users" => "Потребители", +"Admin" => "Админ", +"web services under your control" => "уеб услуги под Ваш контрол", +"ZIP download is turned off." => "Изтеглянето като ZIP е изключено.", +"Files need to be downloaded one by one." => "Файловете трябва да се изтеглят един по един.", +"Back to Files" => "Назад към файловете", +"Selected files too large to generate zip file." => "Избраните файлове са прекалено големи за генерирането на ZIP архив.", +"Application is not enabled" => "Приложението не е включено.", +"Authentication error" => "Възникна проблем с идентификацията", +"Token expired. Please reload page." => "Ключът е изтекъл, моля презаредете страницата", +"Files" => "Файлове", +"Text" => "Текст", +"Images" => "Снимки", +"%s enter the database username." => "%s въведете потребителско име за базата с данни.", +"%s enter the database name." => "%s въведете име на базата с данни.", +"%s you may not use dots in the database name" => "%s, не можете да ползвате точки в името на базата от данни", +"MS SQL username and/or password not valid: %s" => "Невалидно MS SQL потребителско име и/или парола: %s", +"You need to enter either an existing account or the administrator." => "Необходимо е да влезете в всъществуващ акаунт или като администратора", +"MySQL username and/or password not valid" => "Невалидно MySQL потребителско име и/или парола", +"DB Error: \"%s\"" => "Грешка в базата от данни: \"%s\"", +"Offending command was: \"%s\"" => "Проблемната команда беше: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL потребителят '%s'@'localhost' вече съществува", +"Drop this user from MySQL" => "Изтриване на потребителя от MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL потребителят '%s'@'%%' вече съществува.", +"Drop this user from MySQL." => "Изтриване на потребителя от MySQL.", +"Oracle connection could not be established" => "Oracle връзка не можа да се осъществи", +"Oracle username and/or password not valid" => "Невалидно Oracle потребителско име и/или парола", +"Offending command was: \"%s\", name: %s, password: %s" => "Проблемната команда беше: \"%s\", име: %s, парола: %s", +"PostgreSQL username and/or password not valid" => "Невалидно PostgreSQL потребителско име и/или парола", +"Set an admin username." => "Въведете потребителско име за администратор.", +"Set an admin password." => "Въведете парола за администратор.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Вашият web сървър все още не е удачно настроен да позволява синхронизация на файлове, защото WebDAV интерфейсът изглежда не работи.", +"Please double check the installation guides." => "Моля направете повторна справка с ръководството за инсталиране.", +"seconds ago" => "преди секунди", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "днес", +"yesterday" => "вчера", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "последният месец", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "последната година", +"years ago" => "последните години", +"Could not find category \"%s\"" => "Невъзможно откриване на категорията \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/bn_BD.php b/lib/private/l10n/bn_BD.php new file mode 100644 index 00000000000..a42435a2a47 --- /dev/null +++ b/lib/private/l10n/bn_BD.php @@ -0,0 +1,29 @@ + "সহায়িকা", +"Personal" => "ব্যক্তিগত", +"Settings" => "নিয়ামকসমূহ", +"Users" => "ব্যবহারকারী", +"Admin" => "প্রশাসন", +"web services under your control" => "ওয়েব সার্ভিস আপনার হাতের মুঠোয়", +"ZIP download is turned off." => "ZIP ডাউনলোড বন্ধ করা আছে।", +"Files need to be downloaded one by one." => "ফাইলগুলো একে একে ডাউনলোড করা আবশ্যক।", +"Back to Files" => "ফাইলে ফিরে চল", +"Selected files too large to generate zip file." => "নির্বাচিত ফাইলগুলো এতই বৃহৎ যে জিপ ফাইল তৈরী করা সম্ভব নয়।", +"Application is not enabled" => "অ্যাপ্লিকেসনটি সক্রিয় নয়", +"Authentication error" => "অনুমোদন ঘটিত সমস্যা", +"Token expired. Please reload page." => "টোকেন মেয়াদোত্তীর্ণ। দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।", +"Files" => "ফাইল", +"Text" => "টেক্সট", +"seconds ago" => "সেকেন্ড পূর্বে", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "আজ", +"yesterday" => "গতকাল", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "গত মাস", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "গত বছর", +"years ago" => "বছর পূর্বে" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/bs.php b/lib/private/l10n/bs.php new file mode 100644 index 00000000000..3cb98906e62 --- /dev/null +++ b/lib/private/l10n/bs.php @@ -0,0 +1,8 @@ + array("","",""), +"_%n hour ago_::_%n hours ago_" => array("","",""), +"_%n day go_::_%n days ago_" => array("","",""), +"_%n month ago_::_%n months ago_" => array("","","") +); +$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/ca.php b/lib/private/l10n/ca.php new file mode 100644 index 00000000000..a8769224705 --- /dev/null +++ b/lib/private/l10n/ca.php @@ -0,0 +1,72 @@ + "L'aplicació \"%s\" no es pot instal·lar perquè no és compatible amb aquesta versió d'ownCloud.", +"No app name specified" => "No heu especificat cap nom d'aplicació", +"Help" => "Ajuda", +"Personal" => "Personal", +"Settings" => "Configuració", +"Users" => "Usuaris", +"Admin" => "Administració", +"Failed to upgrade \"%s\"." => "Ha fallat l'actualització \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Les imatges de perfil personals encara no funcionen amb encriptació", +"Unknown filetype" => "Tipus de fitxer desconegut", +"Invalid image" => "Imatge no vàlida", +"web services under your control" => "controleu els vostres serveis web", +"cannot open \"%s\"" => "no es pot obrir \"%s\"", +"ZIP download is turned off." => "La baixada en ZIP està desactivada.", +"Files need to be downloaded one by one." => "Els fitxers s'han de baixar d'un en un.", +"Back to Files" => "Torna a Fitxers", +"Selected files too large to generate zip file." => "Els fitxers seleccionats son massa grans per generar un fitxer zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Baixeu els fitxers en trossos petits, de forma separada, o pregunteu a l'administrador.", +"No source specified when installing app" => "No heu especificat la font en instal·lar l'aplicació", +"No href specified when installing app from http" => "No heu especificat href en instal·lar l'aplicació des de http", +"No path specified when installing app from local file" => "No heu seleccionat el camí en instal·lar una aplicació des d'un fitxer local", +"Archives of type %s are not supported" => "Els fitxers del tipus %s no són compatibles", +"Failed to open archive when installing app" => "Ha fallat l'obertura del fitxer en instal·lar l'aplicació", +"App does not provide an info.xml file" => "L'aplicació no proporciona un fitxer info.xml", +"App can't be installed because of not allowed code in the App" => "L'aplicació no es pot instal·lar perquè hi ha codi no autoritzat en l'aplicació", +"App can't be installed because it is not compatible with this version of ownCloud" => "L'aplicació no es pot instal·lar perquè no és compatible amb aquesta versió d'ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "L'aplicació no es pot instal·lar perquè conté l'etiqueta vertader que no es permet per aplicacions no enviades", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "L'aplicació no es pot instal·lar perquè la versió a info.xml/version no és la mateixa que la versió indicada des de la botiga d'aplicacions", +"App directory already exists" => "La carpeta de l'aplicació ja existeix", +"Can't create app folder. Please fix permissions. %s" => "No es pot crear la carpeta de l'aplicació. Arregleu els permisos. %s", +"Application is not enabled" => "L'aplicació no està habilitada", +"Authentication error" => "Error d'autenticació", +"Token expired. Please reload page." => "El testimoni ha expirat. Torneu a carregar la pàgina.", +"Files" => "Fitxers", +"Text" => "Text", +"Images" => "Imatges", +"%s enter the database username." => "%s escriviu el nom d'usuari de la base de dades.", +"%s enter the database name." => "%s escriviu el nom de la base de dades.", +"%s you may not use dots in the database name" => "%s no podeu usar punts en el nom de la base de dades", +"MS SQL username and/or password not valid: %s" => "Nom d'usuari i/o contrasenya MS SQL no vàlids: %s", +"You need to enter either an existing account or the administrator." => "Heu d'escriure un compte existent o el d'administrador.", +"MySQL username and/or password not valid" => "Nom d'usuari i/o contrasenya MySQL no vàlids", +"DB Error: \"%s\"" => "Error DB: \"%s\"", +"Offending command was: \"%s\"" => "L'ordre en conflicte és: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "L'usuari MySQL '%s'@'localhost' ja existeix.", +"Drop this user from MySQL" => "Elimina aquest usuari de MySQL", +"MySQL user '%s'@'%%' already exists" => "L'usuari MySQL '%s'@'%%' ja existeix", +"Drop this user from MySQL." => "Elimina aquest usuari de MySQL.", +"Oracle connection could not be established" => "No s'ha pogut establir la connexió Oracle", +"Oracle username and/or password not valid" => "Nom d'usuari i/o contrasenya Oracle no vàlids", +"Offending command was: \"%s\", name: %s, password: %s" => "L'ordre en conflicte és: \"%s\", nom: %s, contrasenya: %s", +"PostgreSQL username and/or password not valid" => "Nom d'usuari i/o contrasenya PostgreSQL no vàlids", +"Set an admin username." => "Establiu un nom d'usuari per l'administrador.", +"Set an admin password." => "Establiu una contrasenya per l'administrador.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "El servidor web no està configurat correctament per permetre la sincronització de fitxers perquè la interfície WebDAV sembla no funcionar correctament.", +"Please double check the installation guides." => "Comproveu les guies d'instal·lació.", +"seconds ago" => "segons enrere", +"_%n minute ago_::_%n minutes ago_" => array("fa %n minut","fa %n minuts"), +"_%n hour ago_::_%n hours ago_" => array("fa %n hora","fa %n hores"), +"today" => "avui", +"yesterday" => "ahir", +"_%n day go_::_%n days ago_" => array("fa %n dia","fa %n dies"), +"last month" => "el mes passat", +"_%n month ago_::_%n months ago_" => array("fa %n mes","fa %n mesos"), +"last year" => "l'any passat", +"years ago" => "anys enrere", +"Caused by:" => "Provocat per:", +"Could not find category \"%s\"" => "No s'ha trobat la categoria \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/cs_CZ.php b/lib/private/l10n/cs_CZ.php new file mode 100644 index 00000000000..ed31ae79529 --- /dev/null +++ b/lib/private/l10n/cs_CZ.php @@ -0,0 +1,72 @@ + "Aplikace \"%s\" nemůže být nainstalována, protože není kompatibilní s touto verzí ownCloud.", +"No app name specified" => "Nebyl zadan název aplikace", +"Help" => "Nápověda", +"Personal" => "Osobní", +"Settings" => "Nastavení", +"Users" => "Uživatelé", +"Admin" => "Administrace", +"Failed to upgrade \"%s\"." => "Selhala aktualizace verze \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Vlastní profilové obrázky zatím nefungují v kombinaci se šifrováním", +"Unknown filetype" => "Neznámý typ souboru", +"Invalid image" => "Chybný obrázek", +"web services under your control" => "webové služby pod Vaší kontrolou", +"cannot open \"%s\"" => "nelze otevřít \"%s\"", +"ZIP download is turned off." => "Stahování v ZIPu je vypnuto.", +"Files need to be downloaded one by one." => "Soubory musí být stahovány jednotlivě.", +"Back to Files" => "Zpět k souborům", +"Selected files too large to generate zip file." => "Vybrané soubory jsou příliš velké pro vytvoření ZIP souboru.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Stáhněte soubory po menších částech, samostatně, nebo se obraťte na správce.", +"No source specified when installing app" => "Nebyl zadán zdroj při instalaci aplikace", +"No href specified when installing app from http" => "Nebyl zadán odkaz pro instalaci aplikace z HTTP", +"No path specified when installing app from local file" => "Nebyla zadána cesta pro instalaci aplikace z místního souboru", +"Archives of type %s are not supported" => "Archivy typu %s nejsou podporovány", +"Failed to open archive when installing app" => "Chyba při otevírání archivu během instalace aplikace", +"App does not provide an info.xml file" => "Aplikace neposkytuje soubor info.xml", +"App can't be installed because of not allowed code in the App" => "Aplikace nemůže být nainstalována, protože obsahuje nepovolený kód", +"App can't be installed because it is not compatible with this version of ownCloud" => "Aplikace nemůže být nainstalována, protože není kompatibilní s touto verzí ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Aplikace nemůže být nainstalována, protože obsahuje značku\n\n\ntrue\n\n\ncož není povoleno pro nedodávané aplikace", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Aplikace nemůže být nainstalována, protože verze uvedená v info.xml/version nesouhlasí s verzí oznámenou z úložiště aplikací.", +"App directory already exists" => "Adresář aplikace již existuje", +"Can't create app folder. Please fix permissions. %s" => "Nelze vytvořit složku aplikace. Opravte práva souborů. %s", +"Application is not enabled" => "Aplikace není povolena", +"Authentication error" => "Chyba ověření", +"Token expired. Please reload page." => "Token vypršel. Obnovte prosím stránku.", +"Files" => "Soubory", +"Text" => "Text", +"Images" => "Obrázky", +"%s enter the database username." => "Zadejte uživatelské jméno %s databáze.", +"%s enter the database name." => "Zadejte název databáze pro %s databáze.", +"%s you may not use dots in the database name" => "V názvu databáze %s nesmíte používat tečky.", +"MS SQL username and/or password not valid: %s" => "Uživatelské jméno či heslo MSSQL není platné: %s", +"You need to enter either an existing account or the administrator." => "Musíte zadat existující účet či správce.", +"MySQL username and/or password not valid" => "Uživatelské jméno či heslo MySQL není platné", +"DB Error: \"%s\"" => "Chyba databáze: \"%s\"", +"Offending command was: \"%s\"" => "Příslušný příkaz byl: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Uživatel '%s'@'localhost' již v MySQL existuje.", +"Drop this user from MySQL" => "Zrušte tohoto uživatele z MySQL", +"MySQL user '%s'@'%%' already exists" => "Uživatel '%s'@'%%' již v MySQL existuje", +"Drop this user from MySQL." => "Zrušte tohoto uživatele z MySQL", +"Oracle connection could not be established" => "Spojení s Oracle nemohlo být navázáno", +"Oracle username and/or password not valid" => "Uživatelské jméno či heslo Oracle není platné", +"Offending command was: \"%s\", name: %s, password: %s" => "Příslušný příkaz byl: \"%s\", jméno: %s, heslo: %s", +"PostgreSQL username and/or password not valid" => "Uživatelské jméno či heslo PostgreSQL není platné", +"Set an admin username." => "Zadejte uživatelské jméno správce.", +"Set an admin password." => "Zadejte heslo správce.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Váš webový server není správně nastaven pro umožnění synchronizace, rozhraní WebDAV se zdá být rozbité.", +"Please double check the installation guides." => "Zkonzultujte, prosím, průvodce instalací.", +"seconds ago" => "před pár sekundami", +"_%n minute ago_::_%n minutes ago_" => array("před %n minutou","před %n minutami","před %n minutami"), +"_%n hour ago_::_%n hours ago_" => array("před %n hodinou","před %n hodinami","před %n hodinami"), +"today" => "dnes", +"yesterday" => "včera", +"_%n day go_::_%n days ago_" => array("před %n dnem","před %n dny","před %n dny"), +"last month" => "minulý měsíc", +"_%n month ago_::_%n months ago_" => array("před %n měsícem","před %n měsíci","před %n měsíci"), +"last year" => "minulý rok", +"years ago" => "před lety", +"Caused by:" => "Příčina:", +"Could not find category \"%s\"" => "Nelze nalézt kategorii \"%s\"" +); +$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/lib/private/l10n/cy_GB.php b/lib/private/l10n/cy_GB.php new file mode 100644 index 00000000000..6973b51878f --- /dev/null +++ b/lib/private/l10n/cy_GB.php @@ -0,0 +1,50 @@ + "Cymorth", +"Personal" => "Personol", +"Settings" => "Gosodiadau", +"Users" => "Defnyddwyr", +"Admin" => "Gweinyddu", +"web services under your control" => "gwasanaethau gwe a reolir gennych", +"ZIP download is turned off." => "Mae llwytho ZIP wedi ei ddiffodd.", +"Files need to be downloaded one by one." => "Mae angen llwytho ffeiliau i lawr fesul un.", +"Back to Files" => "Nôl i Ffeiliau", +"Selected files too large to generate zip file." => "Mae'r ffeiliau ddewiswyd yn rhy fawr i gynhyrchu ffeil zip.", +"Application is not enabled" => "Nid yw'r pecyn wedi'i alluogi", +"Authentication error" => "Gwall dilysu", +"Token expired. Please reload page." => "Tocyn wedi dod i ben. Ail-lwythwch y dudalen.", +"Files" => "Ffeiliau", +"Text" => "Testun", +"Images" => "Delweddau", +"%s enter the database username." => "%s rhowch enw defnyddiwr y gronfa ddata.", +"%s enter the database name." => "%s rhowch enw'r gronfa ddata.", +"%s you may not use dots in the database name" => "%s does dim hawl defnyddio dot yn enw'r gronfa ddata", +"MS SQL username and/or password not valid: %s" => "Enw a/neu gyfrinair MS SQL annilys: %s", +"You need to enter either an existing account or the administrator." => "Rhaid i chi naill ai gyflwyno cyfrif presennol neu'r gweinyddwr.", +"MySQL username and/or password not valid" => "Enw a/neu gyfrinair MySQL annilys", +"DB Error: \"%s\"" => "Gwall DB: \"%s\"", +"Offending command was: \"%s\"" => "Y gorchymyn wnaeth beri tramgwydd oedd: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Defnyddiwr MySQL '%s'@'localhost' yn bodoli eisoes.", +"Drop this user from MySQL" => "Gollwng y defnyddiwr hwn o MySQL", +"MySQL user '%s'@'%%' already exists" => "Defnyddiwr MySQL '%s'@'%%' eisoes yn bodoli", +"Drop this user from MySQL." => "Gollwng y defnyddiwr hwn o MySQL.", +"Oracle username and/or password not valid" => "Enw a/neu gyfrinair Oracle annilys", +"Offending command was: \"%s\", name: %s, password: %s" => "Y gorchymyn wnaeth beri tramgwydd oedd: \"%s\", enw: %s, cyfrinair: %s", +"PostgreSQL username and/or password not valid" => "Enw a/neu gyfrinair PostgreSQL annilys", +"Set an admin username." => "Creu enw defnyddiwr i'r gweinyddwr.", +"Set an admin password." => "Gosod cyfrinair y gweinyddwr.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Nid yw eich gweinydd wedi'i gyflunio eto i ganiatáu cydweddu ffeiliau oherwydd bod y rhyngwyneb WebDAV wedi torri.", +"Please double check the installation guides." => "Gwiriwch y canllawiau gosod eto.", +"seconds ago" => "eiliad yn ôl", +"_%n minute ago_::_%n minutes ago_" => array("","","",""), +"_%n hour ago_::_%n hours ago_" => array("","","",""), +"today" => "heddiw", +"yesterday" => "ddoe", +"_%n day go_::_%n days ago_" => array("","","",""), +"last month" => "mis diwethaf", +"_%n month ago_::_%n months ago_" => array("","","",""), +"last year" => "y llynedd", +"years ago" => "blwyddyn yn ôl", +"Could not find category \"%s\"" => "Methu canfod categori \"%s\"" +); +$PLURAL_FORMS = "nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"; diff --git a/lib/private/l10n/da.php b/lib/private/l10n/da.php new file mode 100644 index 00000000000..05a43f42ed9 --- /dev/null +++ b/lib/private/l10n/da.php @@ -0,0 +1,72 @@ + "App'en \"%s\" kan ikke blive installeret, da den ikke er kompatibel med denne version af ownCloud.", +"No app name specified" => "Intet app-navn angivet", +"Help" => "Hjælp", +"Personal" => "Personligt", +"Settings" => "Indstillinger", +"Users" => "Brugere", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Upgradering af \"%s\" fejlede", +"Custom profile pictures don't work with encryption yet" => "Personligt profilbillede virker endnu ikke sammen med kryptering", +"Unknown filetype" => "Ukendt filtype", +"Invalid image" => "Ugyldigt billede", +"web services under your control" => "Webtjenester under din kontrol", +"cannot open \"%s\"" => "Kan ikke åbne \"%s\"", +"ZIP download is turned off." => "ZIP-download er slået fra.", +"Files need to be downloaded one by one." => "Filer skal downloades en for en.", +"Back to Files" => "Tilbage til Filer", +"Selected files too large to generate zip file." => "De markerede filer er for store til at generere en ZIP-fil.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Download filerne i små bider, seperat, eller kontakt venligst din administrator.", +"No source specified when installing app" => "Ingen kilde angivet under installation af app", +"No href specified when installing app from http" => "Ingen href angivet under installation af app via http", +"No path specified when installing app from local file" => "Ingen sti angivet under installation af app fra lokal fil", +"Archives of type %s are not supported" => "Arkiver af type %s understøttes ikke", +"Failed to open archive when installing app" => "Kunne ikke åbne arkiv under installation af appen", +"App does not provide an info.xml file" => "Der følger ingen info.xml-fil med appen", +"App can't be installed because of not allowed code in the App" => "Appen kan ikke installeres, da den indeholder ikke-tilladt kode", +"App can't be installed because it is not compatible with this version of ownCloud" => "Appen kan ikke installeres, da den ikke er kompatibel med denne version af ownCloud.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Appen kan ikke installeres, da den indeholder taget\n\n\ntrue\n\n\nhvilket ikke er tilladt for ikke-medfølgende apps", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "App kan ikke installeres, da versionen i info.xml/version ikke er den samme som versionen rapporteret fra app-storen", +"App directory already exists" => "App-mappe findes allerede", +"Can't create app folder. Please fix permissions. %s" => "Kan ikke oprette app-mappe. Ret tilladelser. %s", +"Application is not enabled" => "Programmet er ikke aktiveret", +"Authentication error" => "Adgangsfejl", +"Token expired. Please reload page." => "Adgang er udløbet. Genindlæs siden.", +"Files" => "Filer", +"Text" => "SMS", +"Images" => "Billeder", +"%s enter the database username." => "%s indtast database brugernavnet.", +"%s enter the database name." => "%s indtast database navnet.", +"%s you may not use dots in the database name" => "%s du må ikke bruge punktummer i databasenavnet.", +"MS SQL username and/or password not valid: %s" => "MS SQL brugernavn og/eller adgangskode ikke er gyldigt: %s", +"You need to enter either an existing account or the administrator." => "Du bliver nødt til at indtaste en eksisterende bruger eller en administrator.", +"MySQL username and/or password not valid" => "MySQL brugernavn og/eller kodeord er ikke gyldigt.", +"DB Error: \"%s\"" => "Databasefejl: \"%s\"", +"Offending command was: \"%s\"" => "Fejlende kommando var: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL brugeren '%s'@'localhost' eksisterer allerede.", +"Drop this user from MySQL" => "Slet denne bruger fra MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL brugeren '%s'@'%%' eksisterer allerede.", +"Drop this user from MySQL." => "Slet denne bruger fra MySQL", +"Oracle connection could not be established" => "Oracle forbindelsen kunne ikke etableres", +"Oracle username and/or password not valid" => "Oracle brugernavn og/eller kodeord er ikke gyldigt.", +"Offending command was: \"%s\", name: %s, password: %s" => "Fejlende kommando var: \"%s\", navn: %s, password: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.", +"Set an admin username." => "Angiv et admin brugernavn.", +"Set an admin password." => "Angiv et admin kodeord.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din webserver er endnu ikke sat op til at tillade fil synkronisering fordi WebDAV grænsefladen virker ødelagt.", +"Please double check the installation guides." => "Dobbelttjek venligst installations vejledningerne.", +"seconds ago" => "sekunder siden", +"_%n minute ago_::_%n minutes ago_" => array("%n minut siden","%n minutter siden"), +"_%n hour ago_::_%n hours ago_" => array("%n time siden","%n timer siden"), +"today" => "i dag", +"yesterday" => "i går", +"_%n day go_::_%n days ago_" => array("%n dag siden","%n dage siden"), +"last month" => "sidste måned", +"_%n month ago_::_%n months ago_" => array("%n måned siden","%n måneder siden"), +"last year" => "sidste år", +"years ago" => "år siden", +"Caused by:" => "Forårsaget af:", +"Could not find category \"%s\"" => "Kunne ikke finde kategorien \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/de.php b/lib/private/l10n/de.php new file mode 100644 index 00000000000..87e7a67b47b --- /dev/null +++ b/lib/private/l10n/de.php @@ -0,0 +1,72 @@ + "Applikation \"%s\" kann nicht installiert werden, da sie mit dieser ownCloud Version nicht kompatibel ist.", +"No app name specified" => "Es wurde kein Applikation-Name angegeben", +"Help" => "Hilfe", +"Personal" => "Persönlich", +"Settings" => "Einstellungen", +"Users" => "Benutzer", +"Admin" => "Administration", +"Failed to upgrade \"%s\"." => "Konnte \"%s\" nicht aktualisieren.", +"Custom profile pictures don't work with encryption yet" => "Individuelle Profilbilder werden noch nicht von der Verschlüsselung unterstützt", +"Unknown filetype" => "Unbekannter Dateityp", +"Invalid image" => "Ungültiges Bild", +"web services under your control" => "Web-Services unter Deiner Kontrolle", +"cannot open \"%s\"" => "Öffnen von \"%s\" fehlgeschlagen", +"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.", +"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", +"Back to Files" => "Zurück zu \"Dateien\"", +"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Lade die Dateien in kleineren, separaten, Stücken herunter oder bitte deinen Administrator.", +"No source specified when installing app" => "Für die Installation der Applikation wurde keine Quelle angegeben", +"No href specified when installing app from http" => "Der Link (href) wurde nicht angegeben um die Applikation per http zu installieren", +"No path specified when installing app from local file" => "Bei der Installation der Applikation aus einer lokalen Datei wurde kein Pfad angegeben", +"Archives of type %s are not supported" => "Archive vom Typ %s werden nicht unterstützt", +"Failed to open archive when installing app" => "Das Archiv konnte bei der Installation der Applikation nicht geöffnet werden", +"App does not provide an info.xml file" => "Die Applikation enthält keine info,xml Datei", +"App can't be installed because of not allowed code in the App" => "Die Applikation kann auf Grund von unerlaubten Code nicht installiert werden", +"App can't be installed because it is not compatible with this version of ownCloud" => "Die Anwendung konnte nicht installiert werden, weil Sie nicht mit dieser Version von ownCloud kompatibel ist.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Die Applikation konnte nicht installiert werden, da diese das true Tag beinhaltet und dieses, bei nicht mitausgelieferten Applikationen, nicht erlaubt ist ist", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Die Applikation konnte nicht installiert werden, da die Version in der info.xml nicht die gleiche Version wie im App-Store ist", +"App directory already exists" => "Das Applikationsverzeichnis existiert bereits", +"Can't create app folder. Please fix permissions. %s" => "Es kann kein Applikationsordner erstellt werden. Bitte passen sie die Berechtigungen an. %s", +"Application is not enabled" => "Die Anwendung ist nicht aktiviert", +"Authentication error" => "Fehler bei der Anmeldung", +"Token expired. Please reload page." => "Token abgelaufen. Bitte lade die Seite neu.", +"Files" => "Dateien", +"Text" => "Text", +"Images" => "Bilder", +"%s enter the database username." => "%s gib den Datenbank-Benutzernamen an.", +"%s enter the database name." => "%s gib den Datenbank-Namen an.", +"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten", +"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Password ungültig: %s", +"You need to enter either an existing account or the administrator." => "Du musst entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.", +"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig", +"DB Error: \"%s\"" => "DB Fehler: \"%s\"", +"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL Benutzer '%s'@'localhost' existiert bereits.", +"Drop this user from MySQL" => "Lösche diesen Benutzer von MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits", +"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.", +"Oracle connection could not be established" => "Es konnte keine Verbindung zur Oracle-Datenbank hergestellt werden", +"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig", +"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig", +"Set an admin username." => "Setze Administrator Benutzername.", +"Set an admin password." => "Setze Administrator Passwort", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Dein Web-Server ist noch nicht für Datei-Synchronisation bereit, weil die WebDAV-Schnittstelle vermutlich defekt ist.", +"Please double check the installation guides." => "Bitte prüfe die Installationsanleitungen.", +"seconds ago" => "Gerade eben", +"_%n minute ago_::_%n minutes ago_" => array("","Vor %n Minuten"), +"_%n hour ago_::_%n hours ago_" => array("","Vor %n Stunden"), +"today" => "Heute", +"yesterday" => "Gestern", +"_%n day go_::_%n days ago_" => array("","Vor %n Tagen"), +"last month" => "Letzten Monat", +"_%n month ago_::_%n months ago_" => array("","Vor %n Monaten"), +"last year" => "Letztes Jahr", +"years ago" => "Vor Jahren", +"Caused by:" => "Verursacht durch:", +"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden." +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/de_AT.php b/lib/private/l10n/de_AT.php new file mode 100644 index 00000000000..15f78e0bce6 --- /dev/null +++ b/lib/private/l10n/de_AT.php @@ -0,0 +1,8 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/de_CH.php b/lib/private/l10n/de_CH.php new file mode 100644 index 00000000000..33f3446a693 --- /dev/null +++ b/lib/private/l10n/de_CH.php @@ -0,0 +1,59 @@ + "Anwendung \"%s\" kann nicht installiert werden, da sie mit dieser Version von ownCloud nicht kompatibel ist.", +"No app name specified" => "Kein App-Name spezifiziert", +"Help" => "Hilfe", +"Personal" => "Persönlich", +"Settings" => "Einstellungen", +"Users" => "Benutzer", +"Admin" => "Administrator", +"Failed to upgrade \"%s\"." => "Konnte \"%s\" nicht aktualisieren.", +"web services under your control" => "Web-Services unter Ihrer Kontrolle", +"cannot open \"%s\"" => "Öffnen von \"%s\" fehlgeschlagen", +"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.", +"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", +"Back to Files" => "Zurück zu \"Dateien\"", +"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu gross, um eine ZIP-Datei zu erstellen.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Laden Sie die Dateien in kleineren, separaten, Stücken herunter oder bitten Sie Ihren Administrator.", +"App can't be installed because of not allowed code in the App" => "Anwendung kann wegen nicht erlaubten Codes nicht installiert werden", +"App directory already exists" => "Anwendungsverzeichnis existiert bereits", +"Application is not enabled" => "Die Anwendung ist nicht aktiviert", +"Authentication error" => "Authentifizierungs-Fehler", +"Token expired. Please reload page." => "Token abgelaufen. Bitte laden Sie die Seite neu.", +"Files" => "Dateien", +"Text" => "Text", +"Images" => "Bilder", +"%s enter the database username." => "%s geben Sie den Datenbank-Benutzernamen an.", +"%s enter the database name." => "%s geben Sie den Datenbank-Namen an.", +"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten", +"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Passwort ungültig: %s", +"You need to enter either an existing account or the administrator." => "Sie müssen entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.", +"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig", +"DB Error: \"%s\"" => "DB Fehler: \"%s\"", +"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL Benutzer '%s'@'localhost' existiert bereits.", +"Drop this user from MySQL" => "Lösche diesen Benutzer aus MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits", +"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.", +"Oracle connection could not be established" => "Die Oracle-Verbindung konnte nicht aufgebaut werden.", +"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig", +"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig", +"Set an admin username." => "Setze Administrator Benutzername.", +"Set an admin password." => "Setze Administrator Passwort", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ihr Web-Server ist noch nicht für eine Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.", +"Please double check the installation guides." => "Bitte prüfen Sie die Installationsanleitungen.", +"seconds ago" => "Gerade eben", +"_%n minute ago_::_%n minutes ago_" => array("","Vor %n Minuten"), +"_%n hour ago_::_%n hours ago_" => array("","Vor %n Stunden"), +"today" => "Heute", +"yesterday" => "Gestern", +"_%n day go_::_%n days ago_" => array("","Vor %n Tagen"), +"last month" => "Letzten Monat", +"_%n month ago_::_%n months ago_" => array("","Vor %n Monaten"), +"last year" => "Letztes Jahr", +"years ago" => "Vor Jahren", +"Caused by:" => "Verursacht durch:", +"Could not find category \"%s\"" => "Die Kategorie «%s» konnte nicht gefunden werden." +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/de_DE.php b/lib/private/l10n/de_DE.php new file mode 100644 index 00000000000..09be0eea22d --- /dev/null +++ b/lib/private/l10n/de_DE.php @@ -0,0 +1,72 @@ + "Applikation \"%s\" kann nicht installiert werden, da sie mit dieser ownCloud Version nicht kompatibel ist.", +"No app name specified" => "Es wurde kein Applikation-Name angegeben", +"Help" => "Hilfe", +"Personal" => "Persönlich", +"Settings" => "Einstellungen", +"Users" => "Benutzer", +"Admin" => "Administrator", +"Failed to upgrade \"%s\"." => "Konnte \"%s\" nicht aktualisieren.", +"Custom profile pictures don't work with encryption yet" => "Individuelle Profilbilder werden noch nicht von der Verschlüsselung unterstützt", +"Unknown filetype" => "Unbekannter Dateityp", +"Invalid image" => "Ungültiges Bild", +"web services under your control" => "Web-Services unter Ihrer Kontrolle", +"cannot open \"%s\"" => "Öffnen von \"%s\" fehlgeschlagen", +"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.", +"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", +"Back to Files" => "Zurück zu \"Dateien\"", +"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Laden Sie die Dateien in kleineren, separaten, Stücken herunter oder bitten Sie Ihren Administrator.", +"No source specified when installing app" => "Für die Installation der Applikation wurde keine Quelle angegeben", +"No href specified when installing app from http" => "Der Link (href) wurde nicht angegeben um die Applikation per http zu installieren", +"No path specified when installing app from local file" => "Bei der Installation der Applikation aus einer lokalen Datei wurde kein Pfad angegeben", +"Archives of type %s are not supported" => "Archive des Typs %s werden nicht unterstützt.", +"Failed to open archive when installing app" => "Das Archiv konnte bei der Installation der Applikation nicht geöffnet werden", +"App does not provide an info.xml file" => "Die Applikation enthält keine info,xml Datei", +"App can't be installed because of not allowed code in the App" => "Die Applikation kann auf Grund von unerlaubten Code nicht installiert werden", +"App can't be installed because it is not compatible with this version of ownCloud" => "Die Anwendung konnte nicht installiert werden, weil Sie nicht mit dieser Version von ownCloud kompatibel ist.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Die Applikation konnte nicht installiert werden, da diese das true Tag beinhaltet und dieses, bei nicht mitausgelieferten Applikationen, nicht erlaubt ist ist", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Die Applikation konnte nicht installiert werden, da die Version in der info.xml nicht die gleiche Version wie im App-Store ist", +"App directory already exists" => "Der Ordner für die Anwendung existiert bereits.", +"Can't create app folder. Please fix permissions. %s" => "Der Ordner für die Anwendung konnte nicht angelegt werden. Bitte überprüfen Sie die Ordner- und Dateirechte und passen Sie diese entsprechend an. %s", +"Application is not enabled" => "Die Anwendung ist nicht aktiviert", +"Authentication error" => "Authentifizierungs-Fehler", +"Token expired. Please reload page." => "Token abgelaufen. Bitte laden Sie die Seite neu.", +"Files" => "Dateien", +"Text" => "Text", +"Images" => "Bilder", +"%s enter the database username." => "%s geben Sie den Datenbank-Benutzernamen an.", +"%s enter the database name." => "%s geben Sie den Datenbank-Namen an.", +"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten", +"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Passwort ungültig: %s", +"You need to enter either an existing account or the administrator." => "Sie müssen entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.", +"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig", +"DB Error: \"%s\"" => "DB Fehler: \"%s\"", +"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL Benutzer '%s'@'localhost' existiert bereits.", +"Drop this user from MySQL" => "Lösche diesen Benutzer aus MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits", +"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.", +"Oracle connection could not be established" => "Die Oracle-Verbindung konnte nicht aufgebaut werden.", +"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig", +"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig", +"Set an admin username." => "Setze Administrator Benutzername.", +"Set an admin password." => "Setze Administrator Passwort", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ihr Web-Server ist noch nicht für eine Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.", +"Please double check the installation guides." => "Bitte prüfen Sie die Installationsanleitungen.", +"seconds ago" => "Gerade eben", +"_%n minute ago_::_%n minutes ago_" => array("Vor %n Minute","Vor %n Minuten"), +"_%n hour ago_::_%n hours ago_" => array("Vor %n Stunde","Vor %n Stunden"), +"today" => "Heute", +"yesterday" => "Gestern", +"_%n day go_::_%n days ago_" => array("Vor %n Tag","Vor %n Tagen"), +"last month" => "Letzten Monat", +"_%n month ago_::_%n months ago_" => array("Vor %n Monat","Vor %n Monaten"), +"last year" => "Letztes Jahr", +"years ago" => "Vor Jahren", +"Caused by:" => "Verursacht durch:", +"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden." +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/el.php b/lib/private/l10n/el.php new file mode 100644 index 00000000000..dcbf82d4a4b --- /dev/null +++ b/lib/private/l10n/el.php @@ -0,0 +1,55 @@ + "Βοήθεια", +"Personal" => "Προσωπικά", +"Settings" => "Ρυθμίσεις", +"Users" => "Χρήστες", +"Admin" => "Διαχειριστής", +"Failed to upgrade \"%s\"." => "Αποτυχία αναβάθμισης του \"%s\".", +"web services under your control" => "υπηρεσίες δικτύου υπό τον έλεγχό σας", +"cannot open \"%s\"" => "αδυναμία ανοίγματος \"%s\"", +"ZIP download is turned off." => "Η λήψη ZIP απενεργοποιήθηκε.", +"Files need to be downloaded one by one." => "Τα αρχεία πρέπει να ληφθούν ένα-ένα.", +"Back to Files" => "Πίσω στα Αρχεία", +"Selected files too large to generate zip file." => "Τα επιλεγμένα αρχεία είναι μεγάλα ώστε να δημιουργηθεί αρχείο zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Λήψη των αρχείων σε μικρότερα κομμάτια, χωριστά ή ρωτήστε τον διαχειριστή σας.", +"Application is not enabled" => "Δεν ενεργοποιήθηκε η εφαρμογή", +"Authentication error" => "Σφάλμα πιστοποίησης", +"Token expired. Please reload page." => "Το αναγνωριστικό έληξε. Παρακαλώ φορτώστε ξανά την σελίδα.", +"Files" => "Αρχεία", +"Text" => "Κείμενο", +"Images" => "Εικόνες", +"%s enter the database username." => "%s εισάγετε το όνομα χρήστη της βάσης δεδομένων.", +"%s enter the database name." => "%s εισάγετε το όνομα της βάσης δεδομένων.", +"%s you may not use dots in the database name" => "%s μάλλον δεν χρησιμοποιείτε τελείες στο όνομα της βάσης δεδομένων", +"MS SQL username and/or password not valid: %s" => "Το όνομα χρήστη και/ή ο κωδικός της MS SQL δεν είναι έγκυρα: %s", +"You need to enter either an existing account or the administrator." => "Χρειάζεται να εισάγετε είτε έναν υπάρχον λογαριασμό ή του διαχειριστή.", +"MySQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της MySQL", +"DB Error: \"%s\"" => "Σφάλμα Βάσης Δεδομένων: \"%s\"", +"Offending command was: \"%s\"" => "Η εντολη παραβατικοτητας ηταν: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Υπάρχει ήδη ο χρήστης '%s'@'localhost' της MySQL.", +"Drop this user from MySQL" => "Απόρριψη αυτού του χρήστη από την MySQL", +"MySQL user '%s'@'%%' already exists" => "Ο χρήστης '%s'@'%%' της MySQL υπάρχει ήδη", +"Drop this user from MySQL." => "Απόρριψη αυτού του χρήστη από την MySQL", +"Oracle connection could not be established" => "Αδυναμία σύνδεσης Oracle", +"Oracle username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle", +"Offending command was: \"%s\", name: %s, password: %s" => "Η εντολη παραβατικοτητας ηταν: \"%s\", ονομα: %s, κωδικος: %s", +"PostgreSQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της PostgreSQL", +"Set an admin username." => "Εισάγετε όνομα χρήστη διαχειριστή.", +"Set an admin password." => "Εισάγετε συνθηματικό διαχειριστή.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ο διακομιστής σας δεν έχει ρυθμιστεί κατάλληλα ώστε να επιτρέπει τον συγχρονισμό αρχείων γιατί η διεπαφή WebDAV πιθανόν να είναι κατεστραμμένη.", +"Please double check the installation guides." => "Ελέγξτε ξανά τις οδηγίες εγκατάστασης.", +"seconds ago" => "δευτερόλεπτα πριν", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "σήμερα", +"yesterday" => "χτες", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "τελευταίο μήνα", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "τελευταίο χρόνο", +"years ago" => "χρόνια πριν", +"Caused by:" => "Προκλήθηκε από:", +"Could not find category \"%s\"" => "Αδυναμία εύρεσης κατηγορίας \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/en@pirate.php b/lib/private/l10n/en@pirate.php new file mode 100644 index 00000000000..a8175b1400f --- /dev/null +++ b/lib/private/l10n/en@pirate.php @@ -0,0 +1,9 @@ + "web services under your control", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/en_GB.php b/lib/private/l10n/en_GB.php new file mode 100644 index 00000000000..d02f553eda8 --- /dev/null +++ b/lib/private/l10n/en_GB.php @@ -0,0 +1,72 @@ + "App \"%s\" can't be installed because it is not compatible with this version of ownCloud.", +"No app name specified" => "No app name specified", +"Help" => "Help", +"Personal" => "Personal", +"Settings" => "Settings", +"Users" => "Users", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Failed to upgrade \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Custom profile pictures don't work with encryption yet", +"Unknown filetype" => "Unknown filetype", +"Invalid image" => "Invalid image", +"web services under your control" => "web services under your control", +"cannot open \"%s\"" => "cannot open \"%s\"", +"ZIP download is turned off." => "ZIP download is turned off.", +"Files need to be downloaded one by one." => "Files need to be downloaded one by one.", +"Back to Files" => "Back to Files", +"Selected files too large to generate zip file." => "Selected files too large to generate zip file.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Download the files in smaller chunks, seperately or kindly ask your administrator.", +"No source specified when installing app" => "No source specified when installing app", +"No href specified when installing app from http" => "No href specified when installing app from http", +"No path specified when installing app from local file" => "No path specified when installing app from local file", +"Archives of type %s are not supported" => "Archives of type %s are not supported", +"Failed to open archive when installing app" => "Failed to open archive when installing app", +"App does not provide an info.xml file" => "App does not provide an info.xml file", +"App can't be installed because of not allowed code in the App" => "App can't be installed because of unallowed code in the App", +"App can't be installed because it is not compatible with this version of ownCloud" => "App can't be installed because it is not compatible with this version of ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "App can't be installed because it contains the true tag which is not allowed for non shipped apps", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "App can't be installed because the version in info.xml/version is not the same as the version reported from the app store", +"App directory already exists" => "App directory already exists", +"Can't create app folder. Please fix permissions. %s" => "Can't create app folder. Please fix permissions. %s", +"Application is not enabled" => "Application is not enabled", +"Authentication error" => "Authentication error", +"Token expired. Please reload page." => "Token expired. Please reload page.", +"Files" => "Files", +"Text" => "Text", +"Images" => "Images", +"%s enter the database username." => "%s enter the database username.", +"%s enter the database name." => "%s enter the database name.", +"%s you may not use dots in the database name" => "%s you may not use dots in the database name", +"MS SQL username and/or password not valid: %s" => "MS SQL username and/or password not valid: %s", +"You need to enter either an existing account or the administrator." => "You need to enter either an existing account or the administrator.", +"MySQL username and/or password not valid" => "MySQL username and/or password not valid", +"DB Error: \"%s\"" => "DB Error: \"%s\"", +"Offending command was: \"%s\"" => "Offending command was: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL user '%s'@'localhost' exists already.", +"Drop this user from MySQL" => "Drop this user from MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL user '%s'@'%%' already exists", +"Drop this user from MySQL." => "Drop this user from MySQL.", +"Oracle connection could not be established" => "Oracle connection could not be established", +"Oracle username and/or password not valid" => "Oracle username and/or password not valid", +"Offending command was: \"%s\", name: %s, password: %s" => "Offending command was: \"%s\", name: %s, password: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL username and/or password not valid", +"Set an admin username." => "Set an admin username.", +"Set an admin password." => "Set an admin password.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Your web server is not yet properly setup to allow files synchronisation because the WebDAV interface seems to be broken.", +"Please double check the installation guides." => "Please double check the installation guides.", +"seconds ago" => "seconds ago", +"_%n minute ago_::_%n minutes ago_" => array("%n minute ago","%n minutes ago"), +"_%n hour ago_::_%n hours ago_" => array("%n hour ago","%n hours ago"), +"today" => "today", +"yesterday" => "yesterday", +"_%n day go_::_%n days ago_" => array("%n day go","%n days ago"), +"last month" => "last month", +"_%n month ago_::_%n months ago_" => array("%n month ago","%n months ago"), +"last year" => "last year", +"years ago" => "years ago", +"Caused by:" => "Caused by:", +"Could not find category \"%s\"" => "Could not find category \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/eo.php b/lib/private/l10n/eo.php new file mode 100644 index 00000000000..5311dd6eb15 --- /dev/null +++ b/lib/private/l10n/eo.php @@ -0,0 +1,48 @@ + "Helpo", +"Personal" => "Persona", +"Settings" => "Agordo", +"Users" => "Uzantoj", +"Admin" => "Administranto", +"web services under your control" => "TTT-servoj regataj de vi", +"ZIP download is turned off." => "ZIP-elŝuto estas malkapabligita.", +"Files need to be downloaded one by one." => "Dosieroj devas elŝutiĝi unuope.", +"Back to Files" => "Reen al la dosieroj", +"Selected files too large to generate zip file." => "La elektitaj dosieroj tro grandas por genero de ZIP-dosiero.", +"Application is not enabled" => "La aplikaĵo ne estas kapabligita", +"Authentication error" => "Aŭtentiga eraro", +"Token expired. Please reload page." => "Ĵetono eksvalidiĝis. Bonvolu reŝargi la paĝon.", +"Files" => "Dosieroj", +"Text" => "Teksto", +"Images" => "Bildoj", +"%s enter the database username." => "%s enigu la uzantonomon de la datumbazo.", +"%s enter the database name." => "%s enigu la nomon de la datumbazo.", +"%s you may not use dots in the database name" => "%s vi ne povas uzi punktojn en la nomo de la datumbazo", +"MS SQL username and/or password not valid: %s" => "La uzantonomo de MS SQL aŭ la pasvorto ne validas: %s", +"MySQL username and/or password not valid" => "La uzantonomo de MySQL aŭ la pasvorto ne validas", +"DB Error: \"%s\"" => "Datumbaza eraro: “%s”", +"MySQL user '%s'@'localhost' exists already." => "La uzanto de MySQL “%s”@“localhost” jam ekzistas.", +"Drop this user from MySQL" => "Forigi ĉi tiun uzanton el MySQL", +"MySQL user '%s'@'%%' already exists" => "La uzanto de MySQL “%s”@“%%” jam ekzistas", +"Drop this user from MySQL." => "Forigi ĉi tiun uzanton el MySQL.", +"Oracle connection could not be established" => "Konekto al Oracle ne povas stariĝi", +"Oracle username and/or password not valid" => "La uzantonomo de Oracle aŭ la pasvorto ne validas", +"PostgreSQL username and/or password not valid" => "La uzantonomo de PostgreSQL aŭ la pasvorto ne validas", +"Set an admin username." => "Starigi administran uzantonomon.", +"Set an admin password." => "Starigi administran pasvorton.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Via TTT-servilo ankoraŭ ne ĝuste agordiĝis por permesi sinkronigi dosierojn ĉar la WebDAV-interfaco ŝajnas rompita.", +"Please double check the installation guides." => "Bonvolu duoble kontroli la gvidilon por instalo.", +"seconds ago" => "sekundoj antaŭe", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "hodiaŭ", +"yesterday" => "hieraŭ", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "lastamonate", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "lastajare", +"years ago" => "jaroj antaŭe", +"Could not find category \"%s\"" => "Ne troviĝis kategorio “%s”" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/es.php b/lib/private/l10n/es.php new file mode 100644 index 00000000000..047d5d955bb --- /dev/null +++ b/lib/private/l10n/es.php @@ -0,0 +1,69 @@ + "La aplicación \"%s\" no puede ser instalada porque no es compatible con esta versión de ownCloud", +"No app name specified" => "No se ha especificado nombre de la aplicación", +"Help" => "Ayuda", +"Personal" => "Personal", +"Settings" => "Ajustes", +"Users" => "Usuarios", +"Admin" => "Administración", +"Failed to upgrade \"%s\"." => "Falló la actualización \"%s\".", +"web services under your control" => "Servicios web bajo su control", +"cannot open \"%s\"" => "No se puede abrir \"%s\"", +"ZIP download is turned off." => "La descarga en ZIP está desactivada.", +"Files need to be downloaded one by one." => "Los archivos deben ser descargados uno por uno.", +"Back to Files" => "Volver a Archivos", +"Selected files too large to generate zip file." => "Los archivos seleccionados son demasiado grandes para generar el archivo zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descargue los archivos en trozos más pequeños, por separado o solicítelos amablemente su administrador.", +"No source specified when installing app" => "No se ha especificado origen cuando se ha instalado la aplicación", +"No href specified when installing app from http" => "No href especificado cuando se ha instalado la aplicación", +"No path specified when installing app from local file" => "Sin path especificado cuando se ha instalado la aplicación desde el fichero local", +"Archives of type %s are not supported" => "Ficheros de tipo %s no son soportados", +"Failed to open archive when installing app" => "Fallo de apertura de fichero mientras se instala la aplicación", +"App does not provide an info.xml file" => "La aplicación no suministra un fichero info.xml", +"App can't be installed because of not allowed code in the App" => "La aplicación no puede ser instalada por tener código no autorizado en la aplicación", +"App can't be installed because it is not compatible with this version of ownCloud" => "La aplicación no se puede instalar porque no es compatible con esta versión de ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "La aplicación no se puede instalar porque contiene la etiqueta\n\ntrue\n\nque no está permitida para aplicaciones no distribuidas", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "La aplicación no puede ser instalada por que la versión en info.xml/version no es la misma que la establecida en la app store", +"App directory already exists" => "El directorio de la aplicación ya existe", +"Can't create app folder. Please fix permissions. %s" => "No se puede crear la carpeta de la aplicación. Corrija los permisos. %s", +"Application is not enabled" => "La aplicación no está habilitada", +"Authentication error" => "Error de autenticación", +"Token expired. Please reload page." => "Token expirado. Por favor, recarga la página.", +"Files" => "Archivos", +"Text" => "Texto", +"Images" => "Imágenes", +"%s enter the database username." => "%s ingresar el usuario de la base de datos.", +"%s enter the database name." => "%s ingresar el nombre de la base de datos", +"%s you may not use dots in the database name" => "%s puede utilizar puntos en el nombre de la base de datos", +"MS SQL username and/or password not valid: %s" => "Usuario y/o contraseña de MS SQL no válidos: %s", +"You need to enter either an existing account or the administrator." => "Tiene que ingresar una cuenta existente o la del administrador.", +"MySQL username and/or password not valid" => "Usuario y/o contraseña de MySQL no válidos", +"DB Error: \"%s\"" => "Error BD: \"%s\"", +"Offending command was: \"%s\"" => "Comando infractor: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Usuario MySQL '%s'@'localhost' ya existe.", +"Drop this user from MySQL" => "Eliminar este usuario de MySQL", +"MySQL user '%s'@'%%' already exists" => "Usuario MySQL '%s'@'%%' ya existe", +"Drop this user from MySQL." => "Eliminar este usuario de MySQL.", +"Oracle connection could not be established" => "No se pudo establecer la conexión a Oracle", +"Oracle username and/or password not valid" => "Usuario y/o contraseña de Oracle no válidos", +"Offending command was: \"%s\", name: %s, password: %s" => "Comando infractor: \"%s\", nombre: %s, contraseña: %s", +"PostgreSQL username and/or password not valid" => "Usuario y/o contraseña de PostgreSQL no válidos", +"Set an admin username." => "Configurar un nombre de usuario del administrador", +"Set an admin password." => "Configurar la contraseña del administrador.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Su servidor web aún no está configurado adecuadamente para permitir sincronización de archivos ya que la interfaz WebDAV parece no estar funcionando.", +"Please double check the installation guides." => "Por favor, vuelva a comprobar las guías de instalación.", +"seconds ago" => "hace segundos", +"_%n minute ago_::_%n minutes ago_" => array("Hace %n minuto","Hace %n minutos"), +"_%n hour ago_::_%n hours ago_" => array("Hace %n hora","Hace %n horas"), +"today" => "hoy", +"yesterday" => "ayer", +"_%n day go_::_%n days ago_" => array("Hace %n día","Hace %n días"), +"last month" => "mes pasado", +"_%n month ago_::_%n months ago_" => array("Hace %n mes","Hace %n meses"), +"last year" => "año pasado", +"years ago" => "hace años", +"Caused by:" => "Causado por:", +"Could not find category \"%s\"" => "No puede encontrar la categoria \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/es_AR.php b/lib/private/l10n/es_AR.php new file mode 100644 index 00000000000..f637eb403ed --- /dev/null +++ b/lib/private/l10n/es_AR.php @@ -0,0 +1,69 @@ + "La app \"%s\" no puede ser instalada porque no es compatible con esta versión de ownCloud", +"No app name specified" => "No fue especificado el nombre de la app", +"Help" => "Ayuda", +"Personal" => "Personal", +"Settings" => "Configuración", +"Users" => "Usuarios", +"Admin" => "Administración", +"Failed to upgrade \"%s\"." => "No se pudo actualizar \"%s\".", +"web services under your control" => "servicios web sobre los que tenés control", +"cannot open \"%s\"" => "no se puede abrir \"%s\"", +"ZIP download is turned off." => "La descarga en ZIP está desactivada.", +"Files need to be downloaded one by one." => "Los archivos deben ser descargados de a uno.", +"Back to Files" => "Volver a Archivos", +"Selected files too large to generate zip file." => "Los archivos seleccionados son demasiado grandes para generar el archivo zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descargá los archivos en partes más chicas, de forma separada, o pedíselos al administrador", +"No source specified when installing app" => "No se especificó el origen al instalar la app", +"No href specified when installing app from http" => "No se especificó href al instalar la app", +"No path specified when installing app from local file" => "No se especificó PATH al instalar la app desde el archivo local", +"Archives of type %s are not supported" => "No hay soporte para archivos de tipo %s", +"Failed to open archive when installing app" => "Error al abrir archivo mientras se instalaba la app", +"App does not provide an info.xml file" => "La app no suministra un archivo info.xml", +"App can't be installed because of not allowed code in the App" => "No puede ser instalada la app por tener código no autorizado", +"App can't be installed because it is not compatible with this version of ownCloud" => "No se puede instalar la app porque no es compatible con esta versión de ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "La app no se puede instalar porque contiene la etiqueta true que no está permitida para apps no distribuidas", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "La app no puede ser instalada porque la versión en info.xml/version no es la misma que la establecida en el app store", +"App directory already exists" => "El directorio de la app ya existe", +"Can't create app folder. Please fix permissions. %s" => "No se puede crear el directorio para la app. Corregí los permisos. %s", +"Application is not enabled" => "La aplicación no está habilitada", +"Authentication error" => "Error al autenticar", +"Token expired. Please reload page." => "Token expirado. Por favor, recargá la página.", +"Files" => "Archivos", +"Text" => "Texto", +"Images" => "Imágenes", +"%s enter the database username." => "%s Entrá el usuario de la base de datos", +"%s enter the database name." => "%s Entrá el nombre de la base de datos.", +"%s you may not use dots in the database name" => "%s no podés usar puntos en el nombre de la base de datos", +"MS SQL username and/or password not valid: %s" => "Nombre de usuario y contraseña de MS SQL no son válidas: %s", +"You need to enter either an existing account or the administrator." => "Tenés que ingresar una cuenta existente o el administrador.", +"MySQL username and/or password not valid" => "Usuario y/o contraseña MySQL no válido", +"DB Error: \"%s\"" => "Error DB: \"%s\"", +"Offending command was: \"%s\"" => "El comando no comprendido es: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Usuario MySQL '%s'@'localhost' ya existe.", +"Drop this user from MySQL" => "Borrar este usuario de MySQL", +"MySQL user '%s'@'%%' already exists" => "Usuario MySQL '%s'@'%%' ya existe", +"Drop this user from MySQL." => "Borrar este usuario de MySQL", +"Oracle connection could not be established" => "No fue posible establecer la conexión a Oracle", +"Oracle username and/or password not valid" => "El nombre de usuario y/o contraseña no son válidos", +"Offending command was: \"%s\", name: %s, password: %s" => "El comando no comprendido es: \"%s\", nombre: \"%s\", contraseña: \"%s\"", +"PostgreSQL username and/or password not valid" => "Nombre de usuario o contraseña PostgradeSQL inválido.", +"Set an admin username." => "Configurar un nombre de administrador.", +"Set an admin password." => "Configurar una contraseña de administrador.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Tu servidor web no está configurado todavía para permitir sincronización de archivos porque la interfaz WebDAV parece no funcionar.", +"Please double check the installation guides." => "Por favor, comprobá nuevamente la guía de instalación.", +"seconds ago" => "segundos atrás", +"_%n minute ago_::_%n minutes ago_" => array("Hace %n minuto","Hace %n minutos"), +"_%n hour ago_::_%n hours ago_" => array("Hace %n hora","Hace %n horas"), +"today" => "hoy", +"yesterday" => "ayer", +"_%n day go_::_%n days ago_" => array("Hace %n día","Hace %n días"), +"last month" => "el mes pasado", +"_%n month ago_::_%n months ago_" => array("Hace %n mes","Hace %n meses"), +"last year" => "el año pasado", +"years ago" => "años atrás", +"Caused by:" => "Provocado por:", +"Could not find category \"%s\"" => "No fue posible encontrar la categoría \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/es_MX.php b/lib/private/l10n/es_MX.php new file mode 100644 index 00000000000..15f78e0bce6 --- /dev/null +++ b/lib/private/l10n/es_MX.php @@ -0,0 +1,8 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/et_EE.php b/lib/private/l10n/et_EE.php new file mode 100644 index 00000000000..85dfaeb52d5 --- /dev/null +++ b/lib/private/l10n/et_EE.php @@ -0,0 +1,72 @@ + "Rakendit \"%s\" ei saa paigaldada, kuna see pole ühilduv selle ownCloud versiooniga.", +"No app name specified" => "Ühegi rakendi nime pole määratletud", +"Help" => "Abiinfo", +"Personal" => "Isiklik", +"Settings" => "Seaded", +"Users" => "Kasutajad", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Ebaõnnestunud uuendus \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Kohandatud profiili pildid ei toimi veel koos krüpteeringuga", +"Unknown filetype" => "Tundmatu failitüüp", +"Invalid image" => "Vigane pilt", +"web services under your control" => "veebitenused sinu kontrolli all", +"cannot open \"%s\"" => "ei suuda avada \"%s\"", +"ZIP download is turned off." => "ZIP-ina allalaadimine on välja lülitatud.", +"Files need to be downloaded one by one." => "Failid tuleb alla laadida ükshaaval.", +"Back to Files" => "Tagasi failide juurde", +"Selected files too large to generate zip file." => "Valitud failid on ZIP-faili loomiseks liiga suured.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Laadi failid alla eraldi väiksemate osadena või küsi nõu oma süsteemiadminstraatorilt.", +"No source specified when installing app" => "Ühegi lähteallikat pole rakendi paigalduseks määratletud", +"No href specified when installing app from http" => "Ühtegi aadressi pole määratletud rakendi paigalduseks veebist", +"No path specified when installing app from local file" => "Ühtegi teed pole määratletud paigaldamaks rakendit kohalikust failist", +"Archives of type %s are not supported" => "%s tüüpi arhiivid pole toetatud", +"Failed to open archive when installing app" => "Arhiivi avamine ebaõnnestus rakendi paigalduse käigus", +"App does not provide an info.xml file" => "Rakend ei paku ühtegi info.xml faili", +"App can't be installed because of not allowed code in the App" => "Rakendit ei saa paigaldada, kuna sisaldab lubamatud koodi", +"App can't be installed because it is not compatible with this version of ownCloud" => "Rakendit ei saa paigaldada, kuna see pole ühilduv selle ownCloud versiooniga.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Rakendit ei saa paigaldada, kuna see sisaldab \n\n\ntrue\n\nmärgendit, mis pole lubatud mitte veetud (non shipped) rakendites", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Rakendit ei saa paigaldada, kuna selle versioon info.xml/version pole sama, mis on märgitud rakendite laos.", +"App directory already exists" => "Rakendi kataloog on juba olemas", +"Can't create app folder. Please fix permissions. %s" => "Ei saa luua rakendi kataloogi. Palun korrigeeri õigusi. %s", +"Application is not enabled" => "Rakendus pole sisse lülitatud", +"Authentication error" => "Autentimise viga", +"Token expired. Please reload page." => "Kontrollkood aegus. Paelun lae leht uuesti.", +"Files" => "Failid", +"Text" => "Tekst", +"Images" => "Pildid", +"%s enter the database username." => "%s sisesta andmebaasi kasutajatunnus.", +"%s enter the database name." => "%s sisesta andmebaasi nimi.", +"%s you may not use dots in the database name" => "%s punktide kasutamine andmebaasi nimes pole lubatud", +"MS SQL username and/or password not valid: %s" => "MS SQL kasutajatunnus ja/või parool pole õiged: %s", +"You need to enter either an existing account or the administrator." => "Sisesta kas juba olemasolev konto või administrator.", +"MySQL username and/or password not valid" => "MySQL kasutajatunnus ja/või parool pole õiged", +"DB Error: \"%s\"" => "Andmebaasi viga: \"%s\"", +"Offending command was: \"%s\"" => "Tõrkuv käsk oli: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL kasutaja '%s'@'localhost' on juba olemas.", +"Drop this user from MySQL" => "Kustuta see kasutaja MySQL-ist", +"MySQL user '%s'@'%%' already exists" => "MySQL kasutaja '%s'@'%%' on juba olemas", +"Drop this user from MySQL." => "Kustuta see kasutaja MySQL-ist.", +"Oracle connection could not be established" => "Ei suuda luua ühendust Oracle baasiga", +"Oracle username and/or password not valid" => "Oracle kasutajatunnus ja/või parool pole õiged", +"Offending command was: \"%s\", name: %s, password: %s" => "Tõrkuv käsk oli: \"%s\", nimi: %s, parool: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL kasutajatunnus ja/või parool pole õiged", +"Set an admin username." => "Määra admin kasutajanimi.", +"Set an admin password." => "Määra admini parool.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Veebiserveri ei ole veel korralikult seadistatud võimaldamaks failide sünkroniseerimist, kuna WebDAV liides näib olevat mittetoimiv.", +"Please double check the installation guides." => "Palun tutvu veelkord paigalduse juhenditega.", +"seconds ago" => "sekundit tagasi", +"_%n minute ago_::_%n minutes ago_" => array("","%n minutit tagasi"), +"_%n hour ago_::_%n hours ago_" => array("","%n tundi tagasi"), +"today" => "täna", +"yesterday" => "eile", +"_%n day go_::_%n days ago_" => array("","%n päeva tagasi"), +"last month" => "viimasel kuul", +"_%n month ago_::_%n months ago_" => array("","%n kuud tagasi"), +"last year" => "viimasel aastal", +"years ago" => "aastat tagasi", +"Caused by:" => "Põhjustaja:", +"Could not find category \"%s\"" => "Ei leia kategooriat \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/eu.php b/lib/private/l10n/eu.php new file mode 100644 index 00000000000..413819f4f94 --- /dev/null +++ b/lib/private/l10n/eu.php @@ -0,0 +1,55 @@ + "Laguntza", +"Personal" => "Pertsonala", +"Settings" => "Ezarpenak", +"Users" => "Erabiltzaileak", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Ezin izan da \"%s\" eguneratu.", +"web services under your control" => "web zerbitzuak zure kontrolpean", +"cannot open \"%s\"" => "ezin da \"%s\" ireki", +"ZIP download is turned off." => "ZIP deskarga ez dago gaituta.", +"Files need to be downloaded one by one." => "Fitxategiak banan-banan deskargatu behar dira.", +"Back to Files" => "Itzuli fitxategietara", +"Selected files too large to generate zip file." => "Hautatuko fitxategiak oso handiak dira zip fitxategia sortzeko.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Deskargatu fitzategiak zati txikiagoetan, banan-banan edo eskatu mesedez zure administradoreari", +"Application is not enabled" => "Aplikazioa ez dago gaituta", +"Authentication error" => "Autentifikazio errorea", +"Token expired. Please reload page." => "Tokena iraungitu da. Mesedez birkargatu orria.", +"Files" => "Fitxategiak", +"Text" => "Testua", +"Images" => "Irudiak", +"%s enter the database username." => "%s sartu datu basearen erabiltzaile izena.", +"%s enter the database name." => "%s sartu datu basearen izena.", +"%s you may not use dots in the database name" => "%s ezin duzu punturik erabili datu basearen izenean.", +"MS SQL username and/or password not valid: %s" => "MS SQL erabiltzaile izena edota pasahitza ez dira egokiak: %s", +"You need to enter either an existing account or the administrator." => "Existitzen den kontu bat edo administradorearena jarri behar duzu.", +"MySQL username and/or password not valid" => "MySQL erabiltzaile edota pasahitza ez dira egokiak.", +"DB Error: \"%s\"" => "DB errorea: \"%s\"", +"Offending command was: \"%s\"" => "Errorea komando honek sortu du: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL '%s'@'localhost' erabiltzailea dagoeneko existitzen da.", +"Drop this user from MySQL" => "Ezabatu erabiltzaile hau MySQLtik", +"MySQL user '%s'@'%%' already exists" => "MySQL '%s'@'%%' erabiltzailea dagoeneko existitzen da", +"Drop this user from MySQL." => "Ezabatu erabiltzaile hau MySQLtik.", +"Oracle connection could not be established" => "Ezin da Oracle konexioa sortu", +"Oracle username and/or password not valid" => "Oracle erabiltzaile edota pasahitza ez dira egokiak.", +"Offending command was: \"%s\", name: %s, password: %s" => "Errorea komando honek sortu du: \"%s\", izena: %s, pasahitza: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL erabiltzaile edota pasahitza ez dira egokiak.", +"Set an admin username." => "Ezarri administraziorako erabiltzaile izena.", +"Set an admin password." => "Ezarri administraziorako pasahitza.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Zure web zerbitzaria ez dago oraindik ongi konfiguratuta fitxategien sinkronizazioa egiteko, WebDAV interfazea ongi ez dagoela dirudi.", +"Please double check the installation guides." => "Mesedez begiratu instalazio gidak.", +"seconds ago" => "segundu", +"_%n minute ago_::_%n minutes ago_" => array("orain dela minutu %n","orain dela %n minutu"), +"_%n hour ago_::_%n hours ago_" => array("orain dela ordu %n","orain dela %n ordu"), +"today" => "gaur", +"yesterday" => "atzo", +"_%n day go_::_%n days ago_" => array("orain dela egun %n","orain dela %n egun"), +"last month" => "joan den hilabetean", +"_%n month ago_::_%n months ago_" => array("orain dela hilabete %n","orain dela %n hilabete"), +"last year" => "joan den urtean", +"years ago" => "urte", +"Caused by:" => "Honek eraginda:", +"Could not find category \"%s\"" => "Ezin da \"%s\" kategoria aurkitu" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/fa.php b/lib/private/l10n/fa.php new file mode 100644 index 00000000000..e9cb695bade --- /dev/null +++ b/lib/private/l10n/fa.php @@ -0,0 +1,51 @@ + "راه‌نما", +"Personal" => "شخصی", +"Settings" => "تنظیمات", +"Users" => "کاربران", +"Admin" => "مدیر", +"web services under your control" => "سرویس های تحت وب در کنترل شما", +"ZIP download is turned off." => "دانلود به صورت فشرده غیر فعال است", +"Files need to be downloaded one by one." => "فایل ها باید به صورت یکی یکی دانلود شوند", +"Back to Files" => "بازگشت به فایل ها", +"Selected files too large to generate zip file." => "فایل های انتخاب شده بزرگتر از آن هستند که بتوان یک فایل فشرده تولید کرد", +"Application is not enabled" => "برنامه فعال نشده است", +"Authentication error" => "خطا در اعتبار سنجی", +"Token expired. Please reload page." => "رمز منقضی شده است. لطفا دوباره صفحه را بارگذاری نمایید.", +"Files" => "پرونده‌ها", +"Text" => "متن", +"Images" => "تصاویر", +"%s enter the database username." => "%s نام کاربری پایگاه داده را وارد نمایید.", +"%s enter the database name." => "%s نام پایگاه داده را وارد نمایید.", +"%s you may not use dots in the database name" => "%s شما نباید از نقطه در نام پایگاه داده استفاده نمایید.", +"MS SQL username and/or password not valid: %s" => "نام کاربری و / یا رمزعبور MS SQL معتبر نیست: %s", +"You need to enter either an existing account or the administrator." => "شما نیاز به وارد کردن یک حساب کاربری موجود یا حساب مدیریتی دارید.", +"MySQL username and/or password not valid" => "نام کاربری و / یا رمزعبور MySQL معتبر نیست.", +"DB Error: \"%s\"" => "خطای پایگاه داده: \"%s\"", +"Offending command was: \"%s\"" => "دستور متخلف عبارت است از: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "کاربرMySQL '%s'@'localhost' درحال حاضر موجود است.", +"Drop this user from MySQL" => "این کاربر را از MySQL حذف نمایید.", +"MySQL user '%s'@'%%' already exists" => "کاربر'%s'@'%%' MySQL در حال حاضر موجود است.", +"Drop this user from MySQL." => "این کاربر را از MySQL حذف نمایید.", +"Oracle connection could not be established" => "ارتباط اراکل نمیتواند برقرار باشد.", +"Oracle username and/or password not valid" => "نام کاربری و / یا رمزعبور اراکل معتبر نیست.", +"Offending command was: \"%s\", name: %s, password: %s" => "دستور متخلف عبارت است از: \"%s\"، نام: \"%s\"، رمزعبور:\"%s\"", +"PostgreSQL username and/or password not valid" => "PostgreSQL نام کاربری و / یا رمزعبور معتبر نیست.", +"Set an admin username." => "یک نام کاربری برای مدیر تنظیم نمایید.", +"Set an admin password." => "یک رمزعبور برای مدیر تنظیم نمایید.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "احتمالاً وب سرور شما طوری تنظیم نشده است که اجازه ی همگام سازی فایلها را بدهد زیرا به نظر میرسد رابط WebDAV از کار افتاده است.", +"Please double check the installation guides." => "لطفاً دوباره راهنمای نصبرا بررسی کنید.", +"seconds ago" => "ثانیه‌ها پیش", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "امروز", +"yesterday" => "دیروز", +"_%n day go_::_%n days ago_" => array(""), +"last month" => "ماه قبل", +"_%n month ago_::_%n months ago_" => array(""), +"last year" => "سال قبل", +"years ago" => "سال‌های قبل", +"Could not find category \"%s\"" => "دسته بندی %s یافت نشد" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/fi.php b/lib/private/l10n/fi.php new file mode 100644 index 00000000000..ac1f80a8f73 --- /dev/null +++ b/lib/private/l10n/fi.php @@ -0,0 +1,5 @@ + "asetukset" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/fi_FI.php b/lib/private/l10n/fi_FI.php new file mode 100644 index 00000000000..1d2bdab749c --- /dev/null +++ b/lib/private/l10n/fi_FI.php @@ -0,0 +1,62 @@ + "Sovellusta \"%s\" ei voi asentaa, koska se ei ole yhteensopiva käytössä olevan ownCloud-version kanssa.", +"No app name specified" => "Sovelluksen nimeä ei määritelty", +"Help" => "Ohje", +"Personal" => "Henkilökohtainen", +"Settings" => "Asetukset", +"Users" => "Käyttäjät", +"Admin" => "Ylläpitäjä", +"Failed to upgrade \"%s\"." => "Kohteen \"%s\" päivitys epäonnistui.", +"Custom profile pictures don't work with encryption yet" => "Omavalintaiset profiilikuvat eivät toimi salauksen kanssa vielä", +"Unknown filetype" => "Tuntematon tiedostotyyppi", +"Invalid image" => "Virheellinen kuva", +"web services under your control" => "verkkopalvelut hallinnassasi", +"ZIP download is turned off." => "ZIP-lataus on poistettu käytöstä.", +"Files need to be downloaded one by one." => "Tiedostot on ladattava yksittäin.", +"Back to Files" => "Takaisin tiedostoihin", +"Selected files too large to generate zip file." => "Valitut tiedostot ovat liian suurikokoisia mahtuakseen zip-tiedostoon.", +"No source specified when installing app" => "Lähdettä ei määritelty sovellusta asennettaessa", +"No path specified when installing app from local file" => "Polkua ei määritelty sovellusta asennettaessa paikallisesta tiedostosta", +"Archives of type %s are not supported" => "Tyypin %s arkistot eivät ole tuettuja", +"App does not provide an info.xml file" => "Sovellus ei sisällä info.xml-tiedostoa", +"App can't be installed because of not allowed code in the App" => "Sovellusta ei voi asentaa, koska sovellus sisältää kiellettyä koodia", +"App can't be installed because it is not compatible with this version of ownCloud" => "Sovellusta ei voi asentaa, koska se ei ole yhteensopiva käytössä olevan ownCloud-version kanssa", +"App directory already exists" => "Sovelluskansio on jo olemassa", +"Can't create app folder. Please fix permissions. %s" => "Sovelluskansion luominen ei onnistu. Korjaa käyttöoikeudet. %s", +"Application is not enabled" => "Sovellusta ei ole otettu käyttöön", +"Authentication error" => "Tunnistautumisvirhe", +"Token expired. Please reload page." => "Valtuutus vanheni. Lataa sivu uudelleen.", +"Files" => "Tiedostot", +"Text" => "Teksti", +"Images" => "Kuvat", +"%s enter the database username." => "%s anna tietokannan käyttäjätunnus.", +"%s enter the database name." => "%s anna tietokannan nimi.", +"%s you may not use dots in the database name" => "%s et voi käyttää pisteitä tietokannan nimessä", +"MS SQL username and/or password not valid: %s" => "MS SQL -käyttäjätunnus ja/tai -salasana on väärin: %s", +"MySQL username and/or password not valid" => "MySQL:n käyttäjätunnus ja/tai salasana on väärin", +"DB Error: \"%s\"" => "Tietokantavirhe: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL-käyttäjä '%s'@'localhost' on jo olemassa.", +"Drop this user from MySQL" => "Pudota tämä käyttäjä MySQL:stä", +"MySQL user '%s'@'%%' already exists" => "MySQL-käyttäjä '%s'@'%%' on jo olemassa", +"Drop this user from MySQL." => "Pudota tämä käyttäjä MySQL:stä.", +"Oracle connection could not be established" => "Oracle-yhteyttä ei voitu muodostaa", +"Oracle username and/or password not valid" => "Oraclen käyttäjätunnus ja/tai salasana on väärin", +"PostgreSQL username and/or password not valid" => "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin", +"Set an admin username." => "Aseta ylläpitäjän käyttäjätunnus.", +"Set an admin password." => "Aseta ylläpitäjän salasana.", +"Please double check the installation guides." => "Lue tarkasti asennusohjeet.", +"seconds ago" => "sekuntia sitten", +"_%n minute ago_::_%n minutes ago_" => array("%n minuutti sitten","%n minuuttia sitten"), +"_%n hour ago_::_%n hours ago_" => array("%n tunti sitten","%n tuntia sitten"), +"today" => "tänään", +"yesterday" => "eilen", +"_%n day go_::_%n days ago_" => array("%n päivä sitten","%n päivää sitten"), +"last month" => "viime kuussa", +"_%n month ago_::_%n months ago_" => array("%n kuukausi sitten","%n kuukautta sitten"), +"last year" => "viime vuonna", +"years ago" => "vuotta sitten", +"Caused by:" => "Aiheuttaja:", +"Could not find category \"%s\"" => "Luokkaa \"%s\" ei löytynyt" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/fr.php b/lib/private/l10n/fr.php new file mode 100644 index 00000000000..ab3d618849e --- /dev/null +++ b/lib/private/l10n/fr.php @@ -0,0 +1,72 @@ + "L'application \"%s\" ne peut être installée car elle n'est pas compatible avec cette version de ownCloud.", +"No app name specified" => "Aucun nom d'application spécifié", +"Help" => "Aide", +"Personal" => "Personnel", +"Settings" => "Paramètres", +"Users" => "Utilisateurs", +"Admin" => "Administration", +"Failed to upgrade \"%s\"." => "Echec de la mise à niveau \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Les images de profil personnalisées ne fonctionnent pas encore avec le système de chiffrement.", +"Unknown filetype" => "Type de fichier inconnu", +"Invalid image" => "Image invalide", +"web services under your control" => "services web sous votre contrôle", +"cannot open \"%s\"" => "impossible d'ouvrir \"%s\"", +"ZIP download is turned off." => "Téléchargement ZIP désactivé.", +"Files need to be downloaded one by one." => "Les fichiers nécessitent d'être téléchargés un par un.", +"Back to Files" => "Retour aux Fichiers", +"Selected files too large to generate zip file." => "Les fichiers sélectionnés sont trop volumineux pour être compressés.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Télécharger les fichiers en parties plus petites, séparément ou demander avec bienveillance à votre administrateur.", +"No source specified when installing app" => "Aucune source spécifiée pour installer l'application", +"No href specified when installing app from http" => "Aucun href spécifié pour installer l'application par http", +"No path specified when installing app from local file" => "Aucun chemin spécifié pour installer l'application depuis un fichier local", +"Archives of type %s are not supported" => "Les archives de type %s ne sont pas supportées", +"Failed to open archive when installing app" => "Échec de l'ouverture de l'archive lors de l'installation de l'application", +"App does not provide an info.xml file" => "L'application ne fournit pas de fichier info.xml", +"App can't be installed because of not allowed code in the App" => "L'application ne peut être installée car elle contient du code non-autorisé", +"App can't be installed because it is not compatible with this version of ownCloud" => "L'application ne peut être installée car elle n'est pas compatible avec cette version de ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "L'application ne peut être installée car elle contient la balise true qui n'est pas autorisée pour les applications non-diffusées", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "L'application ne peut être installée car la version de info.xml/version n'est identique à celle indiquée sur l'app store", +"App directory already exists" => "Le dossier de l'application existe déjà", +"Can't create app folder. Please fix permissions. %s" => "Impossible de créer le dossier de l'application. Corrigez les droits d'accès. %s", +"Application is not enabled" => "L'application n'est pas activée", +"Authentication error" => "Erreur d'authentification", +"Token expired. Please reload page." => "La session a expiré. Veuillez recharger la page.", +"Files" => "Fichiers", +"Text" => "Texte", +"Images" => "Images", +"%s enter the database username." => "%s entrez le nom d'utilisateur de la base de données.", +"%s enter the database name." => "%s entrez le nom de la base de données.", +"%s you may not use dots in the database name" => "%s vous nez pouvez pas utiliser de points dans le nom de la base de données", +"MS SQL username and/or password not valid: %s" => "Le nom d'utilisateur et/ou le mot de passe de la base MS SQL est invalide : %s", +"You need to enter either an existing account or the administrator." => "Vous devez spécifier soit le nom d'un compte existant, soit celui de l'administrateur.", +"MySQL username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base MySQL invalide", +"DB Error: \"%s\"" => "Erreur de la base de données : \"%s\"", +"Offending command was: \"%s\"" => "La requête en cause est : \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "L'utilisateur MySQL '%s'@'localhost' existe déjà.", +"Drop this user from MySQL" => "Retirer cet utilisateur de la base MySQL", +"MySQL user '%s'@'%%' already exists" => "L'utilisateur MySQL '%s'@'%%' existe déjà", +"Drop this user from MySQL." => "Retirer cet utilisateur de la base MySQL.", +"Oracle connection could not be established" => "La connexion Oracle ne peut pas être établie", +"Oracle username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base Oracle invalide", +"Offending command was: \"%s\", name: %s, password: %s" => "La requête en cause est : \"%s\", nom : %s, mot de passe : %s", +"PostgreSQL username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL invalide", +"Set an admin username." => "Spécifiez un nom d'utilisateur pour l'administrateur.", +"Set an admin password." => "Spécifiez un mot de passe administrateur.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Votre serveur web, n'est pas correctement configuré pour permettre la synchronisation des fichiers, car l'interface WebDav ne fonctionne pas comme il faut.", +"Please double check the installation guides." => "Veuillez vous référer au guide d'installation.", +"seconds ago" => "il y a quelques secondes", +"_%n minute ago_::_%n minutes ago_" => array("","il y a %n minutes"), +"_%n hour ago_::_%n hours ago_" => array("","Il y a %n heures"), +"today" => "aujourd'hui", +"yesterday" => "hier", +"_%n day go_::_%n days ago_" => array("","il y a %n jours"), +"last month" => "le mois dernier", +"_%n month ago_::_%n months ago_" => array("","Il y a %n mois"), +"last year" => "l'année dernière", +"years ago" => "il y a plusieurs années", +"Caused by:" => "Causé par :", +"Could not find category \"%s\"" => "Impossible de trouver la catégorie \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/private/l10n/gl.php b/lib/private/l10n/gl.php new file mode 100644 index 00000000000..406272d690f --- /dev/null +++ b/lib/private/l10n/gl.php @@ -0,0 +1,72 @@ + "Non é posíbel instalar o aplicativo «%s» por non seren compatíbel con esta versión do ownCloud.", +"No app name specified" => "Non se especificou o nome do aplicativo", +"Help" => "Axuda", +"Personal" => "Persoal", +"Settings" => "Axustes", +"Users" => "Usuarios", +"Admin" => "Administración", +"Failed to upgrade \"%s\"." => "Non foi posíbel anovar «%s».", +"Custom profile pictures don't work with encryption yet" => "As imaxes personalizadas de perfil aínda non funcionan co cifrado", +"Unknown filetype" => "Tipo de ficheiro descoñecido", +"Invalid image" => "Imaxe incorrecta", +"web services under your control" => "servizos web baixo o seu control", +"cannot open \"%s\"" => "non foi posíbel abrir «%s»", +"ZIP download is turned off." => "As descargas ZIP están desactivadas.", +"Files need to be downloaded one by one." => "Os ficheiros necesitan seren descargados dun en un.", +"Back to Files" => "Volver aos ficheiros", +"Selected files too large to generate zip file." => "Os ficheiros seleccionados son demasiado grandes como para xerar un ficheiro zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descargue os ficheiros en cachos máis pequenos e por separado, ou pídallos amabelmente ao seu administrador.", +"No source specified when installing app" => "Non foi especificada ningunha orixe ao instalar aplicativos", +"No href specified when installing app from http" => "Non foi especificada ningunha href ao instalar aplicativos", +"No path specified when installing app from local file" => "Non foi especificada ningunha ruta ao instalar aplicativos desde un ficheiro local", +"Archives of type %s are not supported" => "Os arquivos do tipo %s non están admitidos", +"Failed to open archive when installing app" => "Non foi posíbel abrir o arquivo ao instalar aplicativos", +"App does not provide an info.xml file" => "O aplicativo non fornece un ficheiro info.xml", +"App can't be installed because of not allowed code in the App" => "Non é posíbel instalar o aplicativo por mor de conter código non permitido", +"App can't be installed because it is not compatible with this version of ownCloud" => "Non é posíbel instalar o aplicativo por non seren compatíbel con esta versión do ownCloud.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Non é posíbel instalar o aplicativo por conter a etiqueta\n\n\ntrue\n\nque non está permitida para os aplicativos non enviados", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Non é posíbel instalar o aplicativo xa que a versión en info.xml/version non é a mesma que a versión informada desde a App Store", +"App directory already exists" => "Xa existe o directorio do aplicativo", +"Can't create app folder. Please fix permissions. %s" => "Non é posíbel crear o cartafol de aplicativos. Corrixa os permisos. %s", +"Application is not enabled" => "O aplicativo non está activado", +"Authentication error" => "Produciuse un erro de autenticación", +"Token expired. Please reload page." => "Testemuña caducada. Recargue a páxina.", +"Files" => "Ficheiros", +"Text" => "Texto", +"Images" => "Imaxes", +"%s enter the database username." => "%s introduza o nome de usuario da base de datos", +"%s enter the database name." => "%s introduza o nome da base de datos", +"%s you may not use dots in the database name" => "%s non se poden empregar puntos na base de datos", +"MS SQL username and/or password not valid: %s" => "Nome de usuario e/ou contrasinal de MS SQL incorrecto: %s", +"You need to enter either an existing account or the administrator." => "Deberá introducir unha conta existente ou o administrador.", +"MySQL username and/or password not valid" => "Nome de usuario e/ou contrasinal de MySQL incorrecto", +"DB Error: \"%s\"" => "Produciuse un erro na base de datos: «%s»", +"Offending command was: \"%s\"" => "A orde ofensiva foi: «%s»", +"MySQL user '%s'@'localhost' exists already." => "O usuario MySQL '%s'@'localhost' xa existe.", +"Drop this user from MySQL" => "Omitir este usuario de MySQL", +"MySQL user '%s'@'%%' already exists" => "O usuario MySQL «%s»@«%%» xa existe.", +"Drop this user from MySQL." => "Omitir este usuario de MySQL.", +"Oracle connection could not be established" => "Non foi posíbel estabelecer a conexión con Oracle", +"Oracle username and/or password not valid" => "Nome de usuario e/ou contrasinal de Oracle incorrecto", +"Offending command was: \"%s\", name: %s, password: %s" => "A orde ofensiva foi: «%s», nome: %s, contrasinal: %s", +"PostgreSQL username and/or password not valid" => "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto", +"Set an admin username." => "Estabeleza un nome de usuario administrador", +"Set an admin password." => "Estabeleza un contrasinal de administrador", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "O seu servidor web non está aínda configurado adecuadamente para permitir a sincronización de ficheiros xa que semella que a interface WebDAV non está a funcionar.", +"Please double check the installation guides." => "Volva comprobar as guías de instalación", +"seconds ago" => "segundos atrás", +"_%n minute ago_::_%n minutes ago_" => array("hai %n minuto","hai %n minutos"), +"_%n hour ago_::_%n hours ago_" => array("hai %n hora","hai %n horas"), +"today" => "hoxe", +"yesterday" => "onte", +"_%n day go_::_%n days ago_" => array("hai %n día","hai %n días"), +"last month" => "último mes", +"_%n month ago_::_%n months ago_" => array("hai %n mes","hai %n meses"), +"last year" => "último ano", +"years ago" => "anos atrás", +"Caused by:" => "Causado por:", +"Could not find category \"%s\"" => "Non foi posíbel atopar a categoría «%s»" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/he.php b/lib/private/l10n/he.php new file mode 100644 index 00000000000..ced6244ee91 --- /dev/null +++ b/lib/private/l10n/he.php @@ -0,0 +1,33 @@ + "עזרה", +"Personal" => "אישי", +"Settings" => "הגדרות", +"Users" => "משתמשים", +"Admin" => "מנהל", +"web services under your control" => "שירותי רשת תחת השליטה שלך", +"ZIP download is turned off." => "הורדת ZIP כבויה", +"Files need to be downloaded one by one." => "יש להוריד את הקבצים אחד אחרי השני.", +"Back to Files" => "חזרה לקבצים", +"Selected files too large to generate zip file." => "הקבצים הנבחרים גדולים מידי ליצירת קובץ zip.", +"Application is not enabled" => "יישומים אינם מופעלים", +"Authentication error" => "שגיאת הזדהות", +"Token expired. Please reload page." => "פג תוקף. נא לטעון שוב את הדף.", +"Files" => "קבצים", +"Text" => "טקסט", +"Images" => "תמונות", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "שרת האינטרנט שלך אינו מוגדר לצורכי סנכרון קבצים עדיין כיוון שמנשק ה־WebDAV כנראה אינו תקין.", +"Please double check the installation guides." => "נא לעיין שוב במדריכי ההתקנה.", +"seconds ago" => "שניות", +"_%n minute ago_::_%n minutes ago_" => array("","לפני %n דקות"), +"_%n hour ago_::_%n hours ago_" => array("","לפני %n שעות"), +"today" => "היום", +"yesterday" => "אתמול", +"_%n day go_::_%n days ago_" => array("","לפני %n ימים"), +"last month" => "חודש שעבר", +"_%n month ago_::_%n months ago_" => array("","לפני %n חודשים"), +"last year" => "שנה שעברה", +"years ago" => "שנים", +"Could not find category \"%s\"" => "לא ניתן למצוא את הקטגוריה „%s“" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/hi.php b/lib/private/l10n/hi.php new file mode 100644 index 00000000000..039dfa4465d --- /dev/null +++ b/lib/private/l10n/hi.php @@ -0,0 +1,12 @@ + "सहयोग", +"Personal" => "यक्तिगत", +"Settings" => "सेटिंग्स", +"Users" => "उपयोगकर्ता", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/hr.php b/lib/private/l10n/hr.php new file mode 100644 index 00000000000..d217f924099 --- /dev/null +++ b/lib/private/l10n/hr.php @@ -0,0 +1,23 @@ + "Pomoć", +"Personal" => "Osobno", +"Settings" => "Postavke", +"Users" => "Korisnici", +"Admin" => "Administrator", +"web services under your control" => "web usluge pod vašom kontrolom", +"Authentication error" => "Greška kod autorizacije", +"Files" => "Datoteke", +"Text" => "Tekst", +"seconds ago" => "sekundi prije", +"_%n minute ago_::_%n minutes ago_" => array("","",""), +"_%n hour ago_::_%n hours ago_" => array("","",""), +"today" => "danas", +"yesterday" => "jučer", +"_%n day go_::_%n days ago_" => array("","",""), +"last month" => "prošli mjesec", +"_%n month ago_::_%n months ago_" => array("","",""), +"last year" => "prošlu godinu", +"years ago" => "godina" +); +$PLURAL_FORMS = "nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"; diff --git a/lib/private/l10n/hu_HU.php b/lib/private/l10n/hu_HU.php new file mode 100644 index 00000000000..e944291caee --- /dev/null +++ b/lib/private/l10n/hu_HU.php @@ -0,0 +1,62 @@ + "Nincs az alkalmazás név megadva.", +"Help" => "Súgó", +"Personal" => "Személyes", +"Settings" => "Beállítások", +"Users" => "Felhasználók", +"Admin" => "Adminsztráció", +"Failed to upgrade \"%s\"." => "Sikertelen Frissítés \"%s\".", +"Unknown filetype" => "Ismeretlen file tipús", +"Invalid image" => "Hibás kép", +"web services under your control" => "webszolgáltatások saját kézben", +"cannot open \"%s\"" => "nem sikerült megnyitni \"%s\"", +"ZIP download is turned off." => "A ZIP-letöltés nincs engedélyezve.", +"Files need to be downloaded one by one." => "A fájlokat egyenként kell letölteni.", +"Back to Files" => "Vissza a Fájlokhoz", +"Selected files too large to generate zip file." => "A kiválasztott fájlok túl nagyok a zip tömörítéshez.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Tölts le a fileokat kisebb chunkokban, kölün vagy kérj segitséget a rendszergazdádtól.", +"App does not provide an info.xml file" => "Az alkalmazás nem szolgáltatott info.xml file-t", +"App can't be installed because it is not compatible with this version of ownCloud" => "Az alalmazás nem telepíthető, mert nem kompatibilis az ownClod ezzel a verziójával.", +"App directory already exists" => "Az alkalmazás mappája már létezik", +"Can't create app folder. Please fix permissions. %s" => "Nem lehetett létrehozni az alkalmzás mappáját. Kérlek ellenőrizd a jogosultásgokat. %s", +"Application is not enabled" => "Az alkalmazás nincs engedélyezve", +"Authentication error" => "Azonosítási hiba", +"Token expired. Please reload page." => "A token lejárt. Frissítse az oldalt.", +"Files" => "Fájlok", +"Text" => "Szöveg", +"Images" => "Képek", +"%s enter the database username." => "%s adja meg az adatbázist elérő felhasználó login nevét.", +"%s enter the database name." => "%s adja meg az adatbázis nevét.", +"%s you may not use dots in the database name" => "%s az adatbázis neve nem tartalmazhat pontot", +"MS SQL username and/or password not valid: %s" => "Az MS SQL felhasználónév és/vagy jelszó érvénytelen: %s", +"You need to enter either an existing account or the administrator." => "Vagy egy létező felhasználó vagy az adminisztrátor bejelentkezési nevét kell megadnia", +"MySQL username and/or password not valid" => "A MySQL felhasználói név és/vagy jelszó érvénytelen", +"DB Error: \"%s\"" => "Adatbázis hiba: \"%s\"", +"Offending command was: \"%s\"" => "A hibát ez a parancs okozta: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "A '%s'@'localhost' MySQL felhasználó már létezik.", +"Drop this user from MySQL" => "Törölje ezt a felhasználót a MySQL-ből", +"MySQL user '%s'@'%%' already exists" => "A '%s'@'%%' MySQL felhasználó már létezik", +"Drop this user from MySQL." => "Törölje ezt a felhasználót a MySQL-ből.", +"Oracle connection could not be established" => "Az Oracle kapcsolat nem hozható létre", +"Oracle username and/or password not valid" => "Az Oracle felhasználói név és/vagy jelszó érvénytelen", +"Offending command was: \"%s\", name: %s, password: %s" => "A hibát okozó parancs ez volt: \"%s\", login név: %s, jelszó: %s", +"PostgreSQL username and/or password not valid" => "A PostgreSQL felhasználói név és/vagy jelszó érvénytelen", +"Set an admin username." => "Állítson be egy felhasználói nevet az adminisztrációhoz.", +"Set an admin password." => "Állítson be egy jelszót az adminisztrációhoz.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Az Ön webkiszolgálója nincs megfelelően beállítva az állományok szinkronizálásához, mert a WebDAV-elérés úgy tűnik, nem működik.", +"Please double check the installation guides." => "Kérjük tüzetesen tanulmányozza át a telepítési útmutatót.", +"Could not find category \"%s\"" => "Ez a kategória nem található: \"%s\"", +"seconds ago" => "pár másodperce", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "ma", +"yesterday" => "tegnap", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "múlt hónapban", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "tavaly", +"years ago" => "több éve", +"Caused by:" => "Okozta:" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/hy.php b/lib/private/l10n/hy.php new file mode 100644 index 00000000000..15f78e0bce6 --- /dev/null +++ b/lib/private/l10n/hy.php @@ -0,0 +1,8 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/ia.php b/lib/private/l10n/ia.php new file mode 100644 index 00000000000..34f43bc424a --- /dev/null +++ b/lib/private/l10n/ia.php @@ -0,0 +1,16 @@ + "Adjuta", +"Personal" => "Personal", +"Settings" => "Configurationes", +"Users" => "Usatores", +"Admin" => "Administration", +"web services under your control" => "servicios web sub tu controlo", +"Files" => "Files", +"Text" => "Texto", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/id.php b/lib/private/l10n/id.php new file mode 100644 index 00000000000..080faddb321 --- /dev/null +++ b/lib/private/l10n/id.php @@ -0,0 +1,50 @@ + "Bantuan", +"Personal" => "Pribadi", +"Settings" => "Setelan", +"Users" => "Pengguna", +"Admin" => "Admin", +"web services under your control" => "layanan web dalam kontrol Anda", +"ZIP download is turned off." => "Pengunduhan ZIP dimatikan.", +"Files need to be downloaded one by one." => "Berkas harus diunduh satu persatu.", +"Back to Files" => "Kembali ke Daftar Berkas", +"Selected files too large to generate zip file." => "Berkas yang dipilih terlalu besar untuk dibuat berkas zip-nya.", +"Application is not enabled" => "Aplikasi tidak diaktifkan", +"Authentication error" => "Galat saat autentikasi", +"Token expired. Please reload page." => "Token kedaluwarsa. Silakan muat ulang halaman.", +"Files" => "Berkas", +"Text" => "Teks", +"Images" => "Gambar", +"%s enter the database username." => "%s masukkan nama pengguna basis data.", +"%s enter the database name." => "%s masukkan nama basis data.", +"%s you may not use dots in the database name" => "%sAnda tidak boleh menggunakan karakter titik pada nama basis data", +"MS SQL username and/or password not valid: %s" => "Nama pengguna dan/atau sandi MySQL tidak valid: %s", +"You need to enter either an existing account or the administrator." => "Anda harus memasukkan akun yang sudah ada atau administrator.", +"MySQL username and/or password not valid" => "Nama pengguna dan/atau sandi MySQL tidak valid", +"DB Error: \"%s\"" => "Galat Basis Data: \"%s\"", +"Offending command was: \"%s\"" => "Perintah yang bermasalah: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Pengguna MySQL '%s'@'localhost' sudah ada.", +"Drop this user from MySQL" => "Hapus pengguna ini dari MySQL", +"MySQL user '%s'@'%%' already exists" => "Pengguna MySQL '%s'@'%%' sudah ada.", +"Drop this user from MySQL." => "Hapus pengguna ini dari MySQL.", +"Oracle username and/or password not valid" => "Nama pengguna dan/atau sandi Oracle tidak valid", +"Offending command was: \"%s\", name: %s, password: %s" => "Perintah yang bermasalah: \"%s\", nama pengguna: %s, sandi: %s", +"PostgreSQL username and/or password not valid" => "Nama pengguna dan/atau sandi PostgreSQL tidak valid", +"Set an admin username." => "Setel nama pengguna admin.", +"Set an admin password." => "Setel sandi admin.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Web server Anda belum dikonfigurasikan dengan baik untuk mengizinkan sinkronisasi berkas karena tampaknya antarmuka WebDAV rusak.", +"Please double check the installation guides." => "Silakan periksa ulang panduan instalasi.", +"seconds ago" => "beberapa detik yang lalu", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "hari ini", +"yesterday" => "kemarin", +"_%n day go_::_%n days ago_" => array(""), +"last month" => "bulan kemarin", +"_%n month ago_::_%n months ago_" => array(""), +"last year" => "tahun kemarin", +"years ago" => "beberapa tahun lalu", +"Could not find category \"%s\"" => "Tidak dapat menemukan kategori \"%s\"" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/is.php b/lib/private/l10n/is.php new file mode 100644 index 00000000000..7512d278fb8 --- /dev/null +++ b/lib/private/l10n/is.php @@ -0,0 +1,31 @@ + "Hjálp", +"Personal" => "Um mig", +"Settings" => "Stillingar", +"Users" => "Notendur", +"Admin" => "Stjórnun", +"web services under your control" => "vefþjónusta undir þinni stjórn", +"ZIP download is turned off." => "Slökkt á ZIP niðurhali.", +"Files need to be downloaded one by one." => "Skrárnar verður að sækja eina og eina", +"Back to Files" => "Aftur í skrár", +"Selected files too large to generate zip file." => "Valdar skrár eru of stórar til að búa til ZIP skrá.", +"Application is not enabled" => "Forrit ekki virkt", +"Authentication error" => "Villa við auðkenningu", +"Token expired. Please reload page." => "Auðkenning útrunnin. Vinsamlegast skráðu þig aftur inn.", +"Files" => "Skrár", +"Text" => "Texti", +"Images" => "Myndir", +"seconds ago" => "sek.", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "í dag", +"yesterday" => "í gær", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "síðasta mánuði", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "síðasta ári", +"years ago" => "einhverjum árum", +"Could not find category \"%s\"" => "Fann ekki flokkinn \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/it.php b/lib/private/l10n/it.php new file mode 100644 index 00000000000..b00789bc86f --- /dev/null +++ b/lib/private/l10n/it.php @@ -0,0 +1,72 @@ + "L'applicazione \"%s\" non può essere installata poiché non è compatibile con questa versione di ownCloud.", +"No app name specified" => "Il nome dell'applicazione non è specificato", +"Help" => "Aiuto", +"Personal" => "Personale", +"Settings" => "Impostazioni", +"Users" => "Utenti", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Aggiornamento non riuscito \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Le immagini personalizzate del profilo non funzionano ancora con la cifratura", +"Unknown filetype" => "Tipo di file sconosciuto", +"Invalid image" => "Immagine non valida", +"web services under your control" => "servizi web nelle tue mani", +"cannot open \"%s\"" => "impossibile aprire \"%s\"", +"ZIP download is turned off." => "Lo scaricamento in formato ZIP è stato disabilitato.", +"Files need to be downloaded one by one." => "I file devono essere scaricati uno alla volta.", +"Back to Files" => "Torna ai file", +"Selected files too large to generate zip file." => "I file selezionati sono troppo grandi per generare un file zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Scarica i file in blocchi più piccoli, separatamente o chiedi al tuo amministratore.", +"No source specified when installing app" => "Nessuna fonte specificata durante l'installazione dell'applicazione", +"No href specified when installing app from http" => "Nessun href specificato durante l'installazione dell'applicazione da http", +"No path specified when installing app from local file" => "Nessun percorso specificato durante l'installazione dell'applicazione da file locale", +"Archives of type %s are not supported" => "Gli archivi di tipo %s non sono supportati", +"Failed to open archive when installing app" => "Apertura archivio non riuscita durante l'installazione dell'applicazione", +"App does not provide an info.xml file" => "L'applicazione non fornisce un file info.xml", +"App can't be installed because of not allowed code in the App" => "L'applicazione non può essere installata a causa di codice non consentito al suo interno", +"App can't be installed because it is not compatible with this version of ownCloud" => "L'applicazione non può essere installata poiché non è compatibile con questa versione di ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "L'applicazione non può essere installata poiché contiene il tag true che non è permesso alle applicazioni non shipped", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "L'applicazione non può essere installata poiché la versione in info.xml/version non è la stessa riportata dall'app store", +"App directory already exists" => "La cartella dell'applicazione esiste già", +"Can't create app folder. Please fix permissions. %s" => "Impossibile creare la cartella dell'applicazione. Correggi i permessi. %s", +"Application is not enabled" => "L'applicazione non è abilitata", +"Authentication error" => "Errore di autenticazione", +"Token expired. Please reload page." => "Token scaduto. Ricarica la pagina.", +"Files" => "File", +"Text" => "Testo", +"Images" => "Immagini", +"%s enter the database username." => "%s digita il nome utente del database.", +"%s enter the database name." => "%s digita il nome del database.", +"%s you may not use dots in the database name" => "%s non dovresti utilizzare punti nel nome del database", +"MS SQL username and/or password not valid: %s" => "Nome utente e/o password MS SQL non validi: %s", +"You need to enter either an existing account or the administrator." => "È necessario inserire un account esistente o l'amministratore.", +"MySQL username and/or password not valid" => "Nome utente e/o password di MySQL non validi", +"DB Error: \"%s\"" => "Errore DB: \"%s\"", +"Offending command was: \"%s\"" => "Il comando non consentito era: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "L'utente MySQL '%s'@'localhost' esiste già.", +"Drop this user from MySQL" => "Elimina questo utente da MySQL", +"MySQL user '%s'@'%%' already exists" => "L'utente MySQL '%s'@'%%' esiste già", +"Drop this user from MySQL." => "Elimina questo utente da MySQL.", +"Oracle connection could not be established" => "La connessione a Oracle non può essere stabilita", +"Oracle username and/or password not valid" => "Nome utente e/o password di Oracle non validi", +"Offending command was: \"%s\", name: %s, password: %s" => "Il comando non consentito era: \"%s\", nome: %s, password: %s", +"PostgreSQL username and/or password not valid" => "Nome utente e/o password di PostgreSQL non validi", +"Set an admin username." => "Imposta un nome utente di amministrazione.", +"Set an admin password." => "Imposta una password di amministrazione.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Il tuo server web non è configurato correttamente per consentire la sincronizzazione dei file poiché l'interfaccia WebDAV sembra essere danneggiata.", +"Please double check the installation guides." => "Leggi attentamente le guide d'installazione.", +"seconds ago" => "secondi fa", +"_%n minute ago_::_%n minutes ago_" => array("%n minuto fa","%n minuti fa"), +"_%n hour ago_::_%n hours ago_" => array("%n ora fa","%n ore fa"), +"today" => "oggi", +"yesterday" => "ieri", +"_%n day go_::_%n days ago_" => array("%n giorno fa","%n giorni fa"), +"last month" => "mese scorso", +"_%n month ago_::_%n months ago_" => array("%n mese fa","%n mesi fa"), +"last year" => "anno scorso", +"years ago" => "anni fa", +"Caused by:" => "Causato da:", +"Could not find category \"%s\"" => "Impossibile trovare la categoria \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/ja_JP.php b/lib/private/l10n/ja_JP.php new file mode 100644 index 00000000000..b9e6a0e6924 --- /dev/null +++ b/lib/private/l10n/ja_JP.php @@ -0,0 +1,72 @@ + " \"%s\" アプリは、このバージョンのownCloudと互換性がない為、インストールできません。", +"No app name specified" => "アプリ名が未指定", +"Help" => "ヘルプ", +"Personal" => "個人", +"Settings" => "設定", +"Users" => "ユーザ", +"Admin" => "管理", +"Failed to upgrade \"%s\"." => "\"%s\" へのアップグレードに失敗しました。", +"Custom profile pictures don't work with encryption yet" => "暗号無しでは利用不可なカスタムプロフィール画像", +"Unknown filetype" => "不明なファイルタイプ", +"Invalid image" => "無効な画像", +"web services under your control" => "管理下のウェブサービス", +"cannot open \"%s\"" => "\"%s\" が開けません", +"ZIP download is turned off." => "ZIPダウンロードは無効です。", +"Files need to be downloaded one by one." => "ファイルは1つずつダウンロードする必要があります。", +"Back to Files" => "ファイルに戻る", +"Selected files too large to generate zip file." => "選択したファイルはZIPファイルの生成には大きすぎます。", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "ファイルは、小さいファイルに分割されてダウンロードされます。もしくは、管理者にお尋ねください。", +"No source specified when installing app" => "アプリインストール時のソースが未指定", +"No href specified when installing app from http" => "アプリインストール時のhttpの URL が未指定", +"No path specified when installing app from local file" => "アプリインストール時のローカルファイルのパスが未指定", +"Archives of type %s are not supported" => "\"%s\"タイプのアーカイブ形式は未サポート", +"Failed to open archive when installing app" => "アプリをインストール中にアーカイブファイルを開けませんでした。", +"App does not provide an info.xml file" => "アプリにinfo.xmlファイルが入っていません", +"App can't be installed because of not allowed code in the App" => "アプリで許可されないコードが入っているのが原因でアプリがインストールできません", +"App can't be installed because it is not compatible with this version of ownCloud" => "アプリは、このバージョンのownCloudと互換性がない為、インストールできません。", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "非shippedアプリには許可されないtrueタグが含まれているためにアプリをインストール出来ません。", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "info.xml/versionのバージョンがアプリストアのバージョンと合っていない為、アプリはインストールされません", +"App directory already exists" => "アプリディレクトリは既に存在します", +"Can't create app folder. Please fix permissions. %s" => "アプリフォルダを作成出来ませんでした。%s のパーミッションを修正してください。", +"Application is not enabled" => "アプリケーションは無効です", +"Authentication error" => "認証エラー", +"Token expired. Please reload page." => "トークンが無効になりました。ページを再読込してください。", +"Files" => "ファイル", +"Text" => "TTY TDD", +"Images" => "画像", +"%s enter the database username." => "%s のデータベースのユーザ名を入力してください。", +"%s enter the database name." => "%s のデータベース名を入力してください。", +"%s you may not use dots in the database name" => "%s ではデータベース名にドットを利用できないかもしれません。", +"MS SQL username and/or password not valid: %s" => "MS SQL サーバーのユーザー名/パスワードが正しくありません: %s", +"You need to enter either an existing account or the administrator." => "既存のアカウントもしくは管理者のどちらかを入力する必要があります。", +"MySQL username and/or password not valid" => "MySQLのユーザ名もしくはパスワードは有効ではありません", +"DB Error: \"%s\"" => "DBエラー: \"%s\"", +"Offending command was: \"%s\"" => "違反コマンド: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQLのユーザ '%s'@'localhost' はすでに存在します。", +"Drop this user from MySQL" => "MySQLからこのユーザを削除", +"MySQL user '%s'@'%%' already exists" => "MySQLのユーザ '%s'@'%%' はすでに存在します。", +"Drop this user from MySQL." => "MySQLからこのユーザを削除する。", +"Oracle connection could not be established" => "Oracleへの接続が確立できませんでした。", +"Oracle username and/or password not valid" => "Oracleのユーザ名もしくはパスワードは有効ではありません", +"Offending command was: \"%s\", name: %s, password: %s" => "違反コマンド: \"%s\"、名前: %s、パスワード: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQLのユーザ名もしくはパスワードは有効ではありません", +"Set an admin username." => "管理者のユーザ名を設定。", +"Set an admin password." => "管理者のパスワードを設定。", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "WebDAVインタフェースが動作していないと考えられるため、あなたのWEBサーバはまだファイルの同期を許可するように適切な設定がされていません。", +"Please double check the installation guides." => "インストールガイドをよく確認してください。", +"seconds ago" => "数秒前", +"_%n minute ago_::_%n minutes ago_" => array("%n 分前"), +"_%n hour ago_::_%n hours ago_" => array("%n 時間後"), +"today" => "今日", +"yesterday" => "昨日", +"_%n day go_::_%n days ago_" => array("%n 日後"), +"last month" => "一月前", +"_%n month ago_::_%n months ago_" => array("%n カ月後"), +"last year" => "一年前", +"years ago" => "年前", +"Caused by:" => "原因は以下:", +"Could not find category \"%s\"" => "カテゴリ \"%s\" が見つかりませんでした" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/ka.php b/lib/private/l10n/ka.php new file mode 100644 index 00000000000..04fefe8bdf1 --- /dev/null +++ b/lib/private/l10n/ka.php @@ -0,0 +1,17 @@ + "შველა", +"Personal" => "პერსონა", +"Users" => "მომხმარებლები", +"Admin" => "ადმინისტრატორი", +"ZIP download is turned off." => "ZIP გადმოწერა გამორთულია", +"Files" => "ფაილები", +"seconds ago" => "წამის წინ", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "დღეს", +"yesterday" => "გუშინ", +"_%n day go_::_%n days ago_" => array(""), +"_%n month ago_::_%n months ago_" => array("") +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/ka_GE.php b/lib/private/l10n/ka_GE.php new file mode 100644 index 00000000000..8fbe34e6786 --- /dev/null +++ b/lib/private/l10n/ka_GE.php @@ -0,0 +1,50 @@ + "დახმარება", +"Personal" => "პირადი", +"Settings" => "პარამეტრები", +"Users" => "მომხმარებელი", +"Admin" => "ადმინისტრატორი", +"web services under your control" => "web services under your control", +"ZIP download is turned off." => "ZIP download–ი გათიშულია", +"Files need to be downloaded one by one." => "ფაილები უნდა გადმოიტვირთოს სათითაოდ.", +"Back to Files" => "უკან ფაილებში", +"Selected files too large to generate zip file." => "არჩეული ფაილები ძალიან დიდია zip ფაილის გენერაციისთვის.", +"Application is not enabled" => "აპლიკაცია არ არის აქტიური", +"Authentication error" => "ავთენტიფიკაციის შეცდომა", +"Token expired. Please reload page." => "Token–ს ვადა გაუვიდა. გთხოვთ განაახლოთ გვერდი.", +"Files" => "ფაილები", +"Text" => "ტექსტი", +"Images" => "სურათები", +"%s enter the database username." => "%s შეიყვანეთ ბაზის იუზერნეიმი.", +"%s enter the database name." => "%s შეიყვანეთ ბაზის სახელი.", +"%s you may not use dots in the database name" => "%s არ მიუთითოთ წერტილი ბაზის სახელში", +"MS SQL username and/or password not valid: %s" => "MS SQL მომხმარებელი და/ან პაროლი არ არის მართებული: %s", +"You need to enter either an existing account or the administrator." => "თქვენ უნდა შეიყვანოთ არსებული მომხმარებელის სახელი ან ადმინისტრატორი.", +"MySQL username and/or password not valid" => "MySQL იუზერნეიმი და/ან პაროლი არ არის სწორი", +"DB Error: \"%s\"" => "DB შეცდომა: \"%s\"", +"Offending command was: \"%s\"" => "Offending ბრძანება იყო: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL მომხმარებელი '%s'@'localhost' უკვე არსებობს.", +"Drop this user from MySQL" => "წაშალე ეს მომხამრებელი MySQL–იდან", +"MySQL user '%s'@'%%' already exists" => "MySQL მომხმარებელი '%s'@'%%' უკვე არსებობს", +"Drop this user from MySQL." => "წაშალე ეს მომხამრებელი MySQL–იდან", +"Oracle username and/or password not valid" => "Oracle იუზერნეიმი და/ან პაროლი არ არის სწორი", +"Offending command was: \"%s\", name: %s, password: %s" => "Offending ბრძანება იყო: \"%s\", სახელი: %s, პაროლი: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL იუზერნეიმი და/ან პაროლი არ არის სწორი", +"Set an admin username." => "დააყენეთ ადმინისტრატორის სახელი.", +"Set an admin password." => "დააყენეთ ადმინისტრატორის პაროლი.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "თქვენი web სერვერი არ არის კონფიგურირებული ფაილ სინქრონიზაციისთვის, რადგან WebDAV ინტერფეისი შეიძლება იყოს გატეხილი.", +"Please double check the installation guides." => "გთხოვთ გადაათვალიეროთ ინსტალაციის გზამკვლევი.", +"seconds ago" => "წამის წინ", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "დღეს", +"yesterday" => "გუშინ", +"_%n day go_::_%n days ago_" => array(""), +"last month" => "გასულ თვეში", +"_%n month ago_::_%n months ago_" => array(""), +"last year" => "ბოლო წელს", +"years ago" => "წლის წინ", +"Could not find category \"%s\"" => "\"%s\" კატეგორიის მოძებნა ვერ მოხერხდა" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/km.php b/lib/private/l10n/km.php new file mode 100644 index 00000000000..e7b09649a24 --- /dev/null +++ b/lib/private/l10n/km.php @@ -0,0 +1,8 @@ + array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"_%n day go_::_%n days ago_" => array(""), +"_%n month ago_::_%n months ago_" => array("") +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/kn.php b/lib/private/l10n/kn.php new file mode 100644 index 00000000000..e7b09649a24 --- /dev/null +++ b/lib/private/l10n/kn.php @@ -0,0 +1,8 @@ + array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"_%n day go_::_%n days ago_" => array(""), +"_%n month ago_::_%n months ago_" => array("") +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/ko.php b/lib/private/l10n/ko.php new file mode 100644 index 00000000000..3ef39fefa60 --- /dev/null +++ b/lib/private/l10n/ko.php @@ -0,0 +1,72 @@ + "현재 ownCloud 버전과 호환되지 않기 때문에 \"%s\" 앱을 설치할 수 없습니다.", +"No app name specified" => "앱 이름이 지정되지 않았습니다.", +"Help" => "도움말", +"Personal" => "개인", +"Settings" => "설정", +"Users" => "사용자", +"Admin" => "관리자", +"Failed to upgrade \"%s\"." => "\"%s\" 업그레이드에 실패했습니다.", +"Custom profile pictures don't work with encryption yet" => "개개인의 프로필 사진은 아직은 암호화 되지 않습니다", +"Unknown filetype" => "알수없는 파일형식", +"Invalid image" => "잘못된 그림", +"web services under your control" => "내가 관리하는 웹 서비스", +"cannot open \"%s\"" => "\"%s\"을(를) 열 수 없습니다.", +"ZIP download is turned off." => "ZIP 다운로드가 비활성화되었습니다.", +"Files need to be downloaded one by one." => "파일을 개별적으로 다운로드해야 합니다.", +"Back to Files" => "파일로 돌아가기", +"Selected files too large to generate zip file." => "선택한 파일들은 ZIP 파일을 생성하기에 너무 큽니다.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "작은 조각들 안에 들어있는 파일들을 받고자 하신다면, 나누어서 받으시거나 혹은 시스템 관리자에게 정중하게 물어보십시오", +"No source specified when installing app" => "앱을 설치할 때 소스가 지정되지 않았습니다.", +"No href specified when installing app from http" => "http에서 앱을 설치할 대 href가 지정되지 않았습니다.", +"No path specified when installing app from local file" => "로컬 파일에서 앱을 설치할 때 경로가 지정되지 않았습니다.", +"Archives of type %s are not supported" => "%s 타입 아카이브는 지원되지 않습니다.", +"Failed to open archive when installing app" => "앱을 설치할 때 아카이브를 열지 못했습니다.", +"App does not provide an info.xml file" => "앱에서 info.xml 파일이 제공되지 않았습니다.", +"App can't be installed because of not allowed code in the App" => "앱에 허용되지 않는 코드가 있어서 앱을 설치할 수 없습니다. ", +"App can't be installed because it is not compatible with this version of ownCloud" => "현재 ownCloud 버전과 호환되지 않기 때문에 앱을 설치할 수 없습니다.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "출하되지 않은 앱에 허용되지 않는 true 태그를 포함하고 있기 때문에 앱을 설치할 수 없습니다.", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "info.xml/version에 포함된 버전과 앱 스토어에 보고된 버전이 같지 않아서 앱을 설치할 수 없습니다. ", +"App directory already exists" => "앱 디렉토리가 이미 존재합니다. ", +"Can't create app folder. Please fix permissions. %s" => "앱 폴더를 만들 수 없습니다. 권한을 수정하십시오. %s ", +"Application is not enabled" => "앱이 활성화되지 않았습니다", +"Authentication error" => "인증 오류", +"Token expired. Please reload page." => "토큰이 만료되었습니다. 페이지를 새로 고치십시오.", +"Files" => "파일", +"Text" => "텍스트", +"Images" => "그림", +"%s enter the database username." => "데이터베이스 사용자 명을 %s 에 입력해주십시오", +"%s enter the database name." => "데이터베이스 명을 %s 에 입력해주십시오", +"%s you may not use dots in the database name" => "%s 에 적으신 데이터베이스 이름에는 점을 사용할수 없습니다", +"MS SQL username and/or password not valid: %s" => "MS SQL 사용자 이름이나 암호가 잘못되었습니다: %s", +"You need to enter either an existing account or the administrator." => "기존 계정이나 administrator(관리자)를 입력해야 합니다.", +"MySQL username and/or password not valid" => "MySQL 사용자 이름이나 암호가 잘못되었습니다.", +"DB Error: \"%s\"" => "DB 오류: \"%s\"", +"Offending command was: \"%s\"" => "잘못된 명령: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL 사용자 '%s'@'localhost'이(가) 이미 존재합니다.", +"Drop this user from MySQL" => "이 사용자를 MySQL에서 뺍니다.", +"MySQL user '%s'@'%%' already exists" => "MySQL 사용자 '%s'@'%%'이(가) 이미 존재합니다. ", +"Drop this user from MySQL." => "이 사용자를 MySQL에서 뺍니다.", +"Oracle connection could not be established" => "Oracle 연결을 수립할 수 없습니다.", +"Oracle username and/or password not valid" => "Oracle 사용자 이름이나 암호가 잘못되었습니다.", +"Offending command was: \"%s\", name: %s, password: %s" => "잘못된 명령: \"%s\", 이름: %s, 암호: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL의 사용자 명 혹은 비밀번호가 잘못되었습니다", +"Set an admin username." => "관리자 이름 설정", +"Set an admin password." => "관리자 비밀번호 설정", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "WebDAV 인터페이스가 제대로 작동하지 않습니다. 웹 서버에서 파일 동기화를 사용할 수 있도록 설정이 제대로 되지 않은 것 같습니다.", +"Please double check the installation guides." => "설치 가이드를 다시 한 번 확인하십시오.", +"Could not find category \"%s\"" => "분류 \"%s\"을(를) 찾을 수 없습니다.", +"seconds ago" => "초 전", +"_%n minute ago_::_%n minutes ago_" => array("%n분 전 "), +"_%n hour ago_::_%n hours ago_" => array("%n시간 전 "), +"today" => "오늘", +"yesterday" => "어제", +"_%n day go_::_%n days ago_" => array("%n일 전 "), +"last month" => "지난 달", +"_%n month ago_::_%n months ago_" => array("%n달 전 "), +"last year" => "작년", +"years ago" => "년 전", +"Caused by:" => "원인: " +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/ku_IQ.php b/lib/private/l10n/ku_IQ.php new file mode 100644 index 00000000000..c99f9dd2a12 --- /dev/null +++ b/lib/private/l10n/ku_IQ.php @@ -0,0 +1,13 @@ + "یارمەتی", +"Settings" => "ده‌ستكاری", +"Users" => "به‌كارهێنه‌ر", +"Admin" => "به‌ڕێوه‌به‌ری سه‌ره‌كی", +"web services under your control" => "ڕاژه‌ی وێب له‌ژێر چاودێریت دایه", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/lb.php b/lib/private/l10n/lb.php new file mode 100644 index 00000000000..c25f5b55bd5 --- /dev/null +++ b/lib/private/l10n/lb.php @@ -0,0 +1,23 @@ + "Hëllef", +"Personal" => "Perséinlech", +"Settings" => "Astellungen", +"Users" => "Benotzer", +"Admin" => "Admin", +"web services under your control" => "Web-Servicer ënnert denger Kontroll", +"Authentication error" => "Authentifikatioun's Fehler", +"Files" => "Dateien", +"Text" => "SMS", +"seconds ago" => "Sekonnen hir", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "haut", +"yesterday" => "gëschter", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "Läschte Mount", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "Läscht Joer", +"years ago" => "Joren hier" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/lt_LT.php b/lib/private/l10n/lt_LT.php new file mode 100644 index 00000000000..db8d96c1018 --- /dev/null +++ b/lib/private/l10n/lt_LT.php @@ -0,0 +1,72 @@ + "Programa „%s“ negali būti įdiegta, nes yra nesuderinama su šia ownCloud versija.", +"No app name specified" => "Nenurodytas programos pavadinimas", +"Help" => "Pagalba", +"Personal" => "Asmeniniai", +"Settings" => "Nustatymai", +"Users" => "Vartotojai", +"Admin" => "Administravimas", +"Failed to upgrade \"%s\"." => "Nepavyko pakelti „%s“ versijos.", +"Custom profile pictures don't work with encryption yet" => "Saviti profilio paveiksliukai dar neveikia su šifravimu", +"Unknown filetype" => "Nežinomas failo tipas", +"Invalid image" => "Netinkamas paveikslėlis", +"web services under your control" => "jūsų valdomos web paslaugos", +"cannot open \"%s\"" => "nepavyksta atverti „%s“", +"ZIP download is turned off." => "ZIP atsisiuntimo galimybė yra išjungta.", +"Files need to be downloaded one by one." => "Failai turi būti parsiunčiami vienas po kito.", +"Back to Files" => "Atgal į Failus", +"Selected files too large to generate zip file." => "Pasirinkti failai per dideli archyvavimui į ZIP.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Atsisiųskite failus mažesnėmis dalimis atskirai, arba mandagiai prašykite savo administratoriaus.", +"No source specified when installing app" => "Nenurodytas šaltinis diegiant programą", +"No href specified when installing app from http" => "Nenurodytas href diegiant programą iš http", +"No path specified when installing app from local file" => "Nenurodytas kelias diegiant programą iš vietinio failo", +"Archives of type %s are not supported" => "%s tipo archyvai nepalaikomi", +"Failed to open archive when installing app" => "Nepavyko atverti archyvo diegiant programą", +"App does not provide an info.xml file" => "Programa nepateikia info.xml failo", +"App can't be installed because of not allowed code in the App" => "Programa negali būti įdiegta, nes turi neleistiną kodą", +"App can't be installed because it is not compatible with this version of ownCloud" => "Programa negali būti įdiegta, nes yra nesuderinama su šia ownCloud versija", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Programa negali būti įdiegta, nes turi true žymę, kuri yra neleistina ne kartu platinamoms programoms", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Programa negali būti įdiegta, nes versija pateikta info.xml/version nesutampa su versija deklaruota programų saugykloje", +"App directory already exists" => "Programos aplankas jau egzistuoja", +"Can't create app folder. Please fix permissions. %s" => "Nepavyksta sukurti aplanko. Prašome pataisyti leidimus. %s", +"Application is not enabled" => "Programa neįjungta", +"Authentication error" => "Autentikacijos klaida", +"Token expired. Please reload page." => "Sesija baigėsi. Prašome perkrauti puslapį.", +"Files" => "Failai", +"Text" => "Žinučių", +"Images" => "Paveikslėliai", +"%s enter the database username." => "%s įrašykite duombazės naudotojo vardą.", +"%s enter the database name." => "%s įrašykite duombazės pavadinimą.", +"%s you may not use dots in the database name" => "%s negalite naudoti taškų duombazės pavadinime", +"MS SQL username and/or password not valid: %s" => "MS SQL naudotojo vardas ir/arba slaptažodis netinka: %s", +"You need to enter either an existing account or the administrator." => "Turite prisijungti su egzistuojančia paskyra arba su administratoriumi.", +"MySQL username and/or password not valid" => "Neteisingas MySQL naudotojo vardas ir/arba slaptažodis", +"DB Error: \"%s\"" => "DB klaida: \"%s\"", +"Offending command was: \"%s\"" => "Vykdyta komanda buvo: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL naudotojas '%s'@'localhost' jau egzistuoja.", +"Drop this user from MySQL" => "Pašalinti šį naudotoją iš MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL naudotojas '%s'@'%%' jau egzistuoja", +"Drop this user from MySQL." => "Pašalinti šį naudotoją iš MySQL.", +"Oracle connection could not be established" => "Nepavyko sukurti Oracle ryšio", +"Oracle username and/or password not valid" => "Neteisingas Oracle naudotojo vardas ir/arba slaptažodis", +"Offending command was: \"%s\", name: %s, password: %s" => "Vykdyta komanda buvo: \"%s\", name: %s, password: %s", +"PostgreSQL username and/or password not valid" => "Neteisingas PostgreSQL naudotojo vardas ir/arba slaptažodis", +"Set an admin username." => "Nustatyti administratoriaus naudotojo vardą.", +"Set an admin password." => "Nustatyti administratoriaus slaptažodį.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Jūsų serveris nėra tvarkingai nustatytas leisti failų sinchronizaciją, nes WebDAV sąsaja panašu, kad yra sugadinta.", +"Please double check the installation guides." => "Prašome pažiūrėkite dar kartą diegimo instrukcijas.", +"seconds ago" => "prieš sekundę", +"_%n minute ago_::_%n minutes ago_" => array("prieš %n min.","Prieš % minutes","Prieš %n minučių"), +"_%n hour ago_::_%n hours ago_" => array("Prieš %n valandą","Prieš %n valandas","Prieš %n valandų"), +"today" => "šiandien", +"yesterday" => "vakar", +"_%n day go_::_%n days ago_" => array("Prieš %n dieną","Prieš %n dienas","Prieš %n dienų"), +"last month" => "praeitą mėnesį", +"_%n month ago_::_%n months ago_" => array("Prieš %n mėnesį","Prieš %n mėnesius","Prieš %n mėnesių"), +"last year" => "praeitais metais", +"years ago" => "prieš metus", +"Caused by:" => "Iššaukė:", +"Could not find category \"%s\"" => "Nepavyko rasti kategorijos „%s“" +); +$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/lv.php b/lib/private/l10n/lv.php new file mode 100644 index 00000000000..4090a36edcc --- /dev/null +++ b/lib/private/l10n/lv.php @@ -0,0 +1,55 @@ + "Palīdzība", +"Personal" => "Personīgi", +"Settings" => "Iestatījumi", +"Users" => "Lietotāji", +"Admin" => "Administratori", +"Failed to upgrade \"%s\"." => "Kļūda atjauninot \"%s\"", +"web services under your control" => "tīmekļa servisi tavā varā", +"cannot open \"%s\"" => "Nevar atvērt \"%s\"", +"ZIP download is turned off." => "ZIP lejupielādēšana ir izslēgta.", +"Files need to be downloaded one by one." => "Datnes var lejupielādēt tikai katru atsevišķi.", +"Back to Files" => "Atpakaļ pie datnēm", +"Selected files too large to generate zip file." => "Izvēlētās datnes ir pārāk lielas, lai izveidotu zip datni.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Lejupielādējiet savus failus mazākās daļās, atsevišķi vai palūdziet tos administratoram.", +"Application is not enabled" => "Lietotne nav aktivēta", +"Authentication error" => "Autentifikācijas kļūda", +"Token expired. Please reload page." => "Pilnvarai ir beidzies termiņš. Lūdzu, pārlādējiet lapu.", +"Files" => "Datnes", +"Text" => "Teksts", +"Images" => "Attēli", +"%s enter the database username." => "%s ievadiet datubāzes lietotājvārdu.", +"%s enter the database name." => "%s ievadiet datubāzes nosaukumu.", +"%s you may not use dots in the database name" => "%s datubāžu nosaukumos nedrīkst izmantot punktus", +"MS SQL username and/or password not valid: %s" => "Nav derīga MySQL parole un/vai lietotājvārds — %s", +"You need to enter either an existing account or the administrator." => "Jums jāievada vai nu esošs vai administratora konts.", +"MySQL username and/or password not valid" => "Nav derīga MySQL parole un/vai lietotājvārds", +"DB Error: \"%s\"" => "DB kļūda — “%s”", +"Offending command was: \"%s\"" => "Vainīgā komanda bija “%s”", +"MySQL user '%s'@'localhost' exists already." => "MySQL lietotājs %s'@'localhost' jau eksistē.", +"Drop this user from MySQL" => "Izmest šo lietotāju no MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL lietotājs '%s'@'%%' jau eksistē", +"Drop this user from MySQL." => "Izmest šo lietotāju no MySQL.", +"Oracle connection could not be established" => "Nevar izveidot savienojumu ar Oracle", +"Oracle username and/or password not valid" => "Nav derīga Oracle parole un/vai lietotājvārds", +"Offending command was: \"%s\", name: %s, password: %s" => "Vainīgā komanda bija \"%s\", vārds: %s, parole: %s", +"PostgreSQL username and/or password not valid" => "Nav derīga PostgreSQL parole un/vai lietotājvārds", +"Set an admin username." => "Iestatiet administratora lietotājvārdu.", +"Set an admin password." => "Iestatiet administratora paroli.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Jūsu serveris vēl nav pareizi iestatīts, lai ļautu sinhronizēt datnes, jo izskatās, ka WebDAV saskarne ir salauzta.", +"Please double check the installation guides." => "Lūdzu, vēlreiz pārbaudiet instalēšanas palīdzību.", +"seconds ago" => "sekundes atpakaļ", +"_%n minute ago_::_%n minutes ago_" => array("","","Pirms %n minūtēm"), +"_%n hour ago_::_%n hours ago_" => array("","","Pirms %n stundām"), +"today" => "šodien", +"yesterday" => "vakar", +"_%n day go_::_%n days ago_" => array("","","Pirms %n dienām"), +"last month" => "pagājušajā mēnesī", +"_%n month ago_::_%n months ago_" => array("","","Pirms %n mēnešiem"), +"last year" => "gājušajā gadā", +"years ago" => "gadus atpakaļ", +"Caused by:" => "Cēlonis:", +"Could not find category \"%s\"" => "Nevarēja atrast kategoriju “%s”" +); +$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"; diff --git a/lib/private/l10n/mk.php b/lib/private/l10n/mk.php new file mode 100644 index 00000000000..69d4a1cb694 --- /dev/null +++ b/lib/private/l10n/mk.php @@ -0,0 +1,31 @@ + "Помош", +"Personal" => "Лично", +"Settings" => "Подесувања", +"Users" => "Корисници", +"Admin" => "Админ", +"web services under your control" => "веб сервиси под Ваша контрола", +"ZIP download is turned off." => "Преземање во ZIP е исклучено", +"Files need to be downloaded one by one." => "Датотеките треба да се симнат една по една.", +"Back to Files" => "Назад кон датотеки", +"Selected files too large to generate zip file." => "Избраните датотеки се преголеми за да се генерира zip.", +"Application is not enabled" => "Апликацијата не е овозможена", +"Authentication error" => "Грешка во автентикација", +"Token expired. Please reload page." => "Жетонот е истечен. Ве молам превчитајте ја страницата.", +"Files" => "Датотеки", +"Text" => "Текст", +"Images" => "Слики", +"seconds ago" => "пред секунди", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "денеска", +"yesterday" => "вчера", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "минатиот месец", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "минатата година", +"years ago" => "пред години", +"Could not find category \"%s\"" => "Не можам да најдам категорија „%s“" +); +$PLURAL_FORMS = "nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"; diff --git a/lib/private/l10n/ml_IN.php b/lib/private/l10n/ml_IN.php new file mode 100644 index 00000000000..15f78e0bce6 --- /dev/null +++ b/lib/private/l10n/ml_IN.php @@ -0,0 +1,8 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/ms_MY.php b/lib/private/l10n/ms_MY.php new file mode 100644 index 00000000000..17ef07f83dd --- /dev/null +++ b/lib/private/l10n/ms_MY.php @@ -0,0 +1,17 @@ + "Bantuan", +"Personal" => "Peribadi", +"Settings" => "Tetapan", +"Users" => "Pengguna", +"Admin" => "Admin", +"web services under your control" => "Perkhidmatan web di bawah kawalan anda", +"Authentication error" => "Ralat pengesahan", +"Files" => "Fail-fail", +"Text" => "Teks", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"_%n day go_::_%n days ago_" => array(""), +"_%n month ago_::_%n months ago_" => array("") +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/my_MM.php b/lib/private/l10n/my_MM.php new file mode 100644 index 00000000000..5f4b6ddc820 --- /dev/null +++ b/lib/private/l10n/my_MM.php @@ -0,0 +1,27 @@ + "အကူအညီ", +"Users" => "သုံးစွဲသူ", +"Admin" => "အက်ဒမင်", +"web services under your control" => "သင်၏ထိန်းချုပ်မှု့အောက်တွင်ရှိသော Web services", +"ZIP download is turned off." => "ZIP ဒေါင်းလုတ်ကိုပိတ်ထားသည်", +"Files need to be downloaded one by one." => "ဖိုင်များသည် တစ်ခုပြီး တစ်ခုဒေါင်းလုတ်ချရန်လိုအပ်သည်", +"Back to Files" => "ဖိုင်သို့ပြန်သွားမည်", +"Selected files too large to generate zip file." => "zip ဖိုင်အဖြစ်ပြုလုပ်ရန် ရွေးချယ်ထားသောဖိုင်များသည် အရမ်းကြီးလွန်းသည်", +"Authentication error" => "ခွင့်ပြုချက်မအောင်မြင်", +"Files" => "ဖိုင်များ", +"Text" => "စာသား", +"Images" => "ပုံရိပ်များ", +"seconds ago" => "စက္ကန့်အနည်းငယ်က", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "ယနေ့", +"yesterday" => "မနေ့က", +"_%n day go_::_%n days ago_" => array(""), +"last month" => "ပြီးခဲ့သောလ", +"_%n month ago_::_%n months ago_" => array(""), +"last year" => "မနှစ်က", +"years ago" => "နှစ် အရင်က", +"Could not find category \"%s\"" => "\"%s\"ခေါင်းစဉ်ကို ရှာမတွေ့ပါ" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/nb_NO.php b/lib/private/l10n/nb_NO.php new file mode 100644 index 00000000000..8e7d095d369 --- /dev/null +++ b/lib/private/l10n/nb_NO.php @@ -0,0 +1,33 @@ + "Hjelp", +"Personal" => "Personlig", +"Settings" => "Innstillinger", +"Users" => "Brukere", +"Admin" => "Admin", +"web services under your control" => "web tjenester du kontrollerer", +"ZIP download is turned off." => "ZIP-nedlasting av avslått", +"Files need to be downloaded one by one." => "Filene må lastes ned en om gangen", +"Back to Files" => "Tilbake til filer", +"Selected files too large to generate zip file." => "De valgte filene er for store til å kunne generere ZIP-fil", +"Application is not enabled" => "Applikasjon er ikke påslått", +"Authentication error" => "Autentikasjonsfeil", +"Token expired. Please reload page." => "Symbol utløpt. Vennligst last inn siden på nytt.", +"Files" => "Filer", +"Text" => "Tekst", +"Images" => "Bilder", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din nettservev er ikke konfigurert korrekt for filsynkronisering. WebDAV ser ut til å ikke funkere.", +"Please double check the installation guides." => "Vennligst dobbelsjekk installasjonsguiden.", +"seconds ago" => "sekunder siden", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "i dag", +"yesterday" => "i går", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "forrige måned", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "forrige år", +"years ago" => "år siden", +"Could not find category \"%s\"" => "Kunne ikke finne kategori \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/ne.php b/lib/private/l10n/ne.php new file mode 100644 index 00000000000..15f78e0bce6 --- /dev/null +++ b/lib/private/l10n/ne.php @@ -0,0 +1,8 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/nl.php b/lib/private/l10n/nl.php new file mode 100644 index 00000000000..20374f1f0f8 --- /dev/null +++ b/lib/private/l10n/nl.php @@ -0,0 +1,72 @@ + "App \"%s\" kan niet worden geïnstalleerd omdat die niet compatible is met deze versie van ownCloud.", +"No app name specified" => "De app naam is niet gespecificeerd.", +"Help" => "Help", +"Personal" => "Persoonlijk", +"Settings" => "Instellingen", +"Users" => "Gebruikers", +"Admin" => "Beheerder", +"Failed to upgrade \"%s\"." => "Upgrade \"%s\" mislukt.", +"Custom profile pictures don't work with encryption yet" => "Maatwerk profielafbeelding werkt nog niet met versleuteling", +"Unknown filetype" => "Onbekend bestandsformaat", +"Invalid image" => "Ongeldige afbeelding", +"web services under your control" => "Webdiensten in eigen beheer", +"cannot open \"%s\"" => "Kon \"%s\" niet openen", +"ZIP download is turned off." => "ZIP download is uitgeschakeld.", +"Files need to be downloaded one by one." => "Bestanden moeten één voor één worden gedownload.", +"Back to Files" => "Terug naar bestanden", +"Selected files too large to generate zip file." => "De geselecteerde bestanden zijn te groot om een zip bestand te maken.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Download de bestanden in kleinere brokken, appart of vraag uw administrator.", +"No source specified when installing app" => "Geen bron opgegeven bij installatie van de app", +"No href specified when installing app from http" => "Geen href opgegeven bij installeren van de app vanaf http", +"No path specified when installing app from local file" => "Geen pad opgegeven bij installeren van de app vanaf een lokaal bestand", +"Archives of type %s are not supported" => "Archiefbestanden van type %s niet ondersteund", +"Failed to open archive when installing app" => "Kon archiefbestand bij installatie van de app niet openen", +"App does not provide an info.xml file" => "De app heeft geen info.xml bestand", +"App can't be installed because of not allowed code in the App" => "De app kan niet worden geïnstalleerd wegens onjuiste code in de app", +"App can't be installed because it is not compatible with this version of ownCloud" => "De app kan niet worden geïnstalleerd omdat die niet compatible is met deze versie van ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "De app kan niet worden geïnstallerd omdat het de true tag bevat die niet is toegestaan voor niet gepubliceerde apps", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "De app kan niet worden geïnstalleerd omdat de versie in info.xml/version niet dezelfde is als de versie zoals die in de app store staat vermeld", +"App directory already exists" => "App directory bestaat al", +"Can't create app folder. Please fix permissions. %s" => "Kan de app map niet aanmaken, Herstel de permissies. %s", +"Application is not enabled" => "De applicatie is niet actief", +"Authentication error" => "Authenticatie fout", +"Token expired. Please reload page." => "Token verlopen. Herlaad de pagina.", +"Files" => "Bestanden", +"Text" => "Tekst", +"Images" => "Afbeeldingen", +"%s enter the database username." => "%s opgeven database gebruikersnaam.", +"%s enter the database name." => "%s opgeven databasenaam.", +"%s you may not use dots in the database name" => "%s er mogen geen puntjes in de databasenaam voorkomen", +"MS SQL username and/or password not valid: %s" => "MS SQL gebruikersnaam en/of wachtwoord niet geldig: %s", +"You need to enter either an existing account or the administrator." => "Geef of een bestaand account op of het beheerdersaccount.", +"MySQL username and/or password not valid" => "MySQL gebruikersnaam en/of wachtwoord ongeldig", +"DB Error: \"%s\"" => "DB Fout: \"%s\"", +"Offending command was: \"%s\"" => "Onjuiste commande was: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL gebruiker '%s'@'localhost' bestaat al.", +"Drop this user from MySQL" => "Verwijder deze gebruiker uit MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQL gebruiker '%s'@'%%' bestaat al", +"Drop this user from MySQL." => "Verwijder deze gebruiker uit MySQL.", +"Oracle connection could not be established" => "Er kon geen verbinding met Oracle worden bereikt", +"Oracle username and/or password not valid" => "Oracle gebruikersnaam en/of wachtwoord ongeldig", +"Offending command was: \"%s\", name: %s, password: %s" => "Onjuiste commando was: \"%s\", naam: %s, wachtwoord: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig", +"Set an admin username." => "Stel de gebruikersnaam van de beheerder in.", +"Set an admin password." => "Stel een beheerderswachtwoord in.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Uw webserver is nog niet goed ingesteld voor bestandssynchronisatie omdat de WebDAV interface verbroken lijkt.", +"Please double check the installation guides." => "Controleer de installatiehandleiding goed.", +"seconds ago" => "seconden geleden", +"_%n minute ago_::_%n minutes ago_" => array("%n minuut geleden","%n minuten geleden"), +"_%n hour ago_::_%n hours ago_" => array("%n uur geleden","%n uur geleden"), +"today" => "vandaag", +"yesterday" => "gisteren", +"_%n day go_::_%n days ago_" => array("%n dag terug","%n dagen geleden"), +"last month" => "vorige maand", +"_%n month ago_::_%n months ago_" => array("%n maand geleden","%n maanden geleden"), +"last year" => "vorig jaar", +"years ago" => "jaar geleden", +"Caused by:" => "Gekomen door:", +"Could not find category \"%s\"" => "Kon categorie \"%s\" niet vinden" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/nn_NO.php b/lib/private/l10n/nn_NO.php new file mode 100644 index 00000000000..e8bf8dfdef4 --- /dev/null +++ b/lib/private/l10n/nn_NO.php @@ -0,0 +1,27 @@ + "Hjelp", +"Personal" => "Personleg", +"Settings" => "Innstillingar", +"Users" => "Brukarar", +"Admin" => "Administrer", +"Unknown filetype" => "Ukjend filtype", +"Invalid image" => "Ugyldig bilete", +"web services under your control" => "Vev tjenester under din kontroll", +"Authentication error" => "Feil i autentisering", +"Files" => "Filer", +"Text" => "Tekst", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Tenaren din er ikkje enno rett innstilt til å tilby filsynkronisering sidan WebDAV-grensesnittet ser ut til å vera øydelagt.", +"Please double check the installation guides." => "Ver venleg og dobbeltsjekk installasjonsrettleiinga.", +"seconds ago" => "sekund sidan", +"_%n minute ago_::_%n minutes ago_" => array("","%n minutt sidan"), +"_%n hour ago_::_%n hours ago_" => array("","%n timar sidan"), +"today" => "i dag", +"yesterday" => "i går", +"_%n day go_::_%n days ago_" => array("","%n dagar sidan"), +"last month" => "førre månad", +"_%n month ago_::_%n months ago_" => array("","%n månadar sidan"), +"last year" => "i fjor", +"years ago" => "år sidan" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/nqo.php b/lib/private/l10n/nqo.php new file mode 100644 index 00000000000..e7b09649a24 --- /dev/null +++ b/lib/private/l10n/nqo.php @@ -0,0 +1,8 @@ + array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"_%n day go_::_%n days ago_" => array(""), +"_%n month ago_::_%n months ago_" => array("") +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/oc.php b/lib/private/l10n/oc.php new file mode 100644 index 00000000000..40a527cc76c --- /dev/null +++ b/lib/private/l10n/oc.php @@ -0,0 +1,25 @@ + "Ajuda", +"Personal" => "Personal", +"Settings" => "Configuracion", +"Users" => "Usancièrs", +"Admin" => "Admin", +"web services under your control" => "Services web jos ton contraròtle", +"ZIP download is turned off." => "Avalcargar los ZIP es inactiu.", +"Files need to be downloaded one by one." => "Los fichièrs devan èsser avalcargats un per un.", +"Back to Files" => "Torna cap als fichièrs", +"Authentication error" => "Error d'autentificacion", +"Files" => "Fichièrs", +"seconds ago" => "segonda a", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "uèi", +"yesterday" => "ièr", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "mes passat", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "an passat", +"years ago" => "ans a" +); +$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/private/l10n/pa.php b/lib/private/l10n/pa.php new file mode 100644 index 00000000000..069fea6e710 --- /dev/null +++ b/lib/private/l10n/pa.php @@ -0,0 +1,16 @@ + "ਸੈਟਿੰਗ", +"Files" => "ਫਾਇਲਾਂ", +"seconds ago" => "ਸਕਿੰਟ ਪਹਿਲਾਂ", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "ਅੱਜ", +"yesterday" => "ਕੱਲ੍ਹ", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "ਪਿਛਲੇ ਮਹੀਨੇ", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "ਪਿਛਲੇ ਸਾਲ", +"years ago" => "ਸਾਲਾਂ ਪਹਿਲਾਂ" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/pl.php b/lib/private/l10n/pl.php new file mode 100644 index 00000000000..270559b4e50 --- /dev/null +++ b/lib/private/l10n/pl.php @@ -0,0 +1,72 @@ + "Aplikacja \"%s\" nie może zostać zainstalowana, ponieważ nie jest zgodna z tą wersją ownCloud.", +"No app name specified" => "Nie określono nazwy aplikacji", +"Help" => "Pomoc", +"Personal" => "Osobiste", +"Settings" => "Ustawienia", +"Users" => "Użytkownicy", +"Admin" => "Administrator", +"Failed to upgrade \"%s\"." => "Błąd przy aktualizacji \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Domyślny profil zdjęć nie działa z szyfrowaniem jeszcze", +"Unknown filetype" => "Nieznany typ pliku", +"Invalid image" => "Błędne zdjęcie", +"web services under your control" => "Kontrolowane serwisy", +"cannot open \"%s\"" => "Nie można otworzyć \"%s\"", +"ZIP download is turned off." => "Pobieranie ZIP jest wyłączone.", +"Files need to be downloaded one by one." => "Pliki muszą zostać pobrane pojedynczo.", +"Back to Files" => "Wróć do plików", +"Selected files too large to generate zip file." => "Wybrane pliki są zbyt duże, aby wygenerować plik zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Pobierz pliki w mniejszy kawałkach, oddzielnie lub poproś administratora o zwiększenie limitu.", +"No source specified when installing app" => "Nie określono źródła podczas instalacji aplikacji", +"No href specified when installing app from http" => "Nie określono linku skąd aplikacja ma być zainstalowana", +"No path specified when installing app from local file" => "Nie określono lokalnego pliku z którego miała być instalowana aplikacja", +"Archives of type %s are not supported" => "Typ archiwum %s nie jest obsługiwany", +"Failed to open archive when installing app" => "Nie udało się otworzyć archiwum podczas instalacji aplikacji", +"App does not provide an info.xml file" => "Aplikacja nie posiada pliku info.xml", +"App can't be installed because of not allowed code in the App" => "Aplikacja nie może być zainstalowany ponieważ nie dopuszcza kod w aplikacji", +"App can't be installed because it is not compatible with this version of ownCloud" => "Aplikacja nie może zostać zainstalowana ponieważ jest niekompatybilna z tą wersja ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Aplikacja nie może być zainstalowana ponieważ true tag nie jest true , co nie jest dozwolone dla aplikacji nie wysłanych", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Nie można zainstalować aplikacji, ponieważ w wersji info.xml/version nie jest taka sama, jak wersja z app store", +"App directory already exists" => "Katalog aplikacji już isnieje", +"Can't create app folder. Please fix permissions. %s" => "Nie mogę utworzyć katalogu aplikacji. Proszę popraw uprawnienia. %s", +"Application is not enabled" => "Aplikacja nie jest włączona", +"Authentication error" => "Błąd uwierzytelniania", +"Token expired. Please reload page." => "Token wygasł. Proszę ponownie załadować stronę.", +"Files" => "Pliki", +"Text" => "Połączenie tekstowe", +"Images" => "Obrazy", +"%s enter the database username." => "%s wpisz nazwę użytkownika do bazy", +"%s enter the database name." => "%s wpisz nazwę bazy.", +"%s you may not use dots in the database name" => "%s nie można używać kropki w nazwie bazy danych", +"MS SQL username and/or password not valid: %s" => "Nazwa i/lub hasło serwera MS SQL jest niepoprawne: %s.", +"You need to enter either an existing account or the administrator." => "Należy wprowadzić istniejące konto użytkownika lub administratora.", +"MySQL username and/or password not valid" => "MySQL: Nazwa użytkownika i/lub hasło jest niepoprawne", +"DB Error: \"%s\"" => "Błąd DB: \"%s\"", +"Offending command was: \"%s\"" => "Niepoprawna komenda: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Użytkownik MySQL '%s'@'localhost' już istnieje", +"Drop this user from MySQL" => "Usuń tego użytkownika z MySQL", +"MySQL user '%s'@'%%' already exists" => "Użytkownik MySQL '%s'@'%%t' już istnieje", +"Drop this user from MySQL." => "Usuń tego użytkownika z MySQL.", +"Oracle connection could not be established" => "Nie można ustanowić połączenia z bazą Oracle", +"Oracle username and/or password not valid" => "Oracle: Nazwa użytkownika i/lub hasło jest niepoprawne", +"Offending command was: \"%s\", name: %s, password: %s" => "Niepoprawne polecania: \"%s\", nazwa: %s, hasło: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL: Nazwa użytkownika i/lub hasło jest niepoprawne", +"Set an admin username." => "Ustaw nazwę administratora.", +"Set an admin password." => "Ustaw hasło administratora.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serwer internetowy nie jest jeszcze poprawnie skonfigurowany, aby umożliwić synchronizację plików, ponieważ interfejs WebDAV wydaje się być uszkodzony.", +"Please double check the installation guides." => "Sprawdź ponownie przewodniki instalacji.", +"Could not find category \"%s\"" => "Nie można odnaleźć kategorii \"%s\"", +"seconds ago" => "sekund temu", +"_%n minute ago_::_%n minutes ago_" => array("%n minute temu","%n minut temu","%n minut temu"), +"_%n hour ago_::_%n hours ago_" => array("%n godzinę temu","%n godzin temu","%n godzin temu"), +"today" => "dziś", +"yesterday" => "wczoraj", +"_%n day go_::_%n days ago_" => array("%n dzień temu","%n dni temu","%n dni temu"), +"last month" => "w zeszłym miesiącu", +"_%n month ago_::_%n months ago_" => array("%n miesiąc temu","%n miesięcy temu","%n miesięcy temu"), +"last year" => "w zeszłym roku", +"years ago" => "lat temu", +"Caused by:" => "Spowodowane przez:" +); +$PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/pl_PL.php b/lib/private/l10n/pl_PL.php new file mode 100644 index 00000000000..5494e3dab25 --- /dev/null +++ b/lib/private/l10n/pl_PL.php @@ -0,0 +1,5 @@ + "Ustawienia" +); +$PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/pt_BR.php b/lib/private/l10n/pt_BR.php new file mode 100644 index 00000000000..7a580799701 --- /dev/null +++ b/lib/private/l10n/pt_BR.php @@ -0,0 +1,72 @@ + "O aplicativo \"%s\" não pode ser instalado porque não é compatível com esta versão do ownCloud.", +"No app name specified" => "O nome do aplicativo não foi especificado.", +"Help" => "Ajuda", +"Personal" => "Pessoal", +"Settings" => "Ajustes", +"Users" => "Usuários", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Falha na atualização de \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Fotos de perfil personalizados ainda não funcionam com criptografia", +"Unknown filetype" => "Tipo de arquivo desconhecido", +"Invalid image" => "Imagem inválida", +"web services under your control" => "serviços web sob seu controle", +"cannot open \"%s\"" => "não pode abrir \"%s\"", +"ZIP download is turned off." => "Download ZIP está desligado.", +"Files need to be downloaded one by one." => "Arquivos precisam ser baixados um de cada vez.", +"Back to Files" => "Voltar para Arquivos", +"Selected files too large to generate zip file." => "Arquivos selecionados são muito grandes para gerar arquivo zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Baixe os arquivos em pedaços menores, separadamente ou solicite educadamente ao seu administrador.", +"No source specified when installing app" => "Nenhuma fonte foi especificada enquanto instalava o aplicativo", +"No href specified when installing app from http" => "Nenhuma href foi especificada enquanto instalava o aplicativo de httml", +"No path specified when installing app from local file" => "Nenhum caminho foi especificado enquanto instalava o aplicativo do arquivo local", +"Archives of type %s are not supported" => "Arquivos do tipo %s não são suportados", +"Failed to open archive when installing app" => "Falha para abrir o arquivo enquanto instalava o aplicativo", +"App does not provide an info.xml file" => "O aplicativo não fornece um arquivo info.xml", +"App can't be installed because of not allowed code in the App" => "O aplicativo não pode ser instalado por causa do código não permitido no Aplivativo", +"App can't be installed because it is not compatible with this version of ownCloud" => "O aplicativo não pode ser instalado porque não é compatível com esta versão do ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "O aplicativo não pode ser instalado porque ele contém a marca verdadeiro que não é permitido para aplicações não embarcadas", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "O aplicativo não pode ser instalado porque a versão em info.xml /versão não é a mesma que a versão relatada na App Store", +"App directory already exists" => "Diretório App já existe", +"Can't create app folder. Please fix permissions. %s" => "Não é possível criar pasta app. Corrija as permissões. %s", +"Application is not enabled" => "Aplicação não está habilitada", +"Authentication error" => "Erro de autenticação", +"Token expired. Please reload page." => "Token expirou. Por favor recarregue a página.", +"Files" => "Arquivos", +"Text" => "Texto", +"Images" => "Imagens", +"%s enter the database username." => "%s insira o nome de usuário do banco de dados.", +"%s enter the database name." => "%s insira o nome do banco de dados.", +"%s you may not use dots in the database name" => "%s você não pode usar pontos no nome do banco de dados", +"MS SQL username and/or password not valid: %s" => "Nome de usuário e/ou senha MS SQL inválido(s): %s", +"You need to enter either an existing account or the administrator." => "Você precisa inserir uma conta existente ou o administrador.", +"MySQL username and/or password not valid" => "Nome de usuário e/ou senha MySQL inválido(s)", +"DB Error: \"%s\"" => "Erro no BD: \"%s\"", +"Offending command was: \"%s\"" => "Comando ofensivo era: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "O usuário MySQL '%s'@'localhost' já existe.", +"Drop this user from MySQL" => "Derrubar este usuário do MySQL", +"MySQL user '%s'@'%%' already exists" => "Usuário MySQL '%s'@'%%' já existe", +"Drop this user from MySQL." => "Derrube este usuário do MySQL.", +"Oracle connection could not be established" => "Conexão Oracle não pode ser estabelecida", +"Oracle username and/or password not valid" => "Nome de usuário e/ou senha Oracle inválido(s)", +"Offending command was: \"%s\", name: %s, password: %s" => "Comando ofensivo era: \"%s\", nome: %s, senha: %s", +"PostgreSQL username and/or password not valid" => "Nome de usuário e/ou senha PostgreSQL inválido(s)", +"Set an admin username." => "Defina um nome de usuário de administrador.", +"Set an admin password." => "Defina uma senha de administrador.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Seu servidor web não está configurado corretamente para permitir sincronização de arquivos porque a interface WebDAV parece estar quebrada.", +"Please double check the installation guides." => "Por favor, confira os guias de instalação.", +"seconds ago" => "segundos atrás", +"_%n minute ago_::_%n minutes ago_" => array("","ha %n minutos"), +"_%n hour ago_::_%n hours ago_" => array("","ha %n horas"), +"today" => "hoje", +"yesterday" => "ontem", +"_%n day go_::_%n days ago_" => array("","ha %n dias"), +"last month" => "último mês", +"_%n month ago_::_%n months ago_" => array("","ha %n meses"), +"last year" => "último ano", +"years ago" => "anos atrás", +"Caused by:" => "Causados ​​por:", +"Could not find category \"%s\"" => "Impossível localizar categoria \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/private/l10n/pt_PT.php b/lib/private/l10n/pt_PT.php new file mode 100644 index 00000000000..6e2bcba7b10 --- /dev/null +++ b/lib/private/l10n/pt_PT.php @@ -0,0 +1,57 @@ + "Ajuda", +"Personal" => "Pessoal", +"Settings" => "Configurações", +"Users" => "Utilizadores", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "A actualização \"%s\" falhou.", +"Unknown filetype" => "Ficheiro desconhecido", +"Invalid image" => "Imagem inválida", +"web services under your control" => "serviços web sob o seu controlo", +"cannot open \"%s\"" => "Não foi possível abrir \"%s\"", +"ZIP download is turned off." => "Descarregamento em ZIP está desligado.", +"Files need to be downloaded one by one." => "Os ficheiros precisam de ser descarregados um por um.", +"Back to Files" => "Voltar a Ficheiros", +"Selected files too large to generate zip file." => "Os ficheiros seleccionados são grandes demais para gerar um ficheiro zip.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Descarregue os ficheiros em partes menores, separados ou peça gentilmente ao seu administrador.", +"Application is not enabled" => "A aplicação não está activada", +"Authentication error" => "Erro na autenticação", +"Token expired. Please reload page." => "O token expirou. Por favor recarregue a página.", +"Files" => "Ficheiros", +"Text" => "Texto", +"Images" => "Imagens", +"%s enter the database username." => "%s introduza o nome de utilizador da base de dados", +"%s enter the database name." => "%s introduza o nome da base de dados", +"%s you may not use dots in the database name" => "%s não é permitido utilizar pontos (.) no nome da base de dados", +"MS SQL username and/or password not valid: %s" => "Nome de utilizador/password do MySQL é inválido: %s", +"You need to enter either an existing account or the administrator." => "Precisa de introduzir uma conta existente ou de administrador", +"MySQL username and/or password not valid" => "Nome de utilizador/password do MySQL inválida", +"DB Error: \"%s\"" => "Erro na BD: \"%s\"", +"Offending command was: \"%s\"" => "O comando gerador de erro foi: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "O utilizador '%s'@'localhost' do MySQL já existe.", +"Drop this user from MySQL" => "Eliminar este utilizador do MySQL", +"MySQL user '%s'@'%%' already exists" => "O utilizador '%s'@'%%' do MySQL já existe", +"Drop this user from MySQL." => "Eliminar este utilizador do MySQL", +"Oracle connection could not be established" => "Não foi possível estabelecer a ligação Oracle", +"Oracle username and/or password not valid" => "Nome de utilizador/password do Oracle inválida", +"Offending command was: \"%s\", name: %s, password: %s" => "O comando gerador de erro foi: \"%s\", nome: %s, password: %s", +"PostgreSQL username and/or password not valid" => "Nome de utilizador/password do PostgreSQL inválido", +"Set an admin username." => "Definir um nome de utilizador de administrador", +"Set an admin password." => "Definiar uma password de administrador", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "O seu servidor web não está configurado correctamente para autorizar sincronização de ficheiros, pois o interface WebDAV parece estar com problemas.", +"Please double check the installation guides." => "Por favor verifique installation guides.", +"seconds ago" => "Minutos atrás", +"_%n minute ago_::_%n minutes ago_" => array("","%n minutos atrás"), +"_%n hour ago_::_%n hours ago_" => array("","%n horas atrás"), +"today" => "hoje", +"yesterday" => "ontem", +"_%n day go_::_%n days ago_" => array("","%n dias atrás"), +"last month" => "ultímo mês", +"_%n month ago_::_%n months ago_" => array("","%n meses atrás"), +"last year" => "ano passado", +"years ago" => "anos atrás", +"Caused by:" => "Causado por:", +"Could not find category \"%s\"" => "Não foi encontrado a categoria \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/ro.php b/lib/private/l10n/ro.php new file mode 100644 index 00000000000..76dafcd03e0 --- /dev/null +++ b/lib/private/l10n/ro.php @@ -0,0 +1,35 @@ + "Ajutor", +"Personal" => "Personal", +"Settings" => "Setări", +"Users" => "Utilizatori", +"Admin" => "Admin", +"Unknown filetype" => "Tip fișier necunoscut", +"Invalid image" => "Imagine invalidă", +"web services under your control" => "servicii web controlate de tine", +"ZIP download is turned off." => "Descărcarea ZIP este dezactivată.", +"Files need to be downloaded one by one." => "Fișierele trebuie descărcate unul câte unul.", +"Back to Files" => "Înapoi la fișiere", +"Selected files too large to generate zip file." => "Fișierele selectate sunt prea mari pentru a genera un fișier zip.", +"Application is not enabled" => "Aplicația nu este activată", +"Authentication error" => "Eroare la autentificare", +"Token expired. Please reload page." => "Token expirat. Te rugăm să reîncarci pagina.", +"Files" => "Fișiere", +"Text" => "Text", +"Images" => "Imagini", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serverul de web nu este încă setat corespunzător pentru a permite sincronizarea fișierelor deoarece interfața WebDAV pare a fi întreruptă.", +"Please double check the installation guides." => "Vă rugăm să verificați ghiduri de instalare.", +"seconds ago" => "secunde în urmă", +"_%n minute ago_::_%n minutes ago_" => array("","","acum %n minute"), +"_%n hour ago_::_%n hours ago_" => array("","","acum %n ore"), +"today" => "astăzi", +"yesterday" => "ieri", +"_%n day go_::_%n days ago_" => array("","","acum %n zile"), +"last month" => "ultima lună", +"_%n month ago_::_%n months ago_" => array("","",""), +"last year" => "ultimul an", +"years ago" => "ani în urmă", +"Could not find category \"%s\"" => "Cloud nu a gasit categoria \"%s\"" +); +$PLURAL_FORMS = "nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"; diff --git a/lib/private/l10n/ru.php b/lib/private/l10n/ru.php new file mode 100644 index 00000000000..501065f8b5f --- /dev/null +++ b/lib/private/l10n/ru.php @@ -0,0 +1,72 @@ + "Приложение \"%s\" нельзя установить, так как оно не совместимо с текущей версией ownCloud.", +"No app name specified" => "Не выбрано имя приложения", +"Help" => "Помощь", +"Personal" => "Личное", +"Settings" => "Конфигурация", +"Users" => "Пользователи", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Не смог обновить \"%s\".", +"Custom profile pictures don't work with encryption yet" => "Пользовательские картинки профиля ещё не поддерживают шифрование", +"Unknown filetype" => "Неизвестный тип файла", +"Invalid image" => "Изображение повреждено", +"web services under your control" => "веб-сервисы под вашим управлением", +"cannot open \"%s\"" => "не могу открыть \"%s\"", +"ZIP download is turned off." => "ZIP-скачивание отключено.", +"Files need to be downloaded one by one." => "Файлы должны быть загружены по одному.", +"Back to Files" => "Назад к файлам", +"Selected files too large to generate zip file." => "Выбранные файлы слишком велики, чтобы создать zip файл.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Загрузите файл маленьшими порциями, раздельно или вежливо попросите Вашего администратора.", +"No source specified when installing app" => "Не указан источник при установке приложения", +"No href specified when installing app from http" => "Не указан атрибут href при установке приложения через http", +"No path specified when installing app from local file" => "Не указан путь при установке приложения из локального файла", +"Archives of type %s are not supported" => "Архивы %s не поддерживаются", +"Failed to open archive when installing app" => "Не возможно открыть архив при установке приложения", +"App does not provide an info.xml file" => "Приложение не имеет файла info.xml", +"App can't be installed because of not allowed code in the App" => "Приложение невозможно установить. В нем содержится запрещенный код.", +"App can't be installed because it is not compatible with this version of ownCloud" => "Приложение невозможно установить. Не совместимо с текущей версией ownCloud.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Приложение невозможно установить. Оно содержит параметр true который не допустим для приложений, не входящих в поставку.", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Приложение невозможно установить. Версия в info.xml/version не совпадает с версией заявленной в магазине приложений", +"App directory already exists" => "Папка приложения уже существует", +"Can't create app folder. Please fix permissions. %s" => "Не удалось создать директорию. Исправьте права доступа. %s", +"Application is not enabled" => "Приложение не разрешено", +"Authentication error" => "Ошибка аутентификации", +"Token expired. Please reload page." => "Токен просрочен. Перезагрузите страницу.", +"Files" => "Файлы", +"Text" => "Текст", +"Images" => "Изображения", +"%s enter the database username." => "%s введите имя пользователя базы данных.", +"%s enter the database name." => "%s введите имя базы данных.", +"%s you may not use dots in the database name" => "%s Вы не можете использовать точки в имени базы данных", +"MS SQL username and/or password not valid: %s" => "Имя пользователя и/или пароль MS SQL не подходит: %s", +"You need to enter either an existing account or the administrator." => "Вы должны войти или в существующий аккаунт или под администратором.", +"MySQL username and/or password not valid" => "Неверное имя пользователя и/или пароль MySQL", +"DB Error: \"%s\"" => "Ошибка БД: \"%s\"", +"Offending command was: \"%s\"" => "Вызываемая команда была: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Пользователь MySQL '%s'@'localhost' уже существует.", +"Drop this user from MySQL" => "Удалить этого пользователя из MySQL", +"MySQL user '%s'@'%%' already exists" => "Пользователь MySQL '%s'@'%%' уже существует", +"Drop this user from MySQL." => "Удалить этого пользователя из MySQL.", +"Oracle connection could not be established" => "соединение с Oracle не может быть установлено", +"Oracle username and/or password not valid" => "Неверное имя пользователя и/или пароль Oracle", +"Offending command was: \"%s\", name: %s, password: %s" => "Вызываемая команда была: \"%s\", имя: %s, пароль: %s", +"PostgreSQL username and/or password not valid" => "Неверное имя пользователя и/или пароль PostgreSQL", +"Set an admin username." => "Установить имя пользователя для admin.", +"Set an admin password." => "становит пароль для admin.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш веб сервер до сих пор не настроен правильно для возможности синхронизации файлов, похоже что проблема в неисправности интерфейса WebDAV.", +"Please double check the installation guides." => "Пожалуйста, дважды просмотрите инструкции по установке.", +"seconds ago" => "несколько секунд назад", +"_%n minute ago_::_%n minutes ago_" => array("%n минута назад","%n минуты назад","%n минут назад"), +"_%n hour ago_::_%n hours ago_" => array("%n час назад","%n часа назад","%n часов назад"), +"today" => "сегодня", +"yesterday" => "вчера", +"_%n day go_::_%n days ago_" => array("%n день назад","%n дня назад","%n дней назад"), +"last month" => "в прошлом месяце", +"_%n month ago_::_%n months ago_" => array("%n месяц назад","%n месяца назад","%n месяцев назад"), +"last year" => "в прошлом году", +"years ago" => "несколько лет назад", +"Caused by:" => "Вызвано:", +"Could not find category \"%s\"" => "Категория \"%s\" не найдена" +); +$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/si_LK.php b/lib/private/l10n/si_LK.php new file mode 100644 index 00000000000..d10804cae69 --- /dev/null +++ b/lib/private/l10n/si_LK.php @@ -0,0 +1,30 @@ + "උදව්", +"Personal" => "පෞද්ගලික", +"Settings" => "සිටුවම්", +"Users" => "පරිශීලකයන්", +"Admin" => "පරිපාලක", +"web services under your control" => "ඔබට පාලනය කළ හැකි වෙබ් සේවාවන්", +"ZIP download is turned off." => "ZIP භාගත කිරීම් අක්‍රියයි", +"Files need to be downloaded one by one." => "ගොනු එකින් එක භාගත යුතුයි", +"Back to Files" => "ගොනු වෙතට නැවත යන්න", +"Selected files too large to generate zip file." => "තෝරාගත් ගොනු ZIP ගොනුවක් තැනීමට විශාල වැඩිය.", +"Application is not enabled" => "යෙදුම සක්‍රිය කර නොමැත", +"Authentication error" => "සත්‍යාපන දෝෂයක්", +"Token expired. Please reload page." => "ටෝකනය කල් ඉකුත් වී ඇත. පිටුව නැවුම් කරන්න", +"Files" => "ගොනු", +"Text" => "පෙළ", +"Images" => "අනු රූ", +"seconds ago" => "තත්පරයන්ට පෙර", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "අද", +"yesterday" => "ඊයේ", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "පෙර මාසයේ", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "පෙර අවුරුද්දේ", +"years ago" => "අවුරුදු කීපයකට පෙර" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/sk.php b/lib/private/l10n/sk.php new file mode 100644 index 00000000000..54812b15a6f --- /dev/null +++ b/lib/private/l10n/sk.php @@ -0,0 +1,8 @@ + array("","",""), +"_%n hour ago_::_%n hours ago_" => array("","",""), +"_%n day go_::_%n days ago_" => array("","",""), +"_%n month ago_::_%n months ago_" => array("","","") +); +$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/lib/private/l10n/sk_SK.php b/lib/private/l10n/sk_SK.php new file mode 100644 index 00000000000..13487b039d6 --- /dev/null +++ b/lib/private/l10n/sk_SK.php @@ -0,0 +1,69 @@ + "Aplikácia \"%s\" nemôže byť nainštalovaná kvôli nekompatibilite z danou verziou ownCloudu.", +"No app name specified" => "Nešpecifikované meno aplikácie", +"Help" => "Pomoc", +"Personal" => "Osobné", +"Settings" => "Nastavenia", +"Users" => "Používatelia", +"Admin" => "Administrátor", +"Failed to upgrade \"%s\"." => "Zlyhala aktualizácia \"%s\".", +"web services under your control" => "webové služby pod Vašou kontrolou", +"cannot open \"%s\"" => "nemožno otvoriť \"%s\"", +"ZIP download is turned off." => "Sťahovanie súborov ZIP je vypnuté.", +"Files need to be downloaded one by one." => "Súbory musia byť nahrávané jeden za druhým.", +"Back to Files" => "Späť na súbory", +"Selected files too large to generate zip file." => "Zvolené súbory sú príliš veľké na vygenerovanie zip súboru.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Stiahnite súbory po menších častiach, samostatne, alebo sa obráťte na správcu.", +"No source specified when installing app" => "Nešpecifikovaný zdroj pri inštalácii aplikácie", +"No href specified when installing app from http" => "Nešpecifikovaný atribút \"href\" pri inštalácii aplikácie pomocou protokolu \"http\"", +"No path specified when installing app from local file" => "Nešpecifikovaná cesta pri inštalácii aplikácie z lokálneho súboru", +"Archives of type %s are not supported" => "Typ archívu %s nie je podporovaný", +"Failed to open archive when installing app" => "Zlyhanie pri otváraní archívu počas inštalácie aplikácie", +"App does not provide an info.xml file" => "Aplikácia neposkytuje súbor info.xml", +"App can't be installed because of not allowed code in the App" => "Aplikácia nemôže byť inštalovaná pre nepovolený kód v aplikácii", +"App can't be installed because it is not compatible with this version of ownCloud" => "Aplikácia nemôže byť inštalovaná pre nekompatibilitu z danou verziou ownCloudu", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Aplikácia nemôže byť inštalovaná pretože obsahuje pravý štítok, ktorý nie je povolený pre zaslané \"shipped\" aplikácie", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Aplikácia nemôže byť inštalovaná pretože verzia v info.xml/version nezodpovedá verzii špecifikovanej v aplikačnom obchode", +"App directory already exists" => "Aplikačný adresár už existuje", +"Can't create app folder. Please fix permissions. %s" => "Nemožno vytvoriť aplikačný priečinok. Prosím upravte povolenia. %s", +"Application is not enabled" => "Aplikácia nie je zapnutá", +"Authentication error" => "Chyba autentifikácie", +"Token expired. Please reload page." => "Token vypršal. Obnovte, prosím, stránku.", +"Files" => "Súbory", +"Text" => "Text", +"Images" => "Obrázky", +"%s enter the database username." => "Zadajte používateľské meno %s databázy..", +"%s enter the database name." => "Zadajte názov databázy pre %s databázy.", +"%s you may not use dots in the database name" => "V názve databázy %s nemôžete používať bodky", +"MS SQL username and/or password not valid: %s" => "Používateľské meno, alebo heslo MS SQL nie je platné: %s", +"You need to enter either an existing account or the administrator." => "Musíte zadať jestvujúci účet alebo administrátora.", +"MySQL username and/or password not valid" => "Používateľské meno a/alebo heslo pre MySQL databázu je neplatné", +"DB Error: \"%s\"" => "Chyba DB: \"%s\"", +"Offending command was: \"%s\"" => "Podozrivý príkaz bol: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Používateľ '%s'@'localhost' už v MySQL existuje.", +"Drop this user from MySQL" => "Zahodiť používateľa z MySQL.", +"MySQL user '%s'@'%%' already exists" => "Používateľ '%s'@'%%' už v MySQL existuje", +"Drop this user from MySQL." => "Zahodiť používateľa z MySQL.", +"Oracle connection could not be established" => "Nie je možné pripojiť sa k Oracle", +"Oracle username and/or password not valid" => "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné", +"Offending command was: \"%s\", name: %s, password: %s" => "Podozrivý príkaz bol: \"%s\", meno: %s, heslo: %s", +"PostgreSQL username and/or password not valid" => "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné", +"Set an admin username." => "Zadajte používateľské meno administrátora.", +"Set an admin password." => "Zadajte heslo administrátora.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Váš webový server nie je správne nastavený na synchronizáciu, pretože rozhranie WebDAV je poškodené.", +"Please double check the installation guides." => "Prosím skontrolujte inštalačnú príručku.", +"seconds ago" => "pred sekundami", +"_%n minute ago_::_%n minutes ago_" => array("","","pred %n minútami"), +"_%n hour ago_::_%n hours ago_" => array("","","pred %n hodinami"), +"today" => "dnes", +"yesterday" => "včera", +"_%n day go_::_%n days ago_" => array("","","pred %n dňami"), +"last month" => "minulý mesiac", +"_%n month ago_::_%n months ago_" => array("","","pred %n mesiacmi"), +"last year" => "minulý rok", +"years ago" => "pred rokmi", +"Caused by:" => "Príčina:", +"Could not find category \"%s\"" => "Nemožno nájsť danú kategóriu \"%s\"" +); +$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/lib/private/l10n/sl.php b/lib/private/l10n/sl.php new file mode 100644 index 00000000000..5722191aedf --- /dev/null +++ b/lib/private/l10n/sl.php @@ -0,0 +1,51 @@ + "Pomoč", +"Personal" => "Osebno", +"Settings" => "Nastavitve", +"Users" => "Uporabniki", +"Admin" => "Skrbništvo", +"web services under your control" => "spletne storitve pod vašim nadzorom", +"ZIP download is turned off." => "Prejemanje datotek v paketu ZIP je onemogočeno.", +"Files need to be downloaded one by one." => "Datoteke je mogoče prejeti le posamično.", +"Back to Files" => "Nazaj na datoteke", +"Selected files too large to generate zip file." => "Izbrane datoteke so prevelike za ustvarjanje datoteke arhiva zip.", +"Application is not enabled" => "Program ni omogočen", +"Authentication error" => "Napaka pri overjanju", +"Token expired. Please reload page." => "Žeton je potekel. Stran je treba ponovno naložiti.", +"Files" => "Datoteke", +"Text" => "Besedilo", +"Images" => "Slike", +"%s enter the database username." => "%s - vnos uporabniškega imena podatkovne zbirke.", +"%s enter the database name." => "%s - vnos imena podatkovne zbirke.", +"%s you may not use dots in the database name" => "%s - v imenu podatkovne zbirke ni dovoljeno uporabljati pik.", +"MS SQL username and/or password not valid: %s" => "Uporabniško ime ali geslo MS SQL ni veljavno: %s", +"You need to enter either an existing account or the administrator." => "Prijaviti se je treba v obstoječi ali pa skrbniški račun.", +"MySQL username and/or password not valid" => "Uporabniško ime ali geslo MySQL ni veljavno", +"DB Error: \"%s\"" => "Napaka podatkovne zbirke: \"%s\"", +"Offending command was: \"%s\"" => "Napačni ukaz je: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Uporabnik MySQL '%s'@'localhost' že obstaja.", +"Drop this user from MySQL" => "Odstrani uporabnika s podatkovne zbirke MySQL", +"MySQL user '%s'@'%%' already exists" => "Uporabnik MySQL '%s'@'%%' že obstaja.", +"Drop this user from MySQL." => "Odstrani uporabnika s podatkovne zbirke MySQL", +"Oracle connection could not be established" => "Povezava z bazo Oracle ni uspela.", +"Oracle username and/or password not valid" => "Uporabniško ime ali geslo Oracle ni veljavno", +"Offending command was: \"%s\", name: %s, password: %s" => "Napačni ukaz je: \"%s\", ime: %s, geslo: %s", +"PostgreSQL username and/or password not valid" => "Uporabniško ime ali geslo PostgreSQL ni veljavno", +"Set an admin username." => "Nastavi uporabniško ime skrbnika.", +"Set an admin password." => "Nastavi geslo skrbnika.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Spletni stražnik še ni ustrezno nastavljen in ne omogoča usklajevanja, saj je nastavitev WebDAV okvarjena.", +"Please double check the installation guides." => "Preverite navodila namestitve.", +"seconds ago" => "pred nekaj sekundami", +"_%n minute ago_::_%n minutes ago_" => array("","","",""), +"_%n hour ago_::_%n hours ago_" => array("","","",""), +"today" => "danes", +"yesterday" => "včeraj", +"_%n day go_::_%n days ago_" => array("","","",""), +"last month" => "zadnji mesec", +"_%n month ago_::_%n months ago_" => array("","","",""), +"last year" => "lansko leto", +"years ago" => "let nazaj", +"Could not find category \"%s\"" => "Kategorije \"%s\" ni mogoče najti." +); +$PLURAL_FORMS = "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"; diff --git a/lib/private/l10n/sq.php b/lib/private/l10n/sq.php new file mode 100644 index 00000000000..edaa1df2b86 --- /dev/null +++ b/lib/private/l10n/sq.php @@ -0,0 +1,50 @@ + "Ndihmë", +"Personal" => "Personale", +"Settings" => "Parametra", +"Users" => "Përdoruesit", +"Admin" => "Admin", +"web services under your control" => "shërbime web nën kontrollin tënd", +"ZIP download is turned off." => "Shkarimi i skedarëve ZIP është i çaktivizuar.", +"Files need to be downloaded one by one." => "Skedarët duhet të shkarkohen një nga një.", +"Back to Files" => "Kthehu tek skedarët", +"Selected files too large to generate zip file." => "Skedarët e selektuar janë shumë të mëdhenj për të krijuar një skedar ZIP.", +"Application is not enabled" => "Programi nuk është i aktivizuar.", +"Authentication error" => "Veprim i gabuar gjatë vërtetimit të identitetit", +"Token expired. Please reload page." => "Përmbajtja ka skaduar. Ju lutemi ringarkoni faqen.", +"Files" => "Skedarët", +"Text" => "Tekst", +"Images" => "Foto", +"%s enter the database username." => "% shkruani përdoruesin e database-it.", +"%s enter the database name." => "%s shkruani emrin e database-it.", +"%s you may not use dots in the database name" => "%s nuk mund të përdorni pikat tek emri i database-it", +"MS SQL username and/or password not valid: %s" => "Përdoruesi dhe/apo kodi i MS SQL i pavlefshëm: %s", +"You need to enter either an existing account or the administrator." => "Duhet të përdorni një llogari ekzistuese ose llogarinë e administratorit.", +"MySQL username and/or password not valid" => "Përdoruesi dhe/apo kodi i MySQL-it i pavlefshëm.", +"DB Error: \"%s\"" => "Veprim i gabuar i DB-it: \"%s\"", +"Offending command was: \"%s\"" => "Komanda e gabuar ishte: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Përdoruesi MySQL '%s'@'localhost' ekziston.", +"Drop this user from MySQL" => "Eliminoni këtë përdorues nga MySQL", +"MySQL user '%s'@'%%' already exists" => "Përdoruesi MySQL '%s'@'%%' ekziston", +"Drop this user from MySQL." => "Eliminoni këtë përdorues nga MySQL.", +"Oracle username and/or password not valid" => "Përdoruesi dhe/apo kodi i Oracle-it i pavlefshëm", +"Offending command was: \"%s\", name: %s, password: %s" => "Komanda e gabuar ishte: \"%s\", përdoruesi: %s, kodi: %s", +"PostgreSQL username and/or password not valid" => "Përdoruesi dhe/apo kodi i PostgreSQL i pavlefshëm", +"Set an admin username." => "Cakto emrin e administratorit.", +"Set an admin password." => "Cakto kodin e administratorit.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serveri web i juaji nuk është konfiguruar akoma për të lejuar sinkronizimin e skedarëve sepse ndërfaqja WebDAV mund të jetë e dëmtuar.", +"Please double check the installation guides." => "Ju lutemi kontrolloni mirë shoqëruesin e instalimit.", +"seconds ago" => "sekonda më parë", +"_%n minute ago_::_%n minutes ago_" => array("","%n minuta më parë"), +"_%n hour ago_::_%n hours ago_" => array("","%n orë më parë"), +"today" => "sot", +"yesterday" => "dje", +"_%n day go_::_%n days ago_" => array("","%n ditë më parë"), +"last month" => "muajin e shkuar", +"_%n month ago_::_%n months ago_" => array("","%n muaj më parë"), +"last year" => "vitin e shkuar", +"years ago" => "vite më parë", +"Could not find category \"%s\"" => "Kategoria \"%s\" nuk u gjet" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/sr.php b/lib/private/l10n/sr.php new file mode 100644 index 00000000000..9441d0578fc --- /dev/null +++ b/lib/private/l10n/sr.php @@ -0,0 +1,33 @@ + "Помоћ", +"Personal" => "Лично", +"Settings" => "Поставке", +"Users" => "Корисници", +"Admin" => "Администратор", +"web services under your control" => "веб сервиси под контролом", +"ZIP download is turned off." => "Преузимање ZIP-а је искључено.", +"Files need to be downloaded one by one." => "Датотеке морате преузимати једну по једну.", +"Back to Files" => "Назад на датотеке", +"Selected files too large to generate zip file." => "Изабране датотеке су превелике да бисте направили ZIP датотеку.", +"Application is not enabled" => "Апликација није омогућена", +"Authentication error" => "Грешка при провери идентитета", +"Token expired. Please reload page." => "Жетон је истекао. Поново учитајте страницу.", +"Files" => "Датотеке", +"Text" => "Текст", +"Images" => "Слике", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш веб сервер тренутно не подржава синхронизацију датотека јер се чини да је WebDAV сучеље неисправно.", +"Please double check the installation guides." => "Погледајте водиче за инсталацију.", +"seconds ago" => "пре неколико секунди", +"_%n minute ago_::_%n minutes ago_" => array("","",""), +"_%n hour ago_::_%n hours ago_" => array("","",""), +"today" => "данас", +"yesterday" => "јуче", +"_%n day go_::_%n days ago_" => array("","",""), +"last month" => "прошлог месеца", +"_%n month ago_::_%n months ago_" => array("","",""), +"last year" => "прошле године", +"years ago" => "година раније", +"Could not find category \"%s\"" => "Не могу да пронађем категорију „%s“." +); +$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/sr@latin.php b/lib/private/l10n/sr@latin.php new file mode 100644 index 00000000000..d8fa9289221 --- /dev/null +++ b/lib/private/l10n/sr@latin.php @@ -0,0 +1,22 @@ + "Pomoć", +"Personal" => "Lično", +"Settings" => "Podešavanja", +"Users" => "Korisnici", +"Admin" => "Adninistracija", +"Authentication error" => "Greška pri autentifikaciji", +"Files" => "Fajlovi", +"Text" => "Tekst", +"seconds ago" => "Pre par sekundi", +"_%n minute ago_::_%n minutes ago_" => array("","",""), +"_%n hour ago_::_%n hours ago_" => array("","",""), +"today" => "Danas", +"yesterday" => "juče", +"_%n day go_::_%n days ago_" => array("","",""), +"last month" => "prošlog meseca", +"_%n month ago_::_%n months ago_" => array("","",""), +"last year" => "prošle godine", +"years ago" => "pre nekoliko godina" +); +$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/string.php b/lib/private/l10n/string.php new file mode 100644 index 00000000000..88c85b32e70 --- /dev/null +++ b/lib/private/l10n/string.php @@ -0,0 +1,56 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_L10N_String{ + /** + * @var OC_L10N + */ + protected $l10n; + + /** + * @var string + */ + protected $text; + + /** + * @var array + */ + protected $parameters; + + /** + * @var integer + */ + protected $count; + + public function __construct($l10n, $text, $parameters, $count = 1) { + $this->l10n = $l10n; + $this->text = $text; + $this->parameters = $parameters; + $this->count = $count; + } + + public function __toString() { + $translations = $this->l10n->getTranslations(); + + $text = $this->text; + if(array_key_exists($this->text, $translations)) { + if(is_array($translations[$this->text])) { + $fn = $this->l10n->getPluralFormFunction(); + $id = $fn($this->count); + $text = $translations[$this->text][$id]; + } + else{ + $text = $translations[$this->text]; + } + } + + // Replace %n first (won't interfere with vsprintf) + $text = str_replace('%n', $this->count, $text); + return vsprintf($text, $this->parameters); + } +} diff --git a/lib/private/l10n/sv.php b/lib/private/l10n/sv.php new file mode 100644 index 00000000000..e7c3420a85b --- /dev/null +++ b/lib/private/l10n/sv.php @@ -0,0 +1,69 @@ + "Appen \"%s\" kan inte installeras eftersom att den inte är kompatibel med denna version av ownCloud.", +"No app name specified" => "Inget appnamn angivet", +"Help" => "Hjälp", +"Personal" => "Personligt", +"Settings" => "Inställningar", +"Users" => "Användare", +"Admin" => "Admin", +"Failed to upgrade \"%s\"." => "Misslyckades med att uppgradera \"%s\".", +"web services under your control" => "webbtjänster under din kontroll", +"cannot open \"%s\"" => "Kan inte öppna \"%s\"", +"ZIP download is turned off." => "Nerladdning av ZIP är avstängd.", +"Files need to be downloaded one by one." => "Filer laddas ner en åt gången.", +"Back to Files" => "Tillbaka till Filer", +"Selected files too large to generate zip file." => "Valda filer är för stora för att skapa zip-fil.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Ladda ner filerna i mindre bitar, separat eller fråga din administratör.", +"No source specified when installing app" => "Ingen källa angiven vid installation av app ", +"No href specified when installing app from http" => "Ingen href angiven vid installation av app från http", +"No path specified when installing app from local file" => "Ingen sökväg angiven vid installation av app från lokal fil", +"Archives of type %s are not supported" => "Arkiv av typen %s stöds ej", +"Failed to open archive when installing app" => "Kunde inte öppna arkivet när appen skulle installeras", +"App does not provide an info.xml file" => "Appen har ingen info.xml fil", +"App can't be installed because of not allowed code in the App" => "Appen kan inte installeras eftersom att den innehåller otillåten kod", +"App can't be installed because it is not compatible with this version of ownCloud" => "Appen kan inte installeras eftersom att den inte är kompatibel med denna version av ownCloud", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Appen kan inte installeras eftersom att den innehåller etiketten true vilket inte är tillåtet för icke inkluderade appar", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Appen kan inte installeras eftersom versionen i info.xml inte är samma som rapporteras från app store", +"App directory already exists" => "Appens mapp finns redan", +"Can't create app folder. Please fix permissions. %s" => "Kan inte skapa appens mapp. Var god åtgärda rättigheterna. %s", +"Application is not enabled" => "Applikationen är inte aktiverad", +"Authentication error" => "Fel vid autentisering", +"Token expired. Please reload page." => "Ogiltig token. Ladda om sidan.", +"Files" => "Filer", +"Text" => "Text", +"Images" => "Bilder", +"%s enter the database username." => "%s ange databasanvändare.", +"%s enter the database name." => "%s ange databasnamn", +"%s you may not use dots in the database name" => "%s du får inte använda punkter i databasnamnet", +"MS SQL username and/or password not valid: %s" => "MS SQL-användaren och/eller lösenordet var inte giltigt: %s", +"You need to enter either an existing account or the administrator." => "Du måste antingen ange ett befintligt konto eller administratör.", +"MySQL username and/or password not valid" => "MySQL-användarnamnet och/eller lösenordet är felaktigt", +"DB Error: \"%s\"" => "DB error: \"%s\"", +"Offending command was: \"%s\"" => "Det felaktiga kommandot var: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL-användaren '%s'@'localhost' existerar redan.", +"Drop this user from MySQL" => "Radera denna användare från MySQL", +"MySQL user '%s'@'%%' already exists" => "MySQl-användare '%s'@'%%' existerar redan", +"Drop this user from MySQL." => "Radera denna användare från MySQL.", +"Oracle connection could not be established" => "Oracle-anslutning kunde inte etableras", +"Oracle username and/or password not valid" => "Oracle-användarnamnet och/eller lösenordet är felaktigt", +"Offending command was: \"%s\", name: %s, password: %s" => "Det felande kommandot var: \"%s\", name: %s, password: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt", +"Set an admin username." => "Ange ett användarnamn för administratören.", +"Set an admin password." => "Ange ett administratörslösenord.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din webbserver är inte korrekt konfigurerad för att tillåta filsynkronisering eftersom WebDAV inte verkar fungera.", +"Please double check the installation guides." => "Var god kontrollera installationsguiden.", +"seconds ago" => "sekunder sedan", +"_%n minute ago_::_%n minutes ago_" => array("%n minut sedan","%n minuter sedan"), +"_%n hour ago_::_%n hours ago_" => array("%n timme sedan","%n timmar sedan"), +"today" => "i dag", +"yesterday" => "i går", +"_%n day go_::_%n days ago_" => array("%n dag sedan","%n dagar sedan"), +"last month" => "förra månaden", +"_%n month ago_::_%n months ago_" => array("%n månad sedan","%n månader sedan"), +"last year" => "förra året", +"years ago" => "år sedan", +"Caused by:" => "Orsakad av:", +"Could not find category \"%s\"" => "Kunde inte hitta kategorin \"%s\"" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/sw_KE.php b/lib/private/l10n/sw_KE.php new file mode 100644 index 00000000000..15f78e0bce6 --- /dev/null +++ b/lib/private/l10n/sw_KE.php @@ -0,0 +1,8 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/ta_LK.php b/lib/private/l10n/ta_LK.php new file mode 100644 index 00000000000..e70e65845be --- /dev/null +++ b/lib/private/l10n/ta_LK.php @@ -0,0 +1,31 @@ + "உதவி", +"Personal" => "தனிப்பட்ட", +"Settings" => "அமைப்புகள்", +"Users" => "பயனாளர்", +"Admin" => "நிர்வாகம்", +"web services under your control" => "வலைய சேவைகள் உங்களுடைய கட்டுப்பாட்டின் கீழ் உள்ளது", +"ZIP download is turned off." => "வீசொலிப் பூட்டு பதிவிறக்கம் நிறுத்தப்பட்டுள்ளது.", +"Files need to be downloaded one by one." => "கோப்புகள்ஒன்றன் பின் ஒன்றாக பதிவிறக்கப்படவேண்டும்.", +"Back to Files" => "கோப்புகளுக்கு செல்க", +"Selected files too large to generate zip file." => "வீ சொலிக் கோப்புகளை உருவாக்குவதற்கு தெரிவுசெய்யப்பட்ட கோப்புகள் மிகப்பெரியவை", +"Application is not enabled" => "செயலி இயலுமைப்படுத்தப்படவில்லை", +"Authentication error" => "அத்தாட்சிப்படுத்தலில் வழு", +"Token expired. Please reload page." => "அடையாளவில்லை காலாவதியாகிவிட்டது. தயவுசெய்து பக்கத்தை மீள் ஏற்றுக.", +"Files" => "கோப்புகள்", +"Text" => "உரை", +"Images" => "படங்கள்", +"seconds ago" => "செக்கன்களுக்கு முன்", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "இன்று", +"yesterday" => "நேற்று", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "கடந்த மாதம்", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "கடந்த வருடம்", +"years ago" => "வருடங்களுக்கு முன்", +"Could not find category \"%s\"" => "பிரிவு \"%s\" ஐ கண்டுப்பிடிக்க முடியவில்லை" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/te.php b/lib/private/l10n/te.php new file mode 100644 index 00000000000..524ea0c6024 --- /dev/null +++ b/lib/private/l10n/te.php @@ -0,0 +1,17 @@ + "సహాయం", +"Settings" => "అమరికలు", +"Users" => "వాడుకరులు", +"seconds ago" => "క్షణాల క్రితం", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"today" => "ఈరోజు", +"yesterday" => "నిన్న", +"_%n day go_::_%n days ago_" => array("",""), +"last month" => "పోయిన నెల", +"_%n month ago_::_%n months ago_" => array("",""), +"last year" => "పోయిన సంవత్సరం", +"years ago" => "సంవత్సరాల క్రితం" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/th_TH.php b/lib/private/l10n/th_TH.php new file mode 100644 index 00000000000..3344d0bb18e --- /dev/null +++ b/lib/private/l10n/th_TH.php @@ -0,0 +1,31 @@ + "ช่วยเหลือ", +"Personal" => "ส่วนตัว", +"Settings" => "ตั้งค่า", +"Users" => "ผู้ใช้งาน", +"Admin" => "ผู้ดูแล", +"web services under your control" => "เว็บเซอร์วิสที่คุณควบคุมการใช้งานได้", +"ZIP download is turned off." => "คุณสมบัติการดาวน์โหลด zip ถูกปิดการใช้งานไว้", +"Files need to be downloaded one by one." => "ไฟล์สามารถดาวน์โหลดได้ทีละครั้งเท่านั้น", +"Back to Files" => "กลับไปที่ไฟล์", +"Selected files too large to generate zip file." => "ไฟล์ที่เลือกมีขนาดใหญ่เกินกว่าที่จะสร้างเป็นไฟล์ zip", +"Application is not enabled" => "แอพพลิเคชั่นดังกล่าวยังไม่ได้เปิดใช้งาน", +"Authentication error" => "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน", +"Token expired. Please reload page." => "รหัสยืนยันความถูกต้องหมดอายุแล้ว กรุณาโหลดหน้าเว็บใหม่อีกครั้ง", +"Files" => "ไฟล์", +"Text" => "ข้อความ", +"Images" => "รูปภาพ", +"seconds ago" => "วินาที ก่อนหน้านี้", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "วันนี้", +"yesterday" => "เมื่อวานนี้", +"_%n day go_::_%n days ago_" => array(""), +"last month" => "เดือนที่แล้ว", +"_%n month ago_::_%n months ago_" => array(""), +"last year" => "ปีที่แล้ว", +"years ago" => "ปี ที่ผ่านมา", +"Could not find category \"%s\"" => "ไม่พบหมวดหมู่ \"%s\"" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/tr.php b/lib/private/l10n/tr.php new file mode 100644 index 00000000000..b63c37c7240 --- /dev/null +++ b/lib/private/l10n/tr.php @@ -0,0 +1,69 @@ + "Owncloud yazılımının bu sürümü ile uyumlu olmadığı için \"%s\" uygulaması kurulamaz.", +"No app name specified" => "Uygulama adı belirtimedli", +"Help" => "Yardım", +"Personal" => "Kişisel", +"Settings" => "Ayarlar", +"Users" => "Kullanıcılar", +"Admin" => "Yönetici", +"Failed to upgrade \"%s\"." => "\"%s\" yükseltme başarısız oldu.", +"web services under your control" => "Bilgileriniz güvenli ve şifreli", +"cannot open \"%s\"" => "\"%s\" açılamıyor", +"ZIP download is turned off." => "ZIP indirmeleri kapatılmıştır.", +"Files need to be downloaded one by one." => "Dosyaların birer birer indirilmesi gerekmektedir.", +"Back to Files" => "Dosyalara dön", +"Selected files too large to generate zip file." => "Seçilen dosyalar bir zip dosyası oluşturmak için fazla büyüktür.", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "Dosyaları ayrı ayrı, küçük parçalar halinde indirin ya da yöneticinizden yardım isteyin. ", +"No source specified when installing app" => "Uygulama kurulurken bir kaynak belirtilmedi", +"No href specified when installing app from http" => "Uygulama kuruluyorken http'de href belirtilmedi.", +"No path specified when installing app from local file" => "Uygulama yerel dosyadan kuruluyorken dosya yolu belirtilmedi", +"Archives of type %s are not supported" => "%s arşiv tipi desteklenmiyor", +"Failed to open archive when installing app" => "Uygulama kuruluyorken arşiv dosyası açılamadı", +"App does not provide an info.xml file" => "Uygulama info.xml dosyası sağlamıyor", +"App can't be installed because of not allowed code in the App" => "Uygulamada izin verilmeyeden kodlar olduğu için kurulamıyor.", +"App can't be installed because it is not compatible with this version of ownCloud" => "Owncloud versiyonunuz ile uyumsuz olduğu için uygulama kurulamıyor.", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "Uygulama kurulamıyor. Çünkü \"non shipped\" uygulamalar için true tag içermektedir.", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "Uygulama kurulamıyor çünkü info.xml/version ile uygulama marketde belirtilen sürüm aynı değil.", +"App directory already exists" => "App dizini zaten mevcut", +"Can't create app folder. Please fix permissions. %s" => "app dizini oluşturulamıyor. Lütfen izinleri düzeltin. %s", +"Application is not enabled" => "Uygulama etkinleştirilmedi", +"Authentication error" => "Kimlik doğrulama hatası", +"Token expired. Please reload page." => "Jetonun süresi geçti. Lütfen sayfayı yenileyin.", +"Files" => "Dosyalar", +"Text" => "Metin", +"Images" => "Resimler", +"%s enter the database username." => "%s veritabanı kullanıcı adını gir.", +"%s enter the database name." => "%s veritabanı adını gir.", +"%s you may not use dots in the database name" => "%s veritabanı adında nokta kullanamayabilirsiniz", +"MS SQL username and/or password not valid: %s" => "MS SQL kullanıcı adı ve/veya parolası geçersiz: %s", +"You need to enter either an existing account or the administrator." => "Bir konto veya kullanici birlemek ihtiyacin. ", +"MySQL username and/or password not valid" => "MySQL kullanıcı adı ve/veya parolası geçerli değil", +"DB Error: \"%s\"" => "DB Hata: ''%s''", +"Offending command was: \"%s\"" => "Komut rahasiz ''%s''. ", +"MySQL user '%s'@'localhost' exists already." => "MySQL kullanici '%s @local host zatan var. ", +"Drop this user from MySQL" => "Bu kullanici MySQLden list disari koymak. ", +"MySQL user '%s'@'%%' already exists" => "MySQL kullanici '%s @ % % zaten var (zaten yazili)", +"Drop this user from MySQL." => "Bu kulanıcıyı MySQL veritabanından kaldır", +"Oracle connection could not be established" => "Oracle bağlantısı kurulamadı", +"Oracle username and/or password not valid" => "Adi klullanici ve/veya parola Oracle mantikli değildir. ", +"Offending command was: \"%s\", name: %s, password: %s" => "Hatalı komut: \"%s\", ad: %s, parola: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL adi kullanici ve/veya parola yasal degildir. ", +"Set an admin username." => "Bir adi kullanici vermek. ", +"Set an admin password." => "Parola yonetici birlemek. ", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Web sunucunuz dosya transferi için düzgün bir şekilde yapılandırılmamış. WevDAV arabirimini sorunlu gözüküyor.", +"Please double check the installation guides." => "Lütfen kurulum kılavuzlarını iki kez kontrol edin.", +"seconds ago" => "saniye önce", +"_%n minute ago_::_%n minutes ago_" => array("","%n dakika önce"), +"_%n hour ago_::_%n hours ago_" => array("","%n saat önce"), +"today" => "bugün", +"yesterday" => "dün", +"_%n day go_::_%n days ago_" => array("","%n gün önce"), +"last month" => "geçen ay", +"_%n month ago_::_%n months ago_" => array("","%n ay önce"), +"last year" => "geçen yıl", +"years ago" => "yıl önce", +"Caused by:" => "Neden olan:", +"Could not find category \"%s\"" => "\"%s\" kategorisi bulunamadı" +); +$PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/lib/private/l10n/ug.php b/lib/private/l10n/ug.php new file mode 100644 index 00000000000..e2cf38ecc8c --- /dev/null +++ b/lib/private/l10n/ug.php @@ -0,0 +1,19 @@ + "ياردەم", +"Personal" => "شەخسىي", +"Settings" => "تەڭشەكلەر", +"Users" => "ئىشلەتكۈچىلەر", +"Authentication error" => "سالاھىيەت دەلىللەش خاتالىقى", +"Files" => "ھۆججەتلەر", +"Text" => "قىسقا ئۇچۇر", +"Images" => "سۈرەتلەر", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "سىزنىڭ تور مۇلازىمېتىرىڭىز ھۆججەت قەدەمداشلاشقا يول قويىدىغان قىلىپ توغرا تەڭشەلمەپتۇ، چۈنكى WebDAV نىڭ ئېغىزى بۇزۇلغاندەك تۇرىدۇ.", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "بۈگۈن", +"yesterday" => "تۈنۈگۈن", +"_%n day go_::_%n days ago_" => array(""), +"_%n month ago_::_%n months ago_" => array("") +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/uk.php b/lib/private/l10n/uk.php new file mode 100644 index 00000000000..c1513c5bb79 --- /dev/null +++ b/lib/private/l10n/uk.php @@ -0,0 +1,50 @@ + "Допомога", +"Personal" => "Особисте", +"Settings" => "Налаштування", +"Users" => "Користувачі", +"Admin" => "Адмін", +"web services under your control" => "підконтрольні Вам веб-сервіси", +"ZIP download is turned off." => "ZIP завантаження вимкнено.", +"Files need to be downloaded one by one." => "Файли повинні бути завантаженні послідовно.", +"Back to Files" => "Повернутися до файлів", +"Selected files too large to generate zip file." => "Вибрані фали завеликі для генерування zip файлу.", +"Application is not enabled" => "Додаток не увімкнений", +"Authentication error" => "Помилка автентифікації", +"Token expired. Please reload page." => "Строк дії токена скінчився. Будь ласка, перезавантажте сторінку.", +"Files" => "Файли", +"Text" => "Текст", +"Images" => "Зображення", +"%s enter the database username." => "%s введіть ім'я користувача бази даних.", +"%s enter the database name." => "%s введіть назву бази даних.", +"%s you may not use dots in the database name" => "%s не можна використовувати крапки в назві бази даних", +"MS SQL username and/or password not valid: %s" => "MS SQL ім'я користувача та/або пароль не дійсні: %s", +"You need to enter either an existing account or the administrator." => "Вам потрібно ввести або існуючий обліковий запис або administrator.", +"MySQL username and/or password not valid" => "MySQL ім'я користувача та/або пароль не дійсні", +"DB Error: \"%s\"" => "Помилка БД: \"%s\"", +"Offending command was: \"%s\"" => "Команда, що викликала проблему: \"%s\"", +"MySQL user '%s'@'localhost' exists already." => "Користувач MySQL '%s'@'localhost' вже існує.", +"Drop this user from MySQL" => "Видалити цього користувача з MySQL", +"MySQL user '%s'@'%%' already exists" => "Користувач MySQL '%s'@'%%' вже існує", +"Drop this user from MySQL." => "Видалити цього користувача з MySQL.", +"Oracle username and/or password not valid" => "Oracle ім'я користувача та/або пароль не дійсні", +"Offending command was: \"%s\", name: %s, password: %s" => "Команда, що викликала проблему: \"%s\", ім'я: %s, пароль: %s", +"PostgreSQL username and/or password not valid" => "PostgreSQL ім'я користувача та/або пароль не дійсні", +"Set an admin username." => "Встановіть ім'я адміністратора.", +"Set an admin password." => "Встановіть пароль адміністратора.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш Web-сервер ще не налаштований належним чином для того, щоб дозволити синхронізацію файлів, через те що інтерфейс WebDAV, здається, зламаний.", +"Please double check the installation guides." => "Будь ласка, перевірте інструкції по встановленню.", +"seconds ago" => "секунди тому", +"_%n minute ago_::_%n minutes ago_" => array("","",""), +"_%n hour ago_::_%n hours ago_" => array("","",""), +"today" => "сьогодні", +"yesterday" => "вчора", +"_%n day go_::_%n days ago_" => array("","",""), +"last month" => "минулого місяця", +"_%n month ago_::_%n months ago_" => array("","",""), +"last year" => "минулого року", +"years ago" => "роки тому", +"Could not find category \"%s\"" => "Не вдалося знайти категорію \"%s\"" +); +$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/lib/private/l10n/ur_PK.php b/lib/private/l10n/ur_PK.php new file mode 100644 index 00000000000..7dc967ccd93 --- /dev/null +++ b/lib/private/l10n/ur_PK.php @@ -0,0 +1,14 @@ + "مدد", +"Personal" => "ذاتی", +"Settings" => "سیٹینگز", +"Users" => "یوزرز", +"Admin" => "ایڈمن", +"web services under your control" => "آپ کے اختیار میں ویب سروسیز", +"_%n minute ago_::_%n minutes ago_" => array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day go_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/lib/private/l10n/vi.php b/lib/private/l10n/vi.php new file mode 100644 index 00000000000..dc0045c35ca --- /dev/null +++ b/lib/private/l10n/vi.php @@ -0,0 +1,31 @@ + "Giúp đỡ", +"Personal" => "Cá nhân", +"Settings" => "Cài đặt", +"Users" => "Người dùng", +"Admin" => "Quản trị", +"web services under your control" => "dịch vụ web dưới sự kiểm soát của bạn", +"ZIP download is turned off." => "Tải về ZIP đã bị tắt.", +"Files need to be downloaded one by one." => "Tập tin cần phải được tải về từng người một.", +"Back to Files" => "Trở lại tập tin", +"Selected files too large to generate zip file." => "Tập tin được chọn quá lớn để tạo tập tin ZIP.", +"Application is not enabled" => "Ứng dụng không được BẬT", +"Authentication error" => "Lỗi xác thực", +"Token expired. Please reload page." => "Mã Token đã hết hạn. Hãy tải lại trang.", +"Files" => "Tập tin", +"Text" => "Văn bản", +"Images" => "Hình ảnh", +"seconds ago" => "vài giây trước", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "hôm nay", +"yesterday" => "hôm qua", +"_%n day go_::_%n days ago_" => array(""), +"last month" => "tháng trước", +"_%n month ago_::_%n months ago_" => array(""), +"last year" => "năm trước", +"years ago" => "năm trước", +"Could not find category \"%s\"" => "không thể tìm thấy mục \"%s\"" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/zh_CN.php b/lib/private/l10n/zh_CN.php new file mode 100644 index 00000000000..2c34356ea10 --- /dev/null +++ b/lib/private/l10n/zh_CN.php @@ -0,0 +1,52 @@ + "帮助", +"Personal" => "个人", +"Settings" => "设置", +"Users" => "用户", +"Admin" => "管理", +"web services under your control" => "您控制的web服务", +"ZIP download is turned off." => "ZIP 下载已经关闭", +"Files need to be downloaded one by one." => "需要逐一下载文件", +"Back to Files" => "回到文件", +"Selected files too large to generate zip file." => "选择的文件太大,无法生成 zip 文件。", +"App does not provide an info.xml file" => "应用未提供 info.xml 文件", +"Application is not enabled" => "应用程序未启用", +"Authentication error" => "认证出错", +"Token expired. Please reload page." => "Token 过期,请刷新页面。", +"Files" => "文件", +"Text" => "文本", +"Images" => "图片", +"%s enter the database username." => "%s 输入数据库用户名。", +"%s enter the database name." => "%s 输入数据库名称。", +"%s you may not use dots in the database name" => "%s 您不能在数据库名称中使用英文句号。", +"MS SQL username and/or password not valid: %s" => "MS SQL 用户名和/或密码无效:%s", +"You need to enter either an existing account or the administrator." => "你需要输入一个数据库中已有的账户或管理员账户。", +"MySQL username and/or password not valid" => "MySQL 数据库用户名和/或密码无效", +"DB Error: \"%s\"" => "数据库错误:\"%s\"", +"Offending command was: \"%s\"" => "冲突命令为:\"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL 用户 '%s'@'localhost' 已存在。", +"Drop this user from MySQL" => "建议从 MySQL 数据库中丢弃 Drop 此用户", +"MySQL user '%s'@'%%' already exists" => "MySQL 用户 '%s'@'%%' 已存在", +"Drop this user from MySQL." => "建议从 MySQL 数据库中丢弃 Drop 此用户。", +"Oracle connection could not be established" => "不能建立甲骨文连接", +"Oracle username and/or password not valid" => "Oracle 数据库用户名和/或密码无效", +"Offending command was: \"%s\", name: %s, password: %s" => "冲突命令为:\"%s\",名称:%s,密码:%s", +"PostgreSQL username and/or password not valid" => "PostgreSQL 数据库用户名和/或密码无效", +"Set an admin username." => "请设置一个管理员用户名。", +"Set an admin password." => "请设置一个管理员密码。", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "您的Web服务器尚未正确设置以允许文件同步, 因为WebDAV的接口似乎已损坏.", +"Please double check the installation guides." => "请认真检查安装指南.", +"seconds ago" => "秒前", +"_%n minute ago_::_%n minutes ago_" => array("%n 分钟前"), +"_%n hour ago_::_%n hours ago_" => array("%n 小时前"), +"today" => "今天", +"yesterday" => "昨天", +"_%n day go_::_%n days ago_" => array("%n 天前"), +"last month" => "上月", +"_%n month ago_::_%n months ago_" => array("%n 月前"), +"last year" => "去年", +"years ago" => "年前", +"Could not find category \"%s\"" => "无法找到分类 \"%s\"" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/zh_HK.php b/lib/private/l10n/zh_HK.php new file mode 100644 index 00000000000..ca3e6d504e7 --- /dev/null +++ b/lib/private/l10n/zh_HK.php @@ -0,0 +1,18 @@ + "幫助", +"Personal" => "個人", +"Settings" => "設定", +"Users" => "用戶", +"Admin" => "管理", +"Files" => "文件", +"Text" => "文字", +"_%n minute ago_::_%n minutes ago_" => array(""), +"_%n hour ago_::_%n hours ago_" => array(""), +"today" => "今日", +"yesterday" => "昨日", +"_%n day go_::_%n days ago_" => array(""), +"last month" => "前一月", +"_%n month ago_::_%n months ago_" => array("") +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/l10n/zh_TW.php b/lib/private/l10n/zh_TW.php new file mode 100644 index 00000000000..210c766aa59 --- /dev/null +++ b/lib/private/l10n/zh_TW.php @@ -0,0 +1,69 @@ + "無法安裝應用程式 %s 因為它和此版本的 ownCloud 不相容。", +"No app name specified" => "沒有指定應用程式名稱", +"Help" => "說明", +"Personal" => "個人", +"Settings" => "設定", +"Users" => "使用者", +"Admin" => "管理", +"Failed to upgrade \"%s\"." => "升級失敗:%s", +"web services under your control" => "由您控制的網路服務", +"cannot open \"%s\"" => "無法開啓 %s", +"ZIP download is turned off." => "ZIP 下載已關閉。", +"Files need to be downloaded one by one." => "檔案需要逐一下載。", +"Back to Files" => "回到檔案列表", +"Selected files too large to generate zip file." => "選擇的檔案太大以致於無法產生壓縮檔。", +"Download the files in smaller chunks, seperately or kindly ask your administrator." => "以小分割下載您的檔案,請詢問您的系統管理員。", +"No source specified when installing app" => "沒有指定應用程式安裝來源", +"No href specified when installing app from http" => "從 http 安裝應用程式,找不到 href 屬性", +"No path specified when installing app from local file" => "從本地檔案安裝應用程式時沒有指定路徑", +"Archives of type %s are not supported" => "不支援 %s 格式的壓縮檔", +"Failed to open archive when installing app" => "安裝應用程式時無法開啓壓縮檔", +"App does not provide an info.xml file" => "應用程式沒有提供 info.xml 檔案", +"App can't be installed because of not allowed code in the App" => "無法安裝應用程式因為在當中找到危險的代碼", +"App can't be installed because it is not compatible with this version of ownCloud" => "無法安裝應用程式因為它和此版本的 ownCloud 不相容。", +"App can't be installed because it contains the true tag which is not allowed for non shipped apps" => "無法安裝應用程式,因為它包含了 true 標籤,在未發行的應用程式當中這是不允許的", +"App can't be installed because the version in info.xml/version is not the same as the version reported from the app store" => "無法安裝應用程式,因為它在 info.xml/version 宣告的版本與 app store 當中記載的版本不同", +"App directory already exists" => "應用程式目錄已經存在", +"Can't create app folder. Please fix permissions. %s" => "無法建立應用程式目錄,請檢查權限:%s", +"Application is not enabled" => "應用程式未啟用", +"Authentication error" => "認證錯誤", +"Token expired. Please reload page." => "Token 過期,請重新整理頁面。", +"Files" => "檔案", +"Text" => "文字", +"Images" => "圖片", +"%s enter the database username." => "%s 輸入資料庫使用者名稱。", +"%s enter the database name." => "%s 輸入資料庫名稱。", +"%s you may not use dots in the database name" => "%s 資料庫名稱不能包含小數點", +"MS SQL username and/or password not valid: %s" => "MS SQL 使用者和/或密碼無效:%s", +"You need to enter either an existing account or the administrator." => "您必須輸入一個現有的帳號或管理員帳號。", +"MySQL username and/or password not valid" => "MySQL 用戶名和/或密碼無效", +"DB Error: \"%s\"" => "資料庫錯誤:\"%s\"", +"Offending command was: \"%s\"" => "有問題的指令是:\"%s\"", +"MySQL user '%s'@'localhost' exists already." => "MySQL 使用者 '%s'@'localhost' 已經存在。", +"Drop this user from MySQL" => "在 MySQL 移除這個使用者", +"MySQL user '%s'@'%%' already exists" => "MySQL 使用者 '%s'@'%%' 已經存在", +"Drop this user from MySQL." => "在 MySQL 移除這個使用者。", +"Oracle connection could not be established" => "無法建立 Oracle 資料庫連線", +"Oracle username and/or password not valid" => "Oracle 用戶名和/或密碼無效", +"Offending command was: \"%s\", name: %s, password: %s" => "有問題的指令是:\"%s\" ,使用者:\"%s\",密碼:\"%s\"", +"PostgreSQL username and/or password not valid" => "PostgreSQL 用戶名和/或密碼無效", +"Set an admin username." => "設定管理員帳號。", +"Set an admin password." => "設定管理員密碼。", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "您的網頁伺服器尚未被正確設定來進行檔案同步,因為您的 WebDAV 界面似乎無法使用。", +"Please double check the installation guides." => "請參考安裝指南。", +"seconds ago" => "幾秒前", +"_%n minute ago_::_%n minutes ago_" => array("%n 分鐘前"), +"_%n hour ago_::_%n hours ago_" => array("%n 小時前"), +"today" => "今天", +"yesterday" => "昨天", +"_%n day go_::_%n days ago_" => array("%n 天前"), +"last month" => "上個月", +"_%n month ago_::_%n months ago_" => array("%n 個月前"), +"last year" => "去年", +"years ago" => "幾年前", +"Caused by:" => "原因:", +"Could not find category \"%s\"" => "找不到分類:\"%s\"" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/lib/private/legacy/cache.php b/lib/private/legacy/cache.php new file mode 100644 index 00000000000..f915eb516b1 --- /dev/null +++ b/lib/private/legacy/cache.php @@ -0,0 +1,10 @@ +. + * + */ +/* + * + * An example of config.php + * + * "mysql", + * "firstrun" => false, + * "pi" => 3.14 + * ); + * ?> + * + */ + +/** + * This class is responsible for reading and writing config.php, the very basic + * configuration file of ownCloud. + */ +OC_Config::$object = new \OC\Config(OC::$SERVERROOT.'/config/'); +class OC_Config { + + /** + * @var \OC\Config + */ + public static $object; + + public static function getObject() { + return self::$object; + } + + /** + * @brief Lists all available config keys + * @return array with key names + * + * This function returns all keys saved in config.php. Please note that it + * does not return the values. + */ + public static function getKeys() { + return self::$object->getKeys(); + } + + /** + * @brief Gets a value from config.php + * @param string $key key + * @param string $default = null default value + * @return string the value or $default + * + * This function gets the value from config.php. If it does not exist, + * $default will be returned. + */ + public static function getValue($key, $default = null) { + return self::$object->getValue($key, $default); + } + + /** + * @brief Sets a value + * @param string $key key + * @param string $value value + * + * This function sets the value and writes the config.php. + * + */ + public static function setValue($key, $value) { + try { + self::$object->setValue($key, $value); + } catch (\OC\HintException $e) { + \OC_Template::printErrorPage($e->getMessage(), $e->getHint()); + } + } + + /** + * @brief Removes a key from the config + * @param string $key key + * + * This function removes a key from the config.php. + * + */ + public static function deleteKey($key) { + try { + self::$object->deleteKey($key); + } catch (\OC\HintException $e) { + \OC_Template::printErrorPage($e->getMessage(), $e->getHint()); + } + } +} diff --git a/lib/private/legacy/filesystem.php b/lib/private/legacy/filesystem.php new file mode 100644 index 00000000000..34f92b357ca --- /dev/null +++ b/lib/private/legacy/filesystem.php @@ -0,0 +1,415 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class for abstraction of filesystem functions + * This class won't call any filesystem functions for itself but but will pass them to the correct OC_Filestorage object + * this class should also handle all the file permission related stuff + * + * Hooks provided: + * read(path) + * write(path, &run) + * post_write(path) + * create(path, &run) (when a file is created, both create and write will be emitted in that order) + * post_create(path) + * delete(path, &run) + * post_delete(path) + * rename(oldpath,newpath, &run) + * post_rename(oldpath,newpath) + * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order) + * post_rename(oldpath,newpath) + * + * the &run parameter can be set to false to prevent the operation from occurring + */ + +/** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ +class OC_Filesystem { + /** + * get the mountpoint of the storage object for a path + * ( note: because a storage is not always mounted inside the fakeroot, the + * returned mountpoint is relative to the absolute root of the filesystem + * and doesn't take the chroot into account ) + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return string + */ + static public function getMountPoint($path) { + return \OC\Files\Filesystem::getMountPoint($path); + } + + /** + * resolve a path to a storage and internal path + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return array consisting of the storage and the internal path + */ + static public function resolvePath($path) { + return \OC\Files\Filesystem::resolvePath($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function init($user, $root) { + return \OC\Files\Filesystem::init($user, $root); + } + + /** + * get the default filesystem view + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @return \OC\Files\View + */ + static public function getView() { + return \OC\Files\Filesystem::getView(); + } + + /** + * tear down the filesystem, removing all storage providers + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function tearDown() { + \OC\Files\Filesystem::tearDown(); + } + + /** + * @brief get the relative path of the root data directory for the current user + * @return string + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * Returns path like /admin/files + */ + static public function getRoot() { + return \OC\Files\Filesystem::getRoot(); + } + + /** + * clear all mounts and storage backends + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + public static function clearMounts() { + \OC\Files\Filesystem::clearMounts(); + } + + /** + * mount an \OC\Files\Storage\Storage in our virtual filesystem + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param \OC\Files\Storage\Storage $class + * @param array $arguments + * @param string $mountpoint + */ + static public function mount($class, $arguments, $mountpoint) { + \OC\Files\Filesystem::mount($class, $arguments, $mountpoint); + } + + /** + * return the path to a local version of the file + * we need this because we can't know if a file is stored local or not from + * outside the filestorage and for some purposes a local file is needed + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return string + */ + static public function getLocalFile($path) { + return \OC\Files\Filesystem::getLocalFile($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return string + */ + static public function getLocalFolder($path) { + return \OC\Files\Filesystem::getLocalFolder($path); + } + + /** + * return path to file which reflects one visible in browser + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return string + */ + static public function getLocalPath($path) { + return \OC\Files\Filesystem::getLocalPath($path); + } + + /** + * check if the requested path is valid + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @return bool + */ + static public function isValidPath($path) { + return \OC\Files\Filesystem::isValidPath($path); + } + + /** + * checks if a file is blacklisted for storage in the filesystem + * Listens to write and rename hooks + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param array $data from hook + */ + static public function isBlacklisted($data) { + \OC\Files\Filesystem::isBlacklisted($data); + } + + /** + * following functions are equivalent to their php builtin equivalents for arguments/return values. + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function mkdir($path) { + return \OC\Files\Filesystem::mkdir($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function rmdir($path) { + return \OC\Files\Filesystem::rmdir($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function opendir($path) { + return \OC\Files\Filesystem::opendir($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function readdir($path) { + return \OC\Files\Filesystem::readdir($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function is_dir($path) { + return \OC\Files\Filesystem::is_dir($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function is_file($path) { + return \OC\Files\Filesystem::is_file($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function stat($path) { + return \OC\Files\Filesystem::stat($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function filetype($path) { + return \OC\Files\Filesystem::filetype($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function filesize($path) { + return \OC\Files\Filesystem::filesize($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function readfile($path) { + return \OC\Files\Filesystem::readfile($path); + } + + /** + * @deprecated Replaced by isReadable() as part of CRUDS + */ + static public function is_readable($path) { + return \OC\Files\Filesystem::isReadable($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function isCreatable($path) { + return \OC\Files\Filesystem::isCreatable($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function isReadable($path) { + return \OC\Files\Filesystem::isReadable($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function isUpdatable($path) { + return \OC\Files\Filesystem::isUpdatable($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function isDeletable($path) { + return \OC\Files\Filesystem::isDeletable($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function isSharable($path) { + return \OC\Files\Filesystem::isSharable($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function file_exists($path) { + return \OC\Files\Filesystem::file_exists($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function filemtime($path) { + return \OC\Files\Filesystem::filemtime($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function touch($path, $mtime = null) { + return \OC\Files\Filesystem::touch($path, $mtime); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function file_get_contents($path) { + return \OC\Files\Filesystem::file_get_contents($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function file_put_contents($path, $data) { + return \OC\Files\Filesystem::file_put_contents($path, $data); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function unlink($path) { + return \OC\Files\Filesystem::unlink($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function rename($path1, $path2) { + return \OC\Files\Filesystem::rename($path1, $path2); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function copy($path1, $path2) { + return \OC\Files\Filesystem::copy($path1, $path2); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function fopen($path, $mode) { + return \OC\Files\Filesystem::fopen($path, $mode); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function toTmpFile($path) { + return \OC\Files\Filesystem::toTmpFile($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function fromTmpFile($tmpFile, $path) { + return \OC\Files\Filesystem::fromTmpFile($tmpFile, $path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function getMimeType($path) { + return \OC\Files\Filesystem::getMimeType($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function hash($type, $path, $raw = false) { + return \OC\Files\Filesystem::hash($type, $path, $raw); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function free_space($path = '/') { + return \OC\Files\Filesystem::free_space($path); + } + + /** + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + */ + static public function search($query) { + return \OC\Files\Filesystem::search($query); + } + + /** + * check if a file or folder has been updated since $time + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @param int $time + * @return bool + */ + static public function hasUpdated($path, $time) { + return \OC\Files\Filesystem::hasUpdated($path, $time); + } + + /** + * normalize a path + * + * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem + * @param string $path + * @param bool $stripTrailingSlash + * @return string + */ + public static function normalizePath($path, $stripTrailingSlash = true) { + return \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash); + } +} diff --git a/lib/private/legacy/filesystemview.php b/lib/private/legacy/filesystemview.php new file mode 100644 index 00000000000..d6bca62e06a --- /dev/null +++ b/lib/private/legacy/filesystemview.php @@ -0,0 +1,9 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ + +class OC_FilesystemView extends \OC\Files\View {} diff --git a/lib/private/legacy/log.php b/lib/private/legacy/log.php new file mode 100644 index 00000000000..027cb89e97c --- /dev/null +++ b/lib/private/legacy/log.php @@ -0,0 +1,50 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * logging utilities + * + * Log is saved by default at data/owncloud.log using OC_Log_Owncloud. + * Selecting other backend is done with a config option 'log_type'. + */ + +OC_Log::$object = new \OC\Log(); +class OC_Log { + public static $object; + + const DEBUG=0; + const INFO=1; + const WARN=2; + const ERROR=3; + const FATAL=4; + + static private $level_funcs = array( + self::DEBUG => 'debug', + self::INFO => 'info', + self::WARN => 'warning', + self::ERROR => 'error', + self::FATAL => 'emergency', + ); + + static public $enabled = true; + static protected $class = null; + + /** + * write a message in the log + * @param string $app + * @param string $message + * @param int $level + */ + public static function write($app, $message, $level) { + if (self::$enabled) { + $context = array('app' => $app); + $func = array(self::$object, self::$level_funcs[$level]); + call_user_func($func, $message, $context); + } + } +} diff --git a/lib/private/legacy/preferences.php b/lib/private/legacy/preferences.php new file mode 100644 index 00000000000..a663db7598b --- /dev/null +++ b/lib/private/legacy/preferences.php @@ -0,0 +1,146 @@ +. + * + */ + +/** + * This class provides an easy way for storing user preferences. + */ +OC_Preferences::$object = new \OC\Preferences(OC_DB::getConnection()); +class OC_Preferences{ + public static $object; + /** + * @brief Get all users using the preferences + * @return array with user ids + * + * This function returns a list of all users that have at least one entry + * in the preferences table. + */ + public static function getUsers() { + return self::$object->getUsers(); + } + + /** + * @brief Get all apps of a user + * @param string $user user + * @return array with app ids + * + * This function returns a list of all apps of the user that have at least + * one entry in the preferences table. + */ + public static function getApps( $user ) { + return self::$object->getApps( $user ); + } + + /** + * @brief Get the available keys for an app + * @param string $user user + * @param string $app the app we are looking for + * @return array with key names + * + * This function gets all keys of an app of an user. Please note that the + * values are not returned. + */ + public static function getKeys( $user, $app ) { + return self::$object->getKeys( $user, $app ); + } + + /** + * @brief Gets the preference + * @param string $user user + * @param string $app app + * @param string $key key + * @param string $default = null, default value if the key does not exist + * @return string the value or $default + * + * This function gets a value from the preferences table. If the key does + * not exist the default value will be returned + */ + public static function getValue( $user, $app, $key, $default = null ) { + return self::$object->getValue( $user, $app, $key, $default ); + } + + /** + * @brief sets a value in the preferences + * @param string $user user + * @param string $app app + * @param string $key key + * @param string $value value + * @return bool + * + * Adds a value to the preferences. If the key did not exist before, it + * will be added automagically. + */ + public static function setValue( $user, $app, $key, $value ) { + self::$object->setValue( $user, $app, $key, $value ); + return true; + } + + /** + * @brief Deletes a key + * @param string $user user + * @param string $app app + * @param string $key key + * + * Deletes a key. + */ + public static function deleteKey( $user, $app, $key ) { + self::$object->deleteKey( $user, $app, $key ); + return true; + } + + /** + * @brief Remove app of user from preferences + * @param string $user user + * @param string $app app + * @return bool + * + * Removes all keys in preferences belonging to the app and the user. + */ + public static function deleteApp( $user, $app ) { + self::$object->deleteApp( $user, $app ); + return true; + } + + /** + * @brief Remove user from preferences + * @param string $user user + * @return bool + * + * Removes all keys in preferences belonging to the user. + */ + public static function deleteUser( $user ) { + self::$object->deleteUser( $user ); + return true; + } + + /** + * @brief Remove app from all users + * @param string $app app + * @return bool + * + * Removes all keys in preferences belonging to the app. + */ + public static function deleteAppFromAllUsers( $app ) { + self::$object->deleteAppFromAllUsers( $app ); + return true; + } +} diff --git a/lib/private/legacy/updater.php b/lib/private/legacy/updater.php new file mode 100644 index 00000000000..eea7bb129cf --- /dev/null +++ b/lib/private/legacy/updater.php @@ -0,0 +1,14 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Updater { + public static function check() { + $updater = new \OC\Updater(); + return $updater->check('http://apps.owncloud.com/updater.php'); + } +} diff --git a/lib/private/log.php b/lib/private/log.php new file mode 100644 index 00000000000..e0b9fe3c696 --- /dev/null +++ b/lib/private/log.php @@ -0,0 +1,136 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +/** + * logging utilities + * + * This is a stand in, this should be replaced by a Psr\Log\LoggerInterface + * compatible logger. See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md + * for the full interface specification. + * + * MonoLog is an example implementing this interface. + */ + +class Log { + private $logClass; + + /** + * System is unusable. + * + * @param string $message + * @param array $context + */ + public function emergency($message, array $context = array()) { + $this->log(\OC_Log::FATAL, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + */ + public function alert($message, array $context = array()) { + $this->log(\OC_Log::ERROR, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + */ + public function critical($message, array $context = array()) { + $this->log(\OC_Log::ERROR, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + */ + public function error($message, array $context = array()) { + $this->log(\OC_Log::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + */ + public function warning($message, array $context = array()) { + $this->log(\OC_Log::WARN, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + */ + public function notice($message, array $context = array()) { + $this->log(\OC_Log::INFO, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + */ + public function info($message, array $context = array()) { + $this->log(\OC_Log::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + */ + public function debug($message, array $context = array()) { + $this->log(\OC_Log::DEBUG, $message, $context); + } + + public function __construct() { + $this->logClass = 'OC_Log_'.ucfirst(\OC_Config::getValue('log_type', 'owncloud')); + call_user_func(array($this->logClass, 'init')); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + */ + public function log($level, $message, array $context = array()) { + if (isset($context['app'])) { + $app = $context['app']; + } else { + $app = 'no app in context'; + } + $logClass=$this->logClass; + $logClass::write($app, $message, $level); + } +} diff --git a/lib/private/log/errorhandler.php b/lib/private/log/errorhandler.php new file mode 100644 index 00000000000..69cb960de91 --- /dev/null +++ b/lib/private/log/errorhandler.php @@ -0,0 +1,54 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Log; + +use OC\Log as LoggerInterface; + +class ErrorHandler { + /** @var LoggerInterface */ + private static $logger; + + public static function register() { + $handler = new ErrorHandler(); + + set_error_handler(array($handler, 'onError')); + register_shutdown_function(array($handler, 'onShutdown')); + set_exception_handler(array($handler, 'onException')); + } + + public static function setLogger(LoggerInterface $logger) { + self::$logger = $logger; + } + + //Fatal errors handler + public static function onShutdown() { + $error = error_get_last(); + if($error && self::$logger) { + //ob_end_clean(); + $msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line']; + self::$logger->critical($msg, array('app' => 'PHP')); + } + } + + // Uncaught exception handler + public static function onException($exception) { + $msg = $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine(); + self::$logger->critical($msg, array('app' => 'PHP')); + } + + //Recoverable errors handler + public static function onError($number, $message, $file, $line) { + if (error_reporting() === 0) { + return; + } + $msg = $message . ' at ' . $file . '#' . $line; + self::$logger->warning($msg, array('app' => 'PHP')); + + } +} diff --git a/lib/private/log/owncloud.php b/lib/private/log/owncloud.php new file mode 100644 index 00000000000..d16b9537a16 --- /dev/null +++ b/lib/private/log/owncloud.php @@ -0,0 +1,112 @@ +. + * + */ + +/** + * logging utilities + * + * Log is saved at data/owncloud.log (on default) + */ + +class OC_Log_Owncloud { + static protected $logFile; + + /** + * Init class data + */ + public static function init() { + $defaultLogFile = OC_Config::getValue("datadirectory", OC::$SERVERROOT.'/data').'/owncloud.log'; + self::$logFile = OC_Config::getValue("logfile", $defaultLogFile); + if (!file_exists(self::$logFile)) { + self::$logFile = $defaultLogFile; + } + } + + /** + * write a message in the log + * @param string $app + * @param string $message + * @param int $level + */ + public static function write($app, $message, $level) { + $minLevel=min(OC_Config::getValue( "loglevel", OC_Log::WARN ), OC_Log::ERROR); + if($level>=$minLevel) { + // default to ISO8601 + $format = OC_Config::getValue('logdateformat', 'c'); + $time = date($format, time()); + $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=> $time); + $handle = @fopen(self::$logFile, 'a'); + if ($handle) { + fwrite($handle, json_encode($entry)."\n"); + fclose($handle); + } + } + } + + /** + * get entries from the log in reverse chronological order + * @param int $limit + * @param int $offset + * @return array + */ + public static function getEntries($limit=50, $offset=0) { + self::init(); + $minLevel=OC_Config::getValue( "loglevel", OC_Log::WARN ); + $entries = array(); + $handle = @fopen(self::$logFile, 'rb'); + if ($handle) { + fseek($handle, 0, SEEK_END); + $pos = ftell($handle); + $line = ''; + $entriesCount = 0; + $lines = 0; + // Loop through each character of the file looking for new lines + while ($pos >= 0 && $entriesCount < $limit) { + fseek($handle, $pos); + $ch = fgetc($handle); + if ($ch == "\n" || $pos == 0) { + if ($line != '') { + // Add the first character if at the start of the file, + // because it doesn't hit the else in the loop + if ($pos == 0) { + $line = $ch.$line; + } + $entry = json_decode($line); + // Add the line as an entry if it is passed the offset and is equal or above the log level + if ($entry->level >= $minLevel) { + $lines++; + if ($lines > $offset) { + $entries[] = $entry; + $entriesCount++; + } + } + $line = ''; + } + } else { + $line = $ch.$line; + } + $pos--; + } + fclose($handle); + } + return $entries; + } +} diff --git a/lib/private/log/rotate.php b/lib/private/log/rotate.php new file mode 100644 index 00000000000..bf23ad588b3 --- /dev/null +++ b/lib/private/log/rotate.php @@ -0,0 +1,35 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Log; + +/** + * This rotates the current logfile to a new name, this way the total log usage + * will stay limited and older entries are available for a while longer. + * For more professional log management set the 'logfile' config to a different + * location and manage that with your own tools. + */ +class Rotate extends \OC\BackgroundJob\Job { + private $max_log_size; + public function run($logFile) { + $this->max_log_size = \OC_Config::getValue('log_rotate_size', false); + if ($this->max_log_size) { + $filesize = @filesize($logFile); + if ($filesize >= $this->max_log_size) { + $this->rotate($logFile); + } + } + } + + protected function rotate($logfile) { + $rotatedLogfile = $logfile.'.1'; + rename($logfile, $rotatedLogfile); + $msg = 'Log file "'.$logfile.'" was over '.$this->max_log_size.' bytes, moved to "'.$rotatedLogfile.'"'; + \OC_Log::write('OC\Log\Rotate', $msg, \OC_Log::WARN); + } +} diff --git a/lib/private/log/syslog.php b/lib/private/log/syslog.php new file mode 100644 index 00000000000..c98deab7109 --- /dev/null +++ b/lib/private/log/syslog.php @@ -0,0 +1,40 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Log_Syslog { + static protected $levels = array( + OC_Log::DEBUG => LOG_DEBUG, + OC_Log::INFO => LOG_INFO, + OC_Log::WARN => LOG_WARNING, + OC_Log::ERROR => LOG_ERR, + OC_Log::FATAL => LOG_CRIT, + ); + + /** + * Init class data + */ + public static function init() { + openlog('ownCloud', LOG_PID | LOG_CONS, LOG_USER); + // Close at shutdown + register_shutdown_function('closelog'); + } + + /** + * write a message in the log + * @param string $app + * @param string $message + * @param int $level + */ + public static function write($app, $message, $level) { + $minLevel = min(OC_Config::getValue("loglevel", OC_Log::WARN), OC_Log::ERROR); + if ($level >= $minLevel) { + $syslog_level = self::$levels[$level]; + syslog($syslog_level, '{'.$app.'} '.$message); + } + } +} diff --git a/lib/private/mail.php b/lib/private/mail.php new file mode 100644 index 00000000000..b339b33e962 --- /dev/null +++ b/lib/private/mail.php @@ -0,0 +1,133 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * OC_Mail + * + * A class to handle mail sending. + */ + +require_once 'class.phpmailer.php'; + +class OC_Mail { + + /** + * send an email + * + * @param string $toaddress + * @param string $toname + * @param string $subject + * @param string $mailtext + * @param string $fromaddress + * @param string $fromname + * @param bool|int $html + * @param string $altbody + * @param string $ccaddress + * @param string $ccname + * @param string $bcc + * @throws Exception + */ + public static function send($toaddress, $toname, $subject, $mailtext, $fromaddress, $fromname, + $html=0, $altbody='', $ccaddress='', $ccname='', $bcc='') { + + $SMTPMODE = OC_Config::getValue( 'mail_smtpmode', 'sendmail' ); + $SMTPHOST = OC_Config::getValue( 'mail_smtphost', '127.0.0.1' ); + $SMTPPORT = OC_Config::getValue( 'mail_smtpport', 25 ); + $SMTPAUTH = OC_Config::getValue( 'mail_smtpauth', false ); + $SMTPAUTHTYPE = OC_Config::getValue( 'mail_smtpauthtype', 'LOGIN' ); + $SMTPUSERNAME = OC_Config::getValue( 'mail_smtpname', '' ); + $SMTPPASSWORD = OC_Config::getValue( 'mail_smtppassword', '' ); + $SMTPDEBUG = OC_Config::getValue( 'mail_smtpdebug', false ); + $SMTPTIMEOUT = OC_Config::getValue( 'mail_smtptimeout', 10 ); + $SMTPSECURE = OC_Config::getValue( 'mail_smtpsecure', '' ); + + + $mailo = new PHPMailer(true); + if($SMTPMODE=='sendmail') { + $mailo->IsSendmail(); + }elseif($SMTPMODE=='smtp') { + $mailo->IsSMTP(); + }elseif($SMTPMODE=='qmail') { + $mailo->IsQmail(); + }else{ + $mailo->IsMail(); + } + + + $mailo->Host = $SMTPHOST; + $mailo->Port = $SMTPPORT; + $mailo->SMTPAuth = $SMTPAUTH; + $mailo->SMTPDebug = $SMTPDEBUG; + $mailo->SMTPSecure = $SMTPSECURE; + $mailo->AuthType = $SMTPAUTHTYPE; + $mailo->Username = $SMTPUSERNAME; + $mailo->Password = $SMTPPASSWORD; + $mailo->Timeout = $SMTPTIMEOUT; + + $mailo->From = $fromaddress; + $mailo->FromName = $fromname;; + $mailo->Sender = $fromaddress; + $a=explode(' ', $toaddress); + try { + foreach($a as $ad) { + $mailo->AddAddress($ad, $toname); + } + + if($ccaddress<>'') $mailo->AddCC($ccaddress, $ccname); + if($bcc<>'') $mailo->AddBCC($bcc); + + $mailo->AddReplyTo($fromaddress, $fromname); + + $mailo->WordWrap = 50; + if($html==1) $mailo->IsHTML(true); else $mailo->IsHTML(false); + + $mailo->Subject = $subject; + if($altbody=='') { + $mailo->Body = $mailtext.OC_MAIL::getfooter(); + $mailo->AltBody = ''; + }else{ + $mailo->Body = $mailtext; + $mailo->AltBody = $altbody; + } + $mailo->CharSet = 'UTF-8'; + + $mailo->Send(); + unset($mailo); + OC_Log::write('mail', + 'Mail from '.$fromname.' ('.$fromaddress.')'.' to: '.$toname.'('.$toaddress.')'.' subject: '.$subject, + OC_Log::DEBUG); + } catch (Exception $exception) { + OC_Log::write('mail', $exception->getMessage(), OC_Log::ERROR); + throw($exception); + } + } + + /** + * return the footer for a mail + * + */ + public static function getfooter() { + + $defaults = new OC_Defaults(); + + $txt="\n--\n"; + $txt.=$defaults->getName() . "\n"; + $txt.=$defaults->getSlogan() . "\n"; + + return($txt); + + } + + /** + * @param string $emailAddress a given email address to be validated + * @return bool + */ + public static function ValidateAddress($emailAddress) { + return PHPMailer::ValidateAddress($emailAddress); + } +} diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php new file mode 100644 index 00000000000..575ee4427db --- /dev/null +++ b/lib/private/memcache/apc.php @@ -0,0 +1,67 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class APC extends Cache { + /** + * entries in APC gets namespaced to prevent collisions between owncloud instances and users + */ + protected function getNameSpace() { + return $this->prefix; + } + + public function get($key) { + $result = apc_fetch($this->getNamespace() . $key, $success); + if (!$success) { + return null; + } + return $result; + } + + public function set($key, $value, $ttl = 0) { + return apc_store($this->getNamespace() . $key, $value, $ttl); + } + + public function hasKey($key) { + return apc_exists($this->getNamespace() . $key); + } + + public function remove($key) { + return apc_delete($this->getNamespace() . $key); + } + + public function clear($prefix = '') { + $ns = $this->getNamespace() . $prefix; + $cache = apc_cache_info('user'); + foreach ($cache['cache_list'] as $entry) { + if (strpos($entry['info'], $ns) === 0) { + apc_delete($entry['info']); + } + } + return true; + } + + static public function isAvailable() { + if (!extension_loaded('apc')) { + return false; + } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { + return false; + } else { + return true; + } + } +} + +if (!function_exists('apc_exists')) { + function apc_exists($keys) { + $result = false; + apc_fetch($keys, $result); + return $result; + } +} diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php new file mode 100644 index 00000000000..ccc1aa6e562 --- /dev/null +++ b/lib/private/memcache/apcu.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class APCu extends APC { + public function clear($prefix = '') { + $ns = $this->getNamespace() . $prefix; + $ns = preg_quote($ns, '/'); + $iter = new \APCIterator('/^'.$ns.'/'); + return apc_delete($iter); + } + + static public function isAvailable() { + if (!extension_loaded('apcu')) { + return false; + } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { + return false; + } else { + return true; + } + } +} diff --git a/lib/private/memcache/cache.php b/lib/private/memcache/cache.php new file mode 100644 index 00000000000..0ad1cc7ec03 --- /dev/null +++ b/lib/private/memcache/cache.php @@ -0,0 +1,77 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +abstract class Cache implements \ArrayAccess { + /** + * @var string $prefix + */ + protected $prefix; + + /** + * @param string $prefix + */ + public function __construct($prefix = '') { + $this->prefix = \OC_Util::getInstanceId() . '/' . $prefix; + } + + public function getPrefix() { + return $this->prefix; + } + + /** + * @param string $key + * @return mixed + */ + abstract public function get($key); + + /** + * @param string $key + * @param mixed $value + * @param int $ttl + * @return mixed + */ + abstract public function set($key, $value, $ttl = 0); + + /** + * @param string $key + * @return mixed + */ + abstract public function hasKey($key); + + /** + * @param string $key + * @return mixed + */ + abstract public function remove($key); + + /** + * @param string $prefix + * @return mixed + */ + abstract public function clear($prefix = ''); + + //implement the ArrayAccess interface + + public function offsetExists($offset) { + return $this->hasKey($offset); + } + + public function offsetSet($offset, $value) { + $this->set($offset, $value); + } + + public function offsetGet($offset) { + return $this->get($offset); + } + + public function offsetUnset($offset) { + $this->remove($offset); + } +} diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php new file mode 100644 index 00000000000..fde7d947567 --- /dev/null +++ b/lib/private/memcache/factory.php @@ -0,0 +1,69 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class Factory { + /** + * get a cache instance, will return null if no backend is available + * + * @param string $prefix + * @return \OC\Memcache\Cache + */ + function create($prefix = '') { + if (XCache::isAvailable()) { + return new XCache($prefix); + } elseif (APCu::isAvailable()) { + return new APCu($prefix); + } elseif (APC::isAvailable()) { + return new APC($prefix); + } elseif (Memcached::isAvailable()) { + return new Memcached($prefix); + } else { + return null; + } + } + + /** + * check if there is a memcache backend available + * + * @return bool + */ + public function isAvailable() { + return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Memcached::isAvailable(); + } + + /** + * get a in-server cache instance, will return null if no backend is available + * + * @param string $prefix + * @return \OC\Memcache\Cache + */ + public static function createLowLatency($prefix = '') { + if (XCache::isAvailable()) { + return new XCache($prefix); + } elseif (APCu::isAvailable()) { + return new APCu($prefix); + } elseif (APC::isAvailable()) { + return new APC($prefix); + } else { + return null; + } + } + + /** + * check if there is a in-server backend available + * + * @return bool + */ + public static function isAvailableLowLatency() { + return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable(); + } + + +} diff --git a/lib/private/memcache/memcached.php b/lib/private/memcache/memcached.php new file mode 100644 index 00000000000..978e6c2eff1 --- /dev/null +++ b/lib/private/memcache/memcached.php @@ -0,0 +1,76 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class Memcached extends Cache { + /** + * @var \Memcached $cache + */ + private static $cache = null; + + public function __construct($prefix = '') { + parent::__construct($prefix); + if (is_null(self::$cache)) { + self::$cache = new \Memcached(); + list($host, $port) = \OC_Config::getValue('memcached_server', array('localhost', 11211)); + self::$cache->addServer($host, $port); + } + } + + /** + * entries in XCache gets namespaced to prevent collisions between owncloud instances and users + */ + protected function getNameSpace() { + return $this->prefix; + } + + public function get($key) { + $result = self::$cache->get($this->getNamespace() . $key); + if ($result === false and self::$cache->getResultCode() == \Memcached::RES_NOTFOUND) { + return null; + } else { + return $result; + } + } + + public function set($key, $value, $ttl = 0) { + if ($ttl > 0) { + return self::$cache->set($this->getNamespace() . $key, $value, $ttl); + } else { + return self::$cache->set($this->getNamespace() . $key, $value); + } + } + + public function hasKey($key) { + self::$cache->get($this->getNamespace() . $key); + return self::$cache->getResultCode() !== \Memcached::RES_NOTFOUND; + } + + public function remove($key) { + return self::$cache->delete($this->getNamespace() . $key); + } + + public function clear($prefix = '') { + $prefix = $this->getNamespace() . $prefix; + $allKeys = self::$cache->getAllKeys(); + $keys = array(); + $prefixLength = strlen($prefix); + foreach ($allKeys as $key) { + if (substr($key, 0, $prefixLength) === $prefix) { + $keys[] = $key; + } + } + self::$cache->deleteMulti($keys); + return true; + } + + static public function isAvailable() { + return extension_loaded('memcached'); + } +} diff --git a/lib/private/memcache/xcache.php b/lib/private/memcache/xcache.php new file mode 100644 index 00000000000..33de30562f9 --- /dev/null +++ b/lib/private/memcache/xcache.php @@ -0,0 +1,60 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class XCache extends Cache { + /** + * entries in XCache gets namespaced to prevent collisions between owncloud instances and users + */ + protected function getNameSpace() { + return $this->prefix; + } + + public function get($key) { + return xcache_get($this->getNamespace().$key); + } + + public function set($key, $value, $ttl=0) { + if($ttl>0) { + return xcache_set($this->getNamespace().$key, $value, $ttl); + }else{ + return xcache_set($this->getNamespace().$key, $value); + } + } + + public function hasKey($key) { + return xcache_isset($this->getNamespace().$key); + } + + public function remove($key) { + return xcache_unset($this->getNamespace().$key); + } + + public function clear($prefix='') { + xcache_unset_by_prefix($this->getNamespace().$prefix); + return true; + } + + static public function isAvailable(){ + if (!extension_loaded('xcache')) { + return false; + } elseif (\OC::$CLI) { + return false; + }else{ + return true; + } + } +} + +if(!function_exists('xcache_unset_by_prefix')) { + function xcache_unset_by_prefix($prefix) { + // Since we can't clear targetted cache, we'll clear all. :( + xcache_clear_cache(\XC_TYPE_VAR, 0); + } +} diff --git a/lib/private/migrate.php b/lib/private/migrate.php new file mode 100644 index 00000000000..0b319177400 --- /dev/null +++ b/lib/private/migrate.php @@ -0,0 +1,693 @@ +. + * + */ + + +/** + * provides an interface to migrate users and whole ownclouds + */ +class OC_Migrate{ + + + // Array of OC_Migration_Provider objects + static private $providers=array(); + // User id of the user to import/export + static private $uid=false; + // Holds the ZipArchive object + static private $zip=false; + // Stores the type of export + static private $exporttype=false; + // Array of temp files to be deleted after zip creation + static private $tmpfiles=array(); + // Holds the db object + static private $MDB2=false; + // Schema db object + static private $schema=false; + // Path to the sqlite db + static private $dbpath=false; + // Holds the path to the zip file + static private $zippath=false; + // Holds the OC_Migration_Content object + static private $content=false; + + /** + * register a new migration provider + * @param OC_Migrate_Provider $provider + */ + public static function registerProvider($provider) { + self::$providers[]=$provider; + } + + /** + * @brief finds and loads the providers + */ + static private function findProviders() { + // Find the providers + $apps = OC_App::getAllApps(); + + foreach($apps as $app) { + $path = OC_App::getAppPath($app) . '/appinfo/migrate.php'; + if( file_exists( $path ) ) { + include $path; + } + } + } + + /** + * @brief exports a user, or owncloud instance + * @param optional $uid string user id of user to export if export type is user, defaults to current + * @param ootional $type string type of export, defualts to user + * @param otional $path string path to zip output folder + * @return false on error, path to zip on success + */ + public static function export( $uid=null, $type='user', $path=null ) { + $datadir = OC_Config::getValue( 'datadirectory' ); + // Validate export type + $types = array( 'user', 'instance', 'system', 'userfiles' ); + if( !in_array( $type, $types ) ) { + OC_Log::write( 'migration', 'Invalid export type', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + self::$exporttype = $type; + // Userid? + if( self::$exporttype == 'user' ) { + // Check user exists + self::$uid = is_null($uid) ? OC_User::getUser() : $uid; + if(!OC_User::userExists(self::$uid)) { + return json_encode( array( 'success' => false) ); + } + } + // Calculate zipname + if( self::$exporttype == 'user' ) { + $zipname = 'oc_export_' . self::$uid . '_' . date("y-m-d_H-i-s") . '.zip'; + } else { + $zipname = 'oc_export_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '.zip'; + } + // Calculate path + if( self::$exporttype == 'user' ) { + self::$zippath = $datadir . '/' . self::$uid . '/' . $zipname; + } else { + if( !is_null( $path ) ) { + // Validate custom path + if( !file_exists( $path ) || !is_writeable( $path ) ) { + OC_Log::write( 'migration', 'Path supplied is invalid.', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + self::$zippath = $path . $zipname; + } else { + // Default path + self::$zippath = get_temp_dir() . '/' . $zipname; + } + } + // Create the zip object + if( !self::createZip() ) { + return json_encode( array( 'success' => false ) ); + } + // Do the export + self::findProviders(); + $exportdata = array(); + switch( self::$exporttype ) { + case 'user': + // Connect to the db + self::$dbpath = $datadir . '/' . self::$uid . '/migration.db'; + if( !self::connectDB() ) { + return json_encode( array( 'success' => false ) ); + } + self::$content = new OC_Migration_Content( self::$zip, self::$MDB2 ); + // Export the app info + $exportdata = self::exportAppData(); + // Add the data dir to the zip + self::$content->addDir(OC_User::getHome(self::$uid), true, '/' ); + break; + case 'instance': + self::$content = new OC_Migration_Content( self::$zip ); + // Creates a zip that is compatable with the import function + $dbfile = tempnam( get_temp_dir(), "owncloud_export_data_" ); + OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL'); + + // Now add in *dbname* and *dbprefix* + $dbexport = file_get_contents( $dbfile ); + $dbnamestring = "\n\n " . OC_Config::getValue( "dbname", "owncloud" ); + $dbtableprefixstring = "
\n\n " . OC_Config::getValue( "dbtableprefix", "oc_" ); + $dbexport = str_replace( $dbnamestring, "\n\n *dbname*", $dbexport ); + $dbexport = str_replace( $dbtableprefixstring, "
\n\n *dbprefix*", $dbexport ); + // Add the export to the zip + self::$content->addFromString( $dbexport, "dbexport.xml" ); + // Add user data + foreach(OC_User::getUsers() as $user) { + self::$content->addDir(OC_User::getHome($user), true, "/userdata/" ); + } + break; + case 'userfiles': + self::$content = new OC_Migration_Content( self::$zip ); + // Creates a zip with all of the users files + foreach(OC_User::getUsers() as $user) { + self::$content->addDir(OC_User::getHome($user), true, "/" ); + } + break; + case 'system': + self::$content = new OC_Migration_Content( self::$zip ); + // Creates a zip with the owncloud system files + self::$content->addDir( OC::$SERVERROOT . '/', false, '/'); + foreach (array( + ".git", + "3rdparty", + "apps", + "core", + "files", + "l10n", + "lib", + "ocs", + "search", + "settings", + "tests" + ) as $dir) { + self::$content->addDir( OC::$SERVERROOT . '/' . $dir, true, "/"); + } + break; + } + if( !$info = self::getExportInfo( $exportdata ) ) { + return json_encode( array( 'success' => false ) ); + } + // Add the export info json to the export zip + self::$content->addFromString( $info, 'export_info.json' ); + if( !self::$content->finish() ) { + return json_encode( array( 'success' => false ) ); + } + return json_encode( array( 'success' => true, 'data' => self::$zippath ) ); + } + + /** + * @brief imports a user, or owncloud instance + * @param $path string path to zip + * @param optional $type type of import (user or instance) + * @param optional $uid userid of new user + */ + public static function import( $path, $type='user', $uid=null ) { + + $datadir = OC_Config::getValue( 'datadirectory' ); + // Extract the zip + if( !$extractpath = self::extractZip( $path ) ) { + return json_encode( array( 'success' => false ) ); + } + // Get export_info.json + $scan = scandir( $extractpath ); + // Check for export_info.json + if( !in_array( 'export_info.json', $scan ) ) { + OC_Log::write( 'migration', 'Invalid import file, export_info.json not found', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + $json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) ); + if( $json->exporttype != $type ) { + OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + self::$exporttype = $type; + + $currentuser = OC_User::getUser(); + + // Have we got a user if type is user + if( self::$exporttype == 'user' ) { + self::$uid = !is_null($uid) ? $uid : $currentuser; + } + + // We need to be an admin if we are not importing our own data + if(($type == 'user' && self::$uid != $currentuser) || $type != 'user' ) { + if( !OC_User::isAdminUser($currentuser)) { + // Naughty. + OC_Log::write( 'migration', 'Import not permitted.', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + } + + // Handle export types + switch( self::$exporttype ) { + case 'user': + // Check user availability + if( !OC_User::userExists( self::$uid ) ) { + OC_Log::write( 'migration', 'User doesn\'t exist', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + + // Check if the username is valid + if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $json->exporteduser )) { + OC_Log::write( 'migration', 'Username is not valid', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + + // Copy data + $userfolder = $extractpath . $json->exporteduser; + $newuserfolder = $datadir . '/' . self::$uid; + foreach(scandir($userfolder) as $file){ + if($file !== '.' && $file !== '..' && is_dir($file)) { + $file = str_replace(array('/', '\\'), '', $file); + + // Then copy the folder over + OC_Helper::copyr($userfolder.'/'.$file, $newuserfolder.'/'.$file); + } + } + // Import user app data + if(file_exists($extractpath . $json->exporteduser . '/migration.db')) { + if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', + $json, + self::$uid ) ) { + return json_encode( array( 'success' => false ) ); + } + } + // All done! + if( !self::unlink_r( $extractpath ) ) { + OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR ); + } + return json_encode( array( 'success' => true, 'data' => $appsimported ) ); + break; + case 'instance': + /* + * EXPERIMENTAL + // Check for new data dir and dbexport before doing anything + // TODO + + // Delete current data folder. + OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO ); + if( !self::unlink_r( $datadir, false ) ) { + OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + + // Copy over data + if( !self::copy_r( $extractpath . 'userdata', $datadir ) ) { + OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + + // Import the db + if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ) { + return json_encode( array( 'success' => false ) ); + } + // Done + return json_encode( array( 'success' => true ) ); + */ + break; + } + + } + + /** + * @brief recursively deletes a directory + * @param $dir string path of dir to delete + * $param optional $deleteRootToo bool delete the root directory + * @return bool + */ + private static function unlink_r( $dir, $deleteRootToo=true ) { + if( !$dh = @opendir( $dir ) ) { + return false; + } + while (false !== ($obj = readdir($dh))) { + if($obj == '.' || $obj == '..') { + continue; + } + if (!@unlink($dir . '/' . $obj)) { + self::unlink_r($dir.'/'.$obj, true); + } + } + closedir($dh); + if ( $deleteRootToo ) { + @rmdir($dir); + } + return true; + } + + /** + * @brief tries to extract the import zip + * @param $path string path to the zip + * @return string path to extract location (with a trailing slash) or false on failure + */ + static private function extractZip( $path ) { + self::$zip = new ZipArchive; + // Validate path + if( !file_exists( $path ) ) { + OC_Log::write( 'migration', 'Zip not found', OC_Log::ERROR ); + return false; + } + if ( self::$zip->open( $path ) != true ) { + OC_Log::write( 'migration', "Failed to open zip file", OC_Log::ERROR ); + return false; + } + $to = get_temp_dir() . '/oc_import_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '/'; + if( !self::$zip->extractTo( $to ) ) { + return false; + } + self::$zip->close(); + return $to; + } + + /** + * @brief connects to a MDB2 database scheme + * @returns bool + */ + static private function connectScheme() { + // We need a mdb2 database connection + self::$MDB2->loadModule( 'Manager' ); + self::$MDB2->loadModule( 'Reverse' ); + + // Connect if this did not happen before + if( !self::$schema ) { + require_once 'MDB2/Schema.php'; + self::$schema=MDB2_Schema::factory( self::$MDB2 ); + } + + return true; + } + + /** + * @brief creates a migration.db in the users data dir with their app data in + * @return bool whether operation was successfull + */ + private static function exportAppData( ) { + + $success = true; + $return = array(); + + // Foreach provider + foreach( self::$providers as $provider ) { + // Check if the app is enabled + if( OC_App::isEnabled( $provider->getID() ) ) { + $success = true; + // Does this app use the database? + if( file_exists( OC_App::getAppPath($provider->getID()).'/appinfo/database.xml' ) ) { + // Create some app tables + $tables = self::createAppTables( $provider->getID() ); + if( is_array( $tables ) ) { + // Save the table names + foreach($tables as $table) { + $return['apps'][$provider->getID()]['tables'][] = $table; + } + } else { + // It failed to create the tables + $success = false; + } + } + + // Run the export function? + if( $success ) { + // Set the provider properties + $provider->setData( self::$uid, self::$content ); + $return['apps'][$provider->getID()]['success'] = $provider->export(); + } else { + $return['apps'][$provider->getID()]['success'] = false; + $return['apps'][$provider->getID()]['message'] = 'failed to create the app tables'; + } + + // Now add some app info the the return array + $appinfo = OC_App::getAppInfo( $provider->getID() ); + $return['apps'][$provider->getID()]['version'] = OC_App::getAppVersion($provider->getID()); + } + } + + return $return; + + } + + + /** + * @brief generates json containing export info, and merges any data supplied + * @param optional $array array of data to include in the returned json + * @return bool + */ + static private function getExportInfo( $array=array() ) { + $info = array( + 'ocversion' => OC_Util::getVersion(), + 'exporttime' => time(), + 'exportedby' => OC_User::getUser(), + 'exporttype' => self::$exporttype, + 'exporteduser' => self::$uid + ); + + if( !is_array( $array ) ) { + OC_Log::write( 'migration', 'Supplied $array was not an array in getExportInfo()', OC_Log::ERROR ); + } + // Merge in other data + $info = array_merge( $info, (array)$array ); + // Create json + $json = json_encode( $info ); + return $json; + } + + /** + * @brief connects to migration.db, or creates if not found + * @param $db optional path to migration.db, defaults to user data dir + * @return bool whether the operation was successful + */ + static private function connectDB( $path=null ) { + // Has the dbpath been set? + self::$dbpath = !is_null( $path ) ? $path : self::$dbpath; + if( !self::$dbpath ) { + OC_Log::write( 'migration', 'connectDB() was called without dbpath being set', OC_Log::ERROR ); + return false; + } + // Already connected + if(!self::$MDB2) { + require_once 'MDB2.php'; + + $datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); + + // DB type + if( class_exists( 'SQLite3' ) ) { + $dbtype = 'sqlite3'; + } else if( is_callable( 'sqlite_open' ) ) { + $dbtype = 'sqlite'; + } else { + OC_Log::write( 'migration', 'SQLite not found', OC_Log::ERROR ); + return false; + } + + // Prepare options array + $options = array( + 'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE), + 'log_line_break' => '
', + 'idxname_format' => '%s', + 'debug' => true, + 'quote_identifier' => true + ); + $dsn = array( + 'phptype' => $dbtype, + 'database' => self::$dbpath, + 'mode' => '0644' + ); + + // Try to establish connection + self::$MDB2 = MDB2::factory( $dsn, $options ); + // Die if we could not connect + if( PEAR::isError( self::$MDB2 ) ) { + die( self::$MDB2->getMessage() ); + OC_Log::write( 'migration', 'Failed to create/connect to migration.db', OC_Log::FATAL ); + OC_Log::write( 'migration', self::$MDB2->getUserInfo(), OC_Log::FATAL ); + OC_Log::write( 'migration', self::$MDB2->getMessage(), OC_Log::FATAL ); + return false; + } + // We always, really always want associative arrays + self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC); + } + return true; + + } + + /** + * @brief creates the tables in migration.db from an apps database.xml + * @param $appid string id of the app + * @return bool whether the operation was successful + */ + static private function createAppTables( $appid ) { + + if( !self::connectScheme() ) { + return false; + } + + // There is a database.xml file + $content = file_get_contents(OC_App::getAppPath($appid) . '/appinfo/database.xml' ); + + $file2 = 'static://db_scheme'; + // TODO get the relative path to migration.db from the data dir + // For now just cheat + $path = pathinfo( self::$dbpath ); + $content = str_replace( '*dbname*', self::$uid.'/migration', $content ); + $content = str_replace( '*dbprefix*', '', $content ); + + $xml = new SimpleXMLElement($content); + foreach($xml->table as $table) { + $tables[] = (string)$table->name; + } + + file_put_contents( $file2, $content ); + + // Try to create tables + $definition = self::$schema->parseDatabaseDefinitionFile( $file2 ); + + unlink( $file2 ); + + // Die in case something went wrong + if( $definition instanceof MDB2_Schema_Error ) { + OC_Log::write( 'migration', 'Failed to parse database.xml for: '.$appid, OC_Log::FATAL ); + OC_Log::write( 'migration', $definition->getMessage().': '.$definition->getUserInfo(), OC_Log::FATAL ); + return false; + } + + $definition['overwrite'] = true; + + $ret = self::$schema->createDatabase( $definition ); + + // Die in case something went wrong + if( $ret instanceof MDB2_Error ) { + OC_Log::write( 'migration', 'Failed to create tables for: '.$appid, OC_Log::FATAL ); + OC_Log::write( 'migration', $ret->getMessage().': '.$ret->getUserInfo(), OC_Log::FATAL ); + return false; + } + return $tables; + + } + + /** + * @brief tries to create the zip + * @param $path string path to zip destination + * @return bool + */ + static private function createZip() { + self::$zip = new ZipArchive; + // Check if properties are set + if( !self::$zippath ) { + OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR); + return false; + } + if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== true ) { + OC_Log::write('migration', + 'Failed to create the zip with error: '.self::$zip->getStatusString(), + OC_Log::ERROR); + return false; + } else { + return true; + } + } + + /** + * @brief returns an array of apps that support migration + * @return array + */ + static public function getApps() { + $allapps = OC_App::getAllApps(); + foreach($allapps as $app) { + $path = self::getAppPath($app) . '/lib/migrate.php'; + if( file_exists( $path ) ) { + $supportsmigration[] = $app; + } + } + return $supportsmigration; + } + + /** + * @brief imports a new user + * @param $db string path to migration.db + * @param $info object of migration info + * @param $uid optional uid to use + * @return array of apps with import statuses, or false on failure. + */ + public static function importAppData( $db, $info, $uid=null ) { + // Check if the db exists + if( file_exists( $db ) ) { + // Connect to the db + if(!self::connectDB( $db )) { + OC_Log::write('migration', 'Failed to connect to migration.db', OC_Log::ERROR); + return false; + } + } else { + OC_Log::write('migration', 'Migration.db not found at: '.$db, OC_Log::FATAL ); + return false; + } + + // Find providers + self::findProviders(); + + // Generate importinfo array + $importinfo = array( + 'olduid' => $info->exporteduser, + 'newuid' => self::$uid + ); + + foreach( self::$providers as $provider) { + // Is the app in the export? + $id = $provider->getID(); + if( isset( $info->apps->$id ) ) { + // Is the app installed + if( !OC_App::isEnabled( $id ) ) { + OC_Log::write( 'migration', + 'App: ' . $id . ' is not installed, can\'t import data.', + OC_Log::INFO ); + $appsstatus[$id] = 'notsupported'; + } else { + // Did it succeed on export? + if( $info->apps->$id->success ) { + // Give the provider the content object + if( !self::connectDB( $db ) ) { + return false; + } + $content = new OC_Migration_Content( self::$zip, self::$MDB2 ); + $provider->setData( self::$uid, $content, $info ); + // Then do the import + if( !$appsstatus[$id] = $provider->import( $info->apps->$id, $importinfo ) ) { + // Failed to import app + OC_Log::write( 'migration', + 'Failed to import app data for user: ' . self::$uid . ' for app: ' . $id, + OC_Log::ERROR ); + } + } else { + // Add to failed list + $appsstatus[$id] = false; + } + } + } + } + + return $appsstatus; + + } + + /* + * @brief creates a new user in the database + * @param $uid string user_id of the user to be created + * @param $hash string hash of the user to be created + * @return bool result of user creation + */ + public static function createUser( $uid, $hash ) { + + // Check if userid exists + if(OC_User::userExists( $uid )) { + return false; + } + + // Create the user + $query = OC_DB::prepare( "INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )" ); + $result = $query->execute( array( $uid, $hash)); + if( !$result ) { + OC_Log::write('migration', 'Failed to create the new user "'.$uid."", OC_Log::ERROR); + } + return $result ? true : false; + + } + +} diff --git a/lib/private/migration/content.php b/lib/private/migration/content.php new file mode 100644 index 00000000000..4413d722731 --- /dev/null +++ b/lib/private/migration/content.php @@ -0,0 +1,258 @@ +. + * + */ + + +/** + * provides methods to add and access data from the migration + */ +class OC_Migration_Content{ + + private $zip=false; + // Holds the MDB2 object + private $db=null; + // Holds an array of tmpfiles to delete after zip creation + private $tmpfiles=array(); + + /** + * @brief sets up the + * @param $zip ZipArchive object + * @param optional $db a MDB2 database object (required for exporttype user) + * @return bool + */ + public function __construct( $zip, $db=null ) { + + $this->zip = $zip; + $this->db = $db; + + } + + // @brief prepares the db + // @param $query the sql query to prepare + public function prepare( $query ) { + + // Only add database to tmpfiles if actually used + if( !is_null( $this->db ) ) { + // Get db path + $db = $this->db->getDatabase(); + if(!in_array($db, $this->tmpfiles)) { + $this->tmpfiles[] = $db; + } + } + + // Optimize the query + $query = $this->processQuery( $query ); + + // Optimize the query + $query = $this->db->prepare( $query ); + + // Die if we have an error (error means: bad query, not 0 results!) + if( PEAR::isError( $query ) ) { + $entry = 'DB Error: "'.$query->getMessage().'"
'; + $entry .= 'Offending command was: '.$query.'
'; + OC_Log::write( 'migration', $entry, OC_Log::FATAL ); + return false; + } else { + return $query; + } + + } + + /** + * @brief processes the db query + * @param $query the query to process + * @return string of processed query + */ + private function processQuery( $query ) { + $query = str_replace( '`', '\'', $query ); + $query = str_replace( 'NOW()', 'datetime(\'now\')', $query ); + $query = str_replace( 'now()', 'datetime(\'now\')', $query ); + // remove table prefixes + $query = str_replace( '*PREFIX*', '', $query ); + return $query; + } + + /** + * @brief copys rows to migration.db from the main database + * @param $options array of options. + * @return bool + */ + public function copyRows( $options ) { + if( !array_key_exists( 'table', $options ) ) { + return false; + } + + $return = array(); + + // Need to include 'where' in the query? + if( array_key_exists( 'matchval', $options ) && array_key_exists( 'matchcol', $options ) ) { + + // If only one matchval, create an array + if(!is_array($options['matchval'])) { + $options['matchval'] = array( $options['matchval'] ); + } + + foreach( $options['matchval'] as $matchval ) { + // Run the query for this match value (where x = y value) + $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '` WHERE `' . $options['matchcol'] . '` = ?'; + $query = OC_DB::prepare( $sql ); + $results = $query->execute( array( $matchval ) ); + $newreturns = $this->insertData( $results, $options ); + $return = array_merge( $return, $newreturns ); + } + + } else { + // Just get everything + $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '`'; + $query = OC_DB::prepare( $sql ); + $results = $query->execute(); + $return = $this->insertData( $results, $options ); + + } + + return $return; + + } + + /** + * @brief saves a sql data set into migration.db + * @param $data a sql data set returned from self::prepare()->query() + * @param $options array of copyRows options + * @return void + */ + private function insertData( $data, $options ) { + $return = array(); + // Foreach row of data to insert + while( $row = $data->fetchRow() ) { + // Now save all this to the migration.db + foreach($row as $field=>$value) { + $fields[] = $field; + $values[] = $value; + } + + // Generate some sql + $sql = "INSERT INTO `" . $options['table'] . '` ( `'; + $fieldssql = implode( '`, `', $fields ); + $sql .= $fieldssql . "` ) VALUES( "; + $valuessql = substr( str_repeat( '?, ', count( $fields ) ), 0, -2 ); + $sql .= $valuessql . " )"; + // Make the query + $query = $this->prepare( $sql ); + if( !$query ) { + OC_Log::write( 'migration', 'Invalid sql produced: '.$sql, OC_Log::FATAL ); + return false; + exit(); + } else { + $query->execute( $values ); + // Do we need to return some values? + if( array_key_exists( 'idcol', $options ) ) { + // Yes we do + $return[] = $row[$options['idcol']]; + } else { + // Take a guess and return the first field :) + $return[] = reset($row); + } + } + $fields = ''; + $values = ''; + } + return $return; + } + + /** + * @brief adds a directory to the zip object + * @param $dir string path of the directory to add + * @param $recursive bool + * @param $internaldir string path of folder to add dir to in zip + * @return bool + */ + public function addDir( $dir, $recursive=true, $internaldir='' ) { + $dirname = basename($dir); + $this->zip->addEmptyDir($internaldir . $dirname); + $internaldir.=$dirname.='/'; + if( !file_exists( $dir ) ) { + return false; + } + $dirhandle = opendir($dir); + if(is_resource($dirhandle)) { + while (false !== ( $file = readdir($dirhandle))) { + + if (( $file != '.' ) && ( $file != '..' )) { + + if (is_dir($dir . '/' . $file) && $recursive) { + $this->addDir($dir . '/' . $file, $recursive, $internaldir); + } elseif (is_file($dir . '/' . $file)) { + $this->zip->addFile($dir . '/' . $file, $internaldir . $file); + } + } + } + closedir($dirhandle); + } else { + OC_Log::write('admin_export', "Was not able to open directory: " . $dir, OC_Log::ERROR); + return false; + } + return true; + } + + /** + * @brief adds a file to the zip from a given string + * @param $data string of data to add + * @param $path the relative path inside of the zip to save the file to + * @return bool + */ + public function addFromString( $data, $path ) { + // Create a temp file + $file = tempnam( get_temp_dir(). '/', 'oc_export_tmp_' ); + $this->tmpfiles[] = $file; + if( !file_put_contents( $file, $data ) ) { + OC_Log::write( 'migation', 'Failed to save data to a temporary file', OC_Log::ERROR ); + return false; + } + // Add file to the zip + $this->zip->addFile( $file, $path ); + return true; + } + + /** + * @brief closes the zip, removes temp files + * @return bool + */ + public function finish() { + if( !$this->zip->close() ) { + OC_Log::write( 'migration', + 'Failed to write the zip file with error: '.$this->zip->getStatusString(), + OC_Log::ERROR ); + return false; + } + $this->cleanup(); + return true; + } + + /** + * @brief cleans up after the zip + */ + private function cleanup() { + // Delete tmp files + foreach($this->tmpfiles as $i) { + unlink( $i ); + } + } +} diff --git a/lib/private/migration/provider.php b/lib/private/migration/provider.php new file mode 100644 index 00000000000..234ab3351f3 --- /dev/null +++ b/lib/private/migration/provider.php @@ -0,0 +1,52 @@ +id = $appid; + OC_Migrate::registerProvider( $this ); + } + + /** + * @brief exports data for apps + * @return array appdata to be exported + */ + abstract function export( ); + + /** + * @brief imports data for the app + * @return void + */ + abstract function import( ); + + /** + * @brief sets the OC_Migration_Content object to $this->content + * @param $content a OC_Migration_Content object + */ + public function setData( $uid, $content, $info=null ) { + $this->content = $content; + $this->uid = $uid; + $id = $this->id; + if( !is_null( $info ) ) { + $this->olduid = $info->exporteduser; + $this->appinfo = $info->apps->$id; + } + } + + /** + * @brief returns the appid of the provider + * @return string + */ + public function getID() { + return $this->id; + } +} diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php new file mode 100644 index 00000000000..8ab8ac81bd8 --- /dev/null +++ b/lib/private/mimetypes.list.php @@ -0,0 +1,107 @@ +. +* +*/ + +/** + * list of mimetypes by extension + */ + +return array( + 'css'=>'text/css', + 'flac'=>'audio/flac', + 'gif'=>'image/gif', + 'gzip'=>'application/x-gzip', + 'gz'=>'application/x-gzip', + 'html'=>'text/html', + 'htm'=>'text/html', + 'ics'=>'text/calendar', + 'ical'=>'text/calendar', + 'jpeg'=>'image/jpeg', + 'jpg'=>'image/jpeg', + 'js'=>'application/javascript', + 'oga'=>'audio/ogg', + 'ogg'=>'audio/ogg', + 'ogv'=>'video/ogg', + 'pdf'=>'application/pdf', + 'png'=>'image/png', + 'svg'=>'image/svg+xml', + 'tar'=>'application/x-tar', + 'tgz'=>'application/x-compressed', + 'tar.gz'=>'application/x-compressed', + 'tif'=>'image/tiff', + 'tiff'=>'image/tiff', + 'txt'=>'text/plain', + 'zip'=>'application/zip', + 'wav'=>'audio/wav', + 'odt'=>'application/vnd.oasis.opendocument.text', + 'ods'=>'application/vnd.oasis.opendocument.spreadsheet', + 'odg'=>'application/vnd.oasis.opendocument.graphics', + 'odp'=>'application/vnd.oasis.opendocument.presentation', + 'pages'=>'application/x-iwork-pages-sffpages', + 'numbers'=>'application/x-iwork-numbers-sffnumbers', + 'keynote'=>'application/x-iwork-keynote-sffkey', + 'kra'=>'application/x-krita', + 'mp3'=>'audio/mpeg', + 'doc'=>'application/msword', + 'docx'=>'application/msword', + 'xls'=>'application/msexcel', + 'xlsx'=>'application/msexcel', + 'php'=>'application/x-php', + 'exe'=>'application/x-ms-dos-executable', + 'pl'=>'application/x-pearl', + 'py'=>'application/x-python', + 'blend'=>'application/x-blender', + 'xcf'=>'application/x-gimp', + 'psd'=>'application/x-photoshop', + 'xml'=>'application/xml', + 'avi'=>'video/x-msvideo', + 'dv'=>'video/dv', + 'm2t'=>'video/mp2t', + 'mp4'=>'video/mp4', + 'm4v'=>'video/mp4', + 'mpg'=>'video/mpeg', + 'mpeg'=>'video/mpeg', + 'mov'=>'video/quicktime', + 'webm'=>'video/webm', + 'wmv'=>'video/x-ms-asf', + 'py'=>'text/x-script.phyton', + 'vcf' => 'text/vcard', + 'vcard' => 'text/vcard', + 'doc'=>'application/msword', + 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'xls'=>'application/msexcel', + 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'ppt'=>'application/mspowerpoint', + 'pptx'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'sgf' => 'application/sgf', + 'cdr' => 'application/coreldraw', + 'impress' => 'text/impress', + 'ai' => 'application/illustrator', + 'epub' => 'application/epub+zip', + 'mobi' => 'application/x-mobipocket-ebook', + 'exe' => 'application', + 'msi' => 'application', + 'md' => 'text/markdown', + 'markdown' => 'text/markdown', + 'mdown' => 'text/markdown', + 'mdwn' => 'text/markdown', + 'reveal' => 'text/reveal' +); diff --git a/lib/private/minimizer.php b/lib/private/minimizer.php new file mode 100644 index 00000000000..db522de74dc --- /dev/null +++ b/lib/private/minimizer.php @@ -0,0 +1,64 @@ +contentType); + OC_Response::enableCaching(); + $etag = $this->generateETag($files); + $cache_key .= '-'.$etag; + + $gzout = false; + $cache = OC_Cache::getGlobalCache(); + if (!OC_Request::isNoCache() && (!defined('DEBUG') || !DEBUG)) { + OC_Response::setETagHeader($etag); + $gzout = $cache->get($cache_key.'.gz'); + } + + if (!$gzout) { + $out = $this->minimizeFiles($files); + $gzout = gzencode($out); + $cache->set($cache_key.'.gz', $gzout); + OC_Response::setETagHeader($etag); + } + // on some systems (e.g. SLES 11, but not Ubuntu) mod_deflate and zlib compression will compress the output twice. + // This results in broken core.css and core.js. To avoid it, we switch off zlib compression. + // Since mod_deflate is still active, Apache will compress what needs to be compressed, i.e. no disadvantage. + if(function_exists('apache_get_modules') && ini_get('zlib.output_compression') && in_array('mod_deflate', apache_get_modules())) { + ini_set('zlib.output_compression', 'Off'); + } + if ($encoding = OC_Request::acceptGZip()) { + header('Content-Encoding: '.$encoding); + $out = $gzout; + } else { + $out = gzdecode($gzout); + } + header('Content-Length: '.strlen($out)); + echo $out; + } + + public function clearCache() { + $cache = OC_Cache::getGlobalCache(); + $cache->clear('core.css'); + $cache->clear('core.js'); + } +} + +if (!function_exists('gzdecode')) { + function gzdecode($data, $maxlength=null, &$filename='', &$error='') + { + if (strcmp(substr($data, 0, 9),"\x1f\x8b\x8\0\0\0\0\0\0")) { + return null; // Not the GZIP format we expect (See RFC 1952) + } + return gzinflate(substr($data, 10, -8)); + } +} diff --git a/lib/private/minimizer/css.php b/lib/private/minimizer/css.php new file mode 100644 index 00000000000..8d130572e2b --- /dev/null +++ b/lib/private/minimizer/css.php @@ -0,0 +1,38 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * + */ + +namespace OC; + +/** + * Manages the ownCloud navigation + */ +class NavigationManager implements \OCP\INavigationManager { + protected $entries = array(); + protected $activeEntry; + + /** + * Creates a new navigation entry + * @param array $entry containing: id, name, order, icon and href key + */ + public function add(array $entry) { + $entry['active'] = false; + if(!isset($entry['icon'])) { + $entry['icon'] = ''; + } + $this->entries[] = $entry; + } + + /** + * @brief returns all the added Menu entries + * @return array of the added entries + */ + public function getAll() { + return $this->entries; + } + + /** + * @brief removes all the entries + */ + public function clear() { + $this->entries = array(); + } + + /** + * Sets the current navigation entry of the currently running app + * @param string $id of the app entry to activate (from added $entry) + */ + public function setActiveEntry($id) { + $this->activeEntry = $id; + } + + /** + * @brief gets the active Menu entry + * @return string id or empty string + * + * This function returns the id of the active navigation entry (set by + * setActiveEntry + */ + public function getActiveEntry() { + return $this->activeEntry; + } +} diff --git a/lib/private/notsquareexception.php b/lib/private/notsquareexception.php new file mode 100644 index 00000000000..03dba8fb25f --- /dev/null +++ b/lib/private/notsquareexception.php @@ -0,0 +1,12 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +class NotSquareException extends \Exception { +} diff --git a/lib/private/ocs.php b/lib/private/ocs.php new file mode 100644 index 00000000000..93e8931ce2e --- /dev/null +++ b/lib/private/ocs.php @@ -0,0 +1,263 @@ +. +* +*/ + +use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Routing\Exception\MethodNotAllowedException; + +/** + * Class to handle open collaboration services API requests + * + */ +class OC_OCS { + + /** + * reads input date from get/post/cookies and converts the date to a special data-type + * + * @param string HTTP method to read the key from + * @param string Parameter to read + * @param string Variable type to format data + * @param mixed Default value to return if the key is not found + * @return mixed Data or if the key is not found and no default is set it will exit with a 400 Bad request + */ + public static function readData($method, $key, $type = 'raw', $default = null) { + if ($method == 'get') { + if (isset($_GET[$key])) { + $data = $_GET[$key]; + } else if (isset($default)) { + return $default; + } else { + $data = false; + } + } else if ($method == 'post') { + if (isset($_POST[$key])) { + $data = $_POST[$key]; + } else if (isset($default)) { + return $default; + } else { + $data = false; + } + } + if ($data === false) { + echo self::generateXml('', 'fail', 400, 'Bad request. Please provide a valid '.$key); + exit(); + } else { + // NOTE: Is the raw type necessary? It might be a little risky without sanitization + if ($type == 'raw') return $data; + elseif ($type == 'text') return OC_Util::sanitizeHTML($data); + elseif ($type == 'int') return (int) $data; + elseif ($type == 'float') return (float) $data; + elseif ($type == 'array') return OC_Util::sanitizeHTML($data); + else return OC_Util::sanitizeHTML($data); + } + } + + public static function notFound() { + if($_SERVER['REQUEST_METHOD'] == 'GET') { + $method='get'; + }elseif($_SERVER['REQUEST_METHOD'] == 'PUT') { + $method='put'; + parse_str(file_get_contents("php://input"), $put_vars); + }elseif($_SERVER['REQUEST_METHOD'] == 'POST') { + $method='post'; + }else{ + echo('internal server error: method not supported'); + exit(); + } + + $format = self::readData($method, 'format', 'text', ''); + $txt='Invalid query, please check the syntax. API specifications are here:' + .' http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n"; + $txt.=OC_OCS::getDebugOutput(); + echo(OC_OCS::generateXml($format, 'failed', 999, $txt)); + + } + + /** + * generated some debug information to make it easier to find faild API calls + * @return debug data string + */ + private static function getDebugOutput() { + $txt=''; + $txt.="debug output:\n"; + if(isset($_SERVER['REQUEST_METHOD'])) $txt.='http request method: '.$_SERVER['REQUEST_METHOD']."\n"; + if(isset($_SERVER['REQUEST_URI'])) $txt.='http request uri: '.$_SERVER['REQUEST_URI']."\n"; + if(isset($_GET)) foreach($_GET as $key=>$value) $txt.='get parameter: '.$key.'->'.$value."\n"; + if(isset($_POST)) foreach($_POST as $key=>$value) $txt.='post parameter: '.$key.'->'.$value."\n"; + return($txt); + } + + + /** + * generates the xml or json response for the API call from an multidimenional data array. + * @param string $format + * @param string $status + * @param string $statuscode + * @param string $message + * @param array $data + * @param string $tag + * @param string $tagattribute + * @param int $dimension + * @param int $itemscount + * @param int $itemsperpage + * @return string xml/json + */ + private static function generateXml($format, $status, $statuscode, + $message, $data=array(), $tag='', $tagattribute='', $dimension=-1, $itemscount='', $itemsperpage='') { + if($format=='json') { + $json=array(); + $json['status']=$status; + $json['statuscode']=$statuscode; + $json['message']=$message; + $json['totalitems']=$itemscount; + $json['itemsperpage']=$itemsperpage; + $json['data']=$data; + return(json_encode($json)); + }else{ + $txt=''; + $writer = xmlwriter_open_memory(); + xmlwriter_set_indent( $writer, 2 ); + xmlwriter_start_document($writer ); + xmlwriter_start_element($writer, 'ocs'); + xmlwriter_start_element($writer, 'meta'); + xmlwriter_write_element($writer, 'status', $status); + xmlwriter_write_element($writer, 'statuscode', $statuscode); + xmlwriter_write_element($writer, 'message', $message); + if($itemscount<>'') xmlwriter_write_element($writer, 'totalitems', $itemscount); + if(!empty($itemsperpage)) xmlwriter_write_element($writer, 'itemsperpage', $itemsperpage); + xmlwriter_end_element($writer); + if($dimension=='0') { + // 0 dimensions + xmlwriter_write_element($writer, 'data', $data); + + }elseif($dimension=='1') { + xmlwriter_start_element($writer, 'data'); + foreach($data as $key=>$entry) { + xmlwriter_write_element($writer, $key, $entry); + } + xmlwriter_end_element($writer); + + }elseif($dimension=='2') { + xmlwriter_start_element($writer, 'data'); + foreach($data as $entry) { + xmlwriter_start_element($writer, $tag); + if(!empty($tagattribute)) { + xmlwriter_write_attribute($writer, 'details', $tagattribute); + } + foreach($entry as $key=>$value) { + if(is_array($value)) { + foreach($value as $k=>$v) { + xmlwriter_write_element($writer, $k, $v); + } + } else { + xmlwriter_write_element($writer, $key, $value); + } + } + xmlwriter_end_element($writer); + } + xmlwriter_end_element($writer); + + }elseif($dimension=='3') { + xmlwriter_start_element($writer, 'data'); + foreach($data as $entrykey=>$entry) { + xmlwriter_start_element($writer, $tag); + if(!empty($tagattribute)) { + xmlwriter_write_attribute($writer, 'details', $tagattribute); + } + foreach($entry as $key=>$value) { + if(is_array($value)) { + xmlwriter_start_element($writer, $entrykey); + foreach($value as $k=>$v) { + xmlwriter_write_element($writer, $k, $v); + } + xmlwriter_end_element($writer); + } else { + xmlwriter_write_element($writer, $key, $value); + } + } + xmlwriter_end_element($writer); + } + xmlwriter_end_element($writer); + }elseif($dimension=='dynamic') { + xmlwriter_start_element($writer, 'data'); + OC_OCS::toxml($writer, $data, 'comment'); + xmlwriter_end_element($writer); + } + + xmlwriter_end_element($writer); + + xmlwriter_end_document( $writer ); + $txt.=xmlwriter_output_memory( $writer ); + unset($writer); + return($txt); + } + } + + public static function toXml($writer, $data, $node) { + foreach($data as $key => $value) { + if (is_numeric($key)) { + $key = $node; + } + if (is_array($value)) { + xmlwriter_start_element($writer, $key); + OC_OCS::toxml($writer, $value, $node); + xmlwriter_end_element($writer); + }else{ + xmlwriter_write_element($writer, $key, $value); + } + } + } + + /** + * get private data + * @param string $user + * @param string $app + * @param string $key + * @param bool $like use LIKE instead of = when comparing keys + * @return array + */ + public static function getData($user, $app="", $key="") { + if($app) { + $apps=array($app); + }else{ + $apps=OC_Preferences::getApps($user); + } + if($key) { + $keys=array($key); + }else{ + foreach($apps as $app) { + $keys=OC_Preferences::getKeys($user, $app); + } + } + $result=array(); + foreach($apps as $app) { + foreach($keys as $key) { + $value=OC_Preferences::getValue($user, $app, $key); + $result[]=array('app'=>$app, 'key'=>$key, 'value'=>$value); + } + } + return $result; + } + +} diff --git a/lib/private/ocs/cloud.php b/lib/private/ocs/cloud.php new file mode 100644 index 00000000000..2dd99319057 --- /dev/null +++ b/lib/private/ocs/cloud.php @@ -0,0 +1,108 @@ +. +* +*/ + +class OC_OCS_Cloud { + + public static function getCapabilities($parameters) { + $result = array(); + list($major, $minor, $micro) = OC_Util::getVersion(); + $result['version'] = array( + 'major' => $major, + 'minor' => $minor, + 'micro' => $micro, + 'string' => OC_Util::getVersionString(), + 'edition' => OC_Util::getEditionString(), + ); + + $result['capabilities'] = array( + 'core' => array( + 'pollinterval' => OC_Config::getValue('pollinterval', 60), + ), + ); + + return new OC_OCS_Result($result); + } + + /** + * gets user info + * + * exposes the quota of an user: + * + * + * 1234 + * 4321 + * 5555 + * 0.78 + * + * + * + * @param $parameters object should contain parameter 'userid' which identifies + * the user from whom the information will be returned + */ + public static function getUser($parameters) { + // Check if they are viewing information on themselves + if($parameters['userid'] === OC_User::getUser()) { + // Self lookup + $quota = array(); + $storage = OC_Helper::getStorageInfo(); + $quota = array( + 'free' => $storage['free'], + 'used' => $storage['used'], + 'total' => $storage['total'], + 'relative' => $storage['relative'], + ); + return new OC_OCS_Result(array('quota' => $quota)); + } else { + // No permission to view this user data + return new OC_OCS_Result(null, 997); + } + } + + public static function getUserPublickey($parameters) { + + if(OC_User::userExists($parameters['user'])) { + // calculate the disc space + // TODO + return new OC_OCS_Result(array()); + } else { + return new OC_OCS_Result(null, 300); + } + } + + public static function getUserPrivatekey($parameters) { + $user = OC_User::getUser(); + if(OC_User::isAdminUser($user) or ($user==$parameters['user'])) { + + if(OC_User::userExists($user)) { + // calculate the disc space + $txt = 'this is the private key of '.$parameters['user']; + echo($txt); + } else { + return new OC_OCS_Result(null, 300, 'User does not exist'); + } + } else { + return new OC_OCS_Result('null', 300, 'You don´t have permission to access this ressource.'); + } + } +} diff --git a/lib/private/ocs/config.php b/lib/private/ocs/config.php new file mode 100644 index 00000000000..f19121f4b2b --- /dev/null +++ b/lib/private/ocs/config.php @@ -0,0 +1,36 @@ +. +* +*/ + +class OC_OCS_Config { + + public static function apiConfig($parameters) { + $xml['version'] = '1.7'; + $xml['website'] = 'ownCloud'; + $xml['host'] = OCP\Util::getServerHost(); + $xml['contact'] = ''; + $xml['ssl'] = 'false'; + return new OC_OCS_Result($xml); + } + +} diff --git a/lib/private/ocs/person.php b/lib/private/ocs/person.php new file mode 100644 index 00000000000..1c8210d0825 --- /dev/null +++ b/lib/private/ocs/person.php @@ -0,0 +1,42 @@ +. +* +*/ + +class OC_OCS_Person { + + public static function check($parameters) { + $login = isset($_POST['login']) ? $_POST['login'] : false; + $password = isset($_POST['password']) ? $_POST['password'] : false; + if($login && $password) { + if(OC_User::checkPassword($login, $password)) { + $xml['person']['personid'] = $login; + return new OC_OCS_Result($xml); + } else { + return new OC_OCS_Result(null, 102); + } + } else { + return new OC_OCS_Result(null, 101); + } + } + +} diff --git a/lib/private/ocs/privatedata.php b/lib/private/ocs/privatedata.php new file mode 100644 index 00000000000..4dfd0a6e66e --- /dev/null +++ b/lib/private/ocs/privatedata.php @@ -0,0 +1,66 @@ +. +* +*/ + +class OC_OCS_Privatedata { + + public static function get($parameters) { + OC_Util::checkLoggedIn(); + $user = OC_User::getUser(); + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + $result = OC_OCS::getData($user, $app, $key); + $xml = array(); + foreach($result as $i=>$log) { + $xml[$i]['key']=$log['key']; + $xml[$i]['app']=$log['app']; + $xml[$i]['value']=$log['value']; + } + return new OC_OCS_Result($xml); + //TODO: replace 'privatedata' with 'attribute' once a new libattice has been released that works with it + } + + public static function set($parameters) { + OC_Util::checkLoggedIn(); + $user = OC_User::getUser(); + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + $value = OC_OCS::readData('post', 'value', 'text'); + if(OC_Preferences::setValue($user, $app, $key, $value)) { + return new OC_OCS_Result(null, 100); + } + } + + public static function delete($parameters) { + OC_Util::checkLoggedIn(); + $user = OC_User::getUser(); + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + if($key==="" or $app==="") { + return new OC_OCS_Result(null, 101); //key and app are NOT optional here + } + if(OC_Preferences::deleteKey($user, $app, $key)) { + return new OC_OCS_Result(null, 100); + } + } +} diff --git a/lib/private/ocs/result.php b/lib/private/ocs/result.php new file mode 100644 index 00000000000..84f06fa01c7 --- /dev/null +++ b/lib/private/ocs/result.php @@ -0,0 +1,97 @@ +. +* +*/ + +class OC_OCS_Result{ + + protected $data, $message, $statusCode, $items, $perPage; + + /** + * create the OCS_Result object + * @param $data mixed the data to return + */ + public function __construct($data=null, $code=100, $message=null) { + $this->data = $data; + $this->statusCode = $code; + $this->message = $message; + } + + /** + * optionally set the total number of items available + * @param $items int + */ + public function setTotalItems(int $items) { + $this->items = $items; + } + + /** + * optionally set the the number of items per page + * @param $items int + */ + public function setItemsPerPage(int $items) { + $this->perPage = $items; + } + + /** + * get the status code + * @return int + */ + public function getStatusCode() { + return $this->statusCode; + } + + /** + * get the meta data for the result + * @return array + */ + public function getMeta() { + $meta = array(); + $meta['status'] = ($this->statusCode === 100) ? 'ok' : 'failure'; + $meta['statuscode'] = $this->statusCode; + $meta['message'] = $this->message; + if(isset($this->items)) { + $meta['totalitems'] = $this->items; + } + if(isset($this->perPage)) { + $meta['itemsperpage'] = $this->perPage; + } + return $meta; + + } + + /** + * get the result data + * @return array|string|int + */ + public function getData() { + return $this->data; + } + + /** + * return bool if the method succedded + * @return bool + */ + public function succeeded() { + return (substr($this->statusCode, 0, 1) === '1'); + } + + +} diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php new file mode 100644 index 00000000000..58636f806be --- /dev/null +++ b/lib/private/ocsclient.php @@ -0,0 +1,208 @@ +. + * + */ + +/** + * This class provides an easy way for apps to store config values in the + * database. + */ + +class OC_OCSClient{ + + /** + * @brief Get the url of the OCS AppStore server. + * @returns string of the AppStore server + * + * This function returns the url of the OCS AppStore server. It´s possible + * to set it in the config file or it will fallback to the default + */ + private static function getAppStoreURL() { + $url = OC_Config::getValue('appstoreurl', 'http://api.apps.owncloud.com/v1'); + return($url); + } + + + /** + * @brief Get the content of an OCS url call. + * @returns string of the response + * This function calls an OCS server and returns the response. It also sets a sane timeout + */ + private static function getOCSresponse($url) { + $data = \OC_Util::getUrlContent($url); + return($data); + } + + /** + * @brief Get all the categories from the OCS server + * @returns array with category ids + * @note returns NULL if config value appstoreenabled is set to false + * This function returns a list of all the application categories on the OCS server + */ + public static function getCategories() { + if(OC_Config::getValue('appstoreenabled', true)==false) { + return null; + } + $url=OC_OCSClient::getAppStoreURL().'/content/categories'; + $xml=OC_OCSClient::getOCSresponse($url); + if($xml==false) { + return null; + } + $data=simplexml_load_string($xml); + + $tmp=$data->data; + $cats=array(); + + foreach($tmp->category as $value) { + + $id= (int) $value->id; + $name= (string) $value->name; + $cats[$id]=$name; + + } + + return $cats; + } + + /** + * @brief Get all the applications from the OCS server + * @returns array with application data + * + * This function returns a list of all the applications on the OCS server + */ + public static function getApplications($categories, $page, $filter) { + if(OC_Config::getValue('appstoreenabled', true)==false) { + return(array()); + } + + if(is_array($categories)) { + $categoriesstring=implode('x', $categories); + }else{ + $categoriesstring=$categories; + } + + $version='&version='.implode('x', \OC_Util::getVersion()); + $filterurl='&filter='.urlencode($filter); + $url=OC_OCSClient::getAppStoreURL().'/content/data?categories='.urlencode($categoriesstring) + .'&sortmode=new&page='.urlencode($page).'&pagesize=100'.$filterurl.$version; + $apps=array(); + $xml=OC_OCSClient::getOCSresponse($url); + + if($xml==false) { + return null; + } + $data=simplexml_load_string($xml); + + $tmp=$data->data->content; + for($i = 0; $i < count($tmp); $i++) { + $app=array(); + $app['id']=(string)$tmp[$i]->id; + $app['name']=(string)$tmp[$i]->name; + $app['label']=(string)$tmp[$i]->label; + $app['version']=(string)$tmp[$i]->version; + $app['type']=(string)$tmp[$i]->typeid; + $app['typename']=(string)$tmp[$i]->typename; + $app['personid']=(string)$tmp[$i]->personid; + $app['license']=(string)$tmp[$i]->license; + $app['detailpage']=(string)$tmp[$i]->detailpage; + $app['preview']=(string)$tmp[$i]->smallpreviewpic1; + $app['changed']=strtotime($tmp[$i]->changed); + $app['description']=(string)$tmp[$i]->description; + $app['score']=(string)$tmp[$i]->score; + + $apps[]=$app; + } + return $apps; + } + + + /** + * @brief Get an the applications from the OCS server + * @returns array with application data + * + * This function returns an applications from the OCS server + */ + public static function getApplication($id) { + if(OC_Config::getValue('appstoreenabled', true)==false) { + return null; + } + $url=OC_OCSClient::getAppStoreURL().'/content/data/'.urlencode($id); + $xml=OC_OCSClient::getOCSresponse($url); + + if($xml==false) { + OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); + return null; + } + $data=simplexml_load_string($xml); + + $tmp=$data->data->content; + $app=array(); + $app['id']=$tmp->id; + $app['name']=$tmp->name; + $app['version']=$tmp->version; + $app['type']=$tmp->typeid; + $app['label']=$tmp->label; + $app['typename']=$tmp->typename; + $app['personid']=$tmp->personid; + $app['detailpage']=$tmp->detailpage; + $app['preview1']=$tmp->smallpreviewpic1; + $app['preview2']=$tmp->smallpreviewpic2; + $app['preview3']=$tmp->smallpreviewpic3; + $app['changed']=strtotime($tmp->changed); + $app['description']=$tmp->description; + $app['detailpage']=$tmp->detailpage; + $app['score']=$tmp->score; + + return $app; + } + + /** + * @brief Get the download url for an application from the OCS server + * @returns array with application data + * + * This function returns an download url for an applications from the OCS server + */ + public static function getApplicationDownload($id, $item) { + if(OC_Config::getValue('appstoreenabled', true)==false) { + return null; + } + $url=OC_OCSClient::getAppStoreURL().'/content/download/'.urlencode($id).'/'.urlencode($item); + $xml=OC_OCSClient::getOCSresponse($url); + + if($xml==false) { + OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); + return null; + } + $data=simplexml_load_string($xml); + + $tmp=$data->data->content; + $app=array(); + if(isset($tmp->downloadlink)) { + $app['downloadlink']=$tmp->downloadlink; + }else{ + $app['downloadlink']=''; + } + return $app; + } + + + +} diff --git a/lib/private/preferences.php b/lib/private/preferences.php new file mode 100644 index 00000000000..359d9a83589 --- /dev/null +++ b/lib/private/preferences.php @@ -0,0 +1,232 @@ +. + * + */ +/* + * + * The following SQL statement is just a help for developers and will not be + * executed! + * + * CREATE TABLE `preferences` ( + * `userid` VARCHAR( 255 ) NOT NULL , + * `appid` VARCHAR( 255 ) NOT NULL , + * `configkey` VARCHAR( 255 ) NOT NULL , + * `configvalue` VARCHAR( 255 ) NOT NULL + * ) + * + */ + +namespace OC; + +use \OC\DB\Connection; + + +/** + * This class provides an easy way for storing user preferences. + */ +class Preferences { + protected $conn; + + public function __construct(Connection $conn) { + $this->conn = $conn; + } + + /** + * @brief Get all users using the preferences + * @return array with user ids + * + * This function returns a list of all users that have at least one entry + * in the preferences table. + */ + public function getUsers() { + $query = 'SELECT DISTINCT `userid` FROM `*PREFIX*preferences`'; + $result = $this->conn->executeQuery( $query ); + + $users = array(); + while( $userid = $result->fetchColumn()) { + $users[] = $userid; + } + + return $users; + } + + /** + * @brief Get all apps of an user + * @param string $user user + * @return array with app ids + * + * This function returns a list of all apps of the user that have at least + * one entry in the preferences table. + */ + public function getApps( $user ) { + $query = 'SELECT DISTINCT `appid` FROM `*PREFIX*preferences` WHERE `userid` = ?'; + $result = $this->conn->executeQuery( $query, array( $user ) ); + + $apps = array(); + while( $appid = $result->fetchColumn()) { + $apps[] = $appid; + } + + return $apps; + } + + /** + * @brief Get the available keys for an app + * @param string $user user + * @param string $app the app we are looking for + * @return array with key names + * + * This function gets all keys of an app of an user. Please note that the + * values are not returned. + */ + public function getKeys( $user, $app ) { + $query = 'SELECT `configkey` FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ?'; + $result = $this->conn->executeQuery( $query, array( $user, $app )); + + $keys = array(); + while( $key = $result->fetchColumn()) { + $keys[] = $key; + } + + return $keys; + } + + /** + * @brief Gets the preference + * @param string $user user + * @param string $app app + * @param string $key key + * @param string $default = null, default value if the key does not exist + * @return string the value or $default + * + * This function gets a value from the preferences table. If the key does + * not exist the default value will be returned + */ + public function getValue( $user, $app, $key, $default = null ) { + // Try to fetch the value, return default if not exists. + $query = 'SELECT `configvalue` FROM `*PREFIX*preferences`' + .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?'; + $row = $this->conn->fetchAssoc( $query, array( $user, $app, $key )); + if($row) { + return $row["configvalue"]; + } else { + return $default; + } + } + + /** + * @brief sets a value in the preferences + * @param string $user user + * @param string $app app + * @param string $key key + * @param string $value value + * + * Adds a value to the preferences. If the key did not exist before, it + * will be added automagically. + */ + public function setValue( $user, $app, $key, $value ) { + // Check if the key does exist + $query = 'SELECT COUNT(*) FROM `*PREFIX*preferences`' + .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?'; + $count = $this->conn->fetchColumn( $query, array( $user, $app, $key )); + $exists = $count > 0; + + if( !$exists ) { + $data = array( + 'userid' => $user, + 'appid' => $app, + 'configkey' => $key, + 'configvalue' => $value, + ); + $this->conn->insert('*PREFIX*preferences', $data); + } else { + $data = array( + 'configvalue' => $value, + ); + $where = array( + 'userid' => $user, + 'appid' => $app, + 'configkey' => $key, + ); + $this->conn->update('*PREFIX*preferences', $data, $where); + } + } + + /** + * @brief Deletes a key + * @param string $user user + * @param string $app app + * @param string $key key + * + * Deletes a key. + */ + public function deleteKey( $user, $app, $key ) { + $where = array( + 'userid' => $user, + 'appid' => $app, + 'configkey' => $key, + ); + $this->conn->delete('*PREFIX*preferences', $where); + } + + /** + * @brief Remove app of user from preferences + * @param string $user user + * @param string $app app + * + * Removes all keys in preferences belonging to the app and the user. + */ + public function deleteApp( $user, $app ) { + $where = array( + 'userid' => $user, + 'appid' => $app, + ); + $this->conn->delete('*PREFIX*preferences', $where); + } + + /** + * @brief Remove user from preferences + * @param string $user user + * + * Removes all keys in preferences belonging to the user. + */ + public function deleteUser( $user ) { + $where = array( + 'userid' => $user, + ); + $this->conn->delete('*PREFIX*preferences', $where); + } + + /** + * @brief Remove app from all users + * @param string $app app + * + * Removes all keys in preferences belonging to the app. + */ + public function deleteAppFromAllUsers( $app ) { + $where = array( + 'appid' => $app, + ); + $this->conn->delete('*PREFIX*preferences', $where); + } +} + +require_once __DIR__.'/legacy/'.basename(__FILE__); diff --git a/lib/private/preview.php b/lib/private/preview.php new file mode 100755 index 00000000000..266f7795f12 --- /dev/null +++ b/lib/private/preview.php @@ -0,0 +1,630 @@ +configMaxX = \OC_Config::getValue('preview_max_x', null); + $this->configMaxY = \OC_Config::getValue('preview_max_y', null); + $this->maxScaleFactor = \OC_Config::getValue('preview_max_scale_factor', 2); + + //save parameters + $this->setFile($file); + $this->setMaxX($maxX); + $this->setMaxY($maxY); + $this->setScalingUp($scalingUp); + + //init fileviews + if($user === ''){ + $user = \OC_User::getUser(); + } + $this->fileView = new \OC\Files\View('/' . $user . '/' . $root); + $this->userView = new \OC\Files\View('/' . $user); + + $this->preview = null; + + //check if there are preview backends + if(empty(self::$providers)) { + self::initProviders(); + } + + if(empty(self::$providers)) { + \OC_Log::write('core', 'No preview providers exist', \OC_Log::ERROR); + throw new \Exception('No preview providers'); + } + } + + /** + * @brief returns the path of the file you want a thumbnail from + * @return string + */ + public function getFile() { + return $this->file; + } + + /** + * @brief returns the max width of the preview + * @return integer + */ + public function getMaxX() { + return $this->maxX; + } + + /** + * @brief returns the max height of the preview + * @return integer + */ + public function getMaxY() { + return $this->maxY; + } + + /** + * @brief returns whether or not scalingup is enabled + * @return bool + */ + public function getScalingUp() { + return $this->scalingup; + } + + /** + * @brief returns the name of the thumbnailfolder + * @return string + */ + public function getThumbnailsFolder() { + return self::THUMBNAILS_FOLDER; + } + + /** + * @brief returns the max scale factor + * @return integer + */ + public function getMaxScaleFactor() { + return $this->maxScaleFactor; + } + + /** + * @brief returns the max width set in ownCloud's config + * @return integer + */ + public function getConfigMaxX() { + return $this->configMaxX; + } + + /** + * @brief returns the max height set in ownCloud's config + * @return integer + */ + public function getConfigMaxY() { + return $this->configMaxY; + } + + /** + * @brief set the path of the file you want a thumbnail from + * @param string $file + * @return $this + */ + public function setFile($file) { + $this->file = $file; + return $this; + } + + /** + * @brief set the the max width of the preview + * @param int $maxX + * @return $this + */ + public function setMaxX($maxX=1) { + if($maxX <= 0) { + throw new \Exception('Cannot set width of 0 or smaller!'); + } + $configMaxX = $this->getConfigMaxX(); + if(!is_null($configMaxX)) { + if($maxX > $configMaxX) { + \OC_Log::write('core', 'maxX reduced from ' . $maxX . ' to ' . $configMaxX, \OC_Log::DEBUG); + $maxX = $configMaxX; + } + } + $this->maxX = $maxX; + return $this; + } + + /** + * @brief set the the max height of the preview + * @param int $maxY + * @return $this + */ + public function setMaxY($maxY=1) { + if($maxY <= 0) { + throw new \Exception('Cannot set height of 0 or smaller!'); + } + $configMaxY = $this->getConfigMaxY(); + if(!is_null($configMaxY)) { + if($maxY > $configMaxY) { + \OC_Log::write('core', 'maxX reduced from ' . $maxY . ' to ' . $configMaxY, \OC_Log::DEBUG); + $maxY = $configMaxY; + } + } + $this->maxY = $maxY; + return $this; + } + + /** + * @brief set whether or not scalingup is enabled + * @param bool $scalingUp + * @return $this + */ + public function setScalingup($scalingUp) { + if($this->getMaxScaleFactor() === 1) { + $scalingUp = false; + } + $this->scalingup = $scalingUp; + return $this; + } + + /** + * @brief check if all parameters are valid + * @return bool + */ + public function isFileValid() { + $file = $this->getFile(); + if($file === '') { + \OC_Log::write('core', 'No filename passed', \OC_Log::DEBUG); + return false; + } + + if(!$this->fileView->file_exists($file)) { + \OC_Log::write('core', 'File:"' . $file . '" not found', \OC_Log::DEBUG); + return false; + } + + return true; + } + + /** + * @brief deletes previews of a file with specific x and y + * @return bool + */ + public function deletePreview() { + $file = $this->getFile(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/' . $this->getMaxX() . '-' . $this->getMaxY() . '.png'; + $this->userView->unlink($previewPath); + return !$this->userView->file_exists($previewPath); + } + + /** + * @brief deletes all previews of a file + * @return bool + */ + public function deleteAllPreviews() { + $file = $this->getFile(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; + $this->userView->deleteAll($previewPath); + $this->userView->rmdir($previewPath); + return !$this->userView->is_dir($previewPath); + } + + /** + * @brief check if thumbnail or bigger version of thumbnail of file is cached + * @return mixed (bool / string) + * false if thumbnail does not exist + * path to thumbnail if thumbnail exists + */ + private function isCached() { + $file = $this->getFile(); + $maxX = $this->getMaxX(); + $maxY = $this->getMaxY(); + $scalingUp = $this->getScalingUp(); + $maxScaleFactor = $this->getMaxScaleFactor(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + if(is_null($fileId)) { + return false; + } + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; + if(!$this->userView->is_dir($previewPath)) { + return false; + } + + //does a preview with the wanted height and width already exist? + if($this->userView->file_exists($previewPath . $maxX . '-' . $maxY . '.png')) { + return $previewPath . $maxX . '-' . $maxY . '.png'; + } + + $wantedAspectRatio = (float) ($maxX / $maxY); + + //array for usable cached thumbnails + $possibleThumbnails = array(); + + $allThumbnails = $this->userView->getDirectoryContent($previewPath); + foreach($allThumbnails as $thumbnail) { + $name = rtrim($thumbnail['name'], '.png'); + $size = explode('-', $name); + $x = (int) $size[0]; + $y = (int) $size[1]; + + $aspectRatio = (float) ($x / $y); + if($aspectRatio !== $wantedAspectRatio) { + continue; + } + + if($x < $maxX || $y < $maxY) { + if($scalingUp) { + $scalefactor = $maxX / $x; + if($scalefactor > $maxScaleFactor) { + continue; + } + }else{ + continue; + } + } + $possibleThumbnails[$x] = $thumbnail['path']; + } + + if(count($possibleThumbnails) === 0) { + return false; + } + + if(count($possibleThumbnails) === 1) { + return current($possibleThumbnails); + } + + ksort($possibleThumbnails); + + if(key(reset($possibleThumbnails)) > $maxX) { + return current(reset($possibleThumbnails)); + } + + if(key(end($possibleThumbnails)) < $maxX) { + return current(end($possibleThumbnails)); + } + + foreach($possibleThumbnails as $width => $path) { + if($width < $maxX) { + continue; + }else{ + return $path; + } + } + } + + /** + * @brief return a preview of a file + * @return \OC_Image + */ + public function getPreview() { + if(!is_null($this->preview) && $this->preview->valid()){ + return $this->preview; + } + + $this->preview = null; + $file = $this->getFile(); + $maxX = $this->getMaxX(); + $maxY = $this->getMaxY(); + $scalingUp = $this->getScalingUp(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + $cached = $this->isCached(); + + if($cached) { + $image = new \OC_Image($this->userView->file_get_contents($cached, 'r')); + $this->preview = $image->valid() ? $image : null; + $this->resizeAndCrop(); + } + + if(is_null($this->preview)) { + $mimetype = $this->fileView->getMimeType($file); + $preview = null; + + foreach(self::$providers as $supportedMimetype => $provider) { + if(!preg_match($supportedMimetype, $mimetype)) { + continue; + } + + \OC_Log::write('core', 'Generating preview for "' . $file . '" with "' . get_class($provider) . '"', \OC_Log::DEBUG); + + $preview = $provider->getThumbnail($file, $maxX, $maxY, $scalingUp, $this->fileView); + + if(!($preview instanceof \OC_Image)) { + continue; + } + + $this->preview = $preview; + $this->resizeAndCrop(); + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; + $cachePath = $previewPath . $maxX . '-' . $maxY . '.png'; + + if($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) { + $this->userView->mkdir($this->getThumbnailsFolder() . '/'); + } + + if($this->userView->is_dir($previewPath) === false) { + $this->userView->mkdir($previewPath); + } + + $this->userView->file_put_contents($cachePath, $preview->data()); + + break; + } + } + + if(is_null($this->preview)) { + $this->preview = new \OC_Image(); + } + + return $this->preview; + } + + /** + * @brief show preview + * @return void + */ + public function showPreview() { + \OCP\Response::enableCaching(3600 * 24); // 24 hours + if(is_null($this->preview)) { + $this->getPreview(); + } + $this->preview->show(); + return; + } + + /** + * @brief show preview + * @return void + */ + public function show() { + $this->showPreview(); + return; + } + + /** + * @brief resize, crop and fix orientation + * @return void + */ + private function resizeAndCrop() { + $image = $this->preview; + $x = $this->getMaxX(); + $y = $this->getMaxY(); + $scalingUp = $this->getScalingUp(); + $maxscalefactor = $this->getMaxScaleFactor(); + + if(!($image instanceof \OC_Image)) { + \OC_Log::write('core', '$this->preview is not an instance of OC_Image', \OC_Log::DEBUG); + return; + } + + $image->fixOrientation(); + + $realx = (int) $image->width(); + $realy = (int) $image->height(); + + if($x === $realx && $y === $realy) { + $this->preview = $image; + return; + } + + $factorX = $x / $realx; + $factorY = $y / $realy; + + if($factorX >= $factorY) { + $factor = $factorX; + }else{ + $factor = $factorY; + } + + if($scalingUp === false) { + if($factor > 1) { + $factor = 1; + } + } + + if(!is_null($maxscalefactor)) { + if($factor > $maxscalefactor) { + \OC_Log::write('core', 'scalefactor reduced from ' . $factor . ' to ' . $maxscalefactor, \OC_Log::DEBUG); + $factor = $maxscalefactor; + } + } + + $newXsize = (int) ($realx * $factor); + $newYsize = (int) ($realy * $factor); + + $image->preciseResize($newXsize, $newYsize); + + if($newXsize === $x && $newYsize === $y) { + $this->preview = $image; + return; + } + + if($newXsize >= $x && $newYsize >= $y) { + $cropX = floor(abs($x - $newXsize) * 0.5); + //don't crop previews on the Y axis, this sucks if it's a document. + //$cropY = floor(abs($y - $newYsize) * 0.5); + $cropY = 0; + + $image->crop($cropX, $cropY, $x, $y); + + $this->preview = $image; + return; + } + + if($newXsize < $x || $newYsize < $y) { + if($newXsize > $x) { + $cropX = floor(($newXsize - $x) * 0.5); + $image->crop($cropX, 0, $x, $newYsize); + } + + if($newYsize > $y) { + $cropY = floor(($newYsize - $y) * 0.5); + $image->crop(0, $cropY, $newXsize, $y); + } + + $newXsize = (int) $image->width(); + $newYsize = (int) $image->height(); + + //create transparent background layer + $backgroundlayer = imagecreatetruecolor($x, $y); + $white = imagecolorallocate($backgroundlayer, 255, 255, 255); + imagefill($backgroundlayer, 0, 0, $white); + + $image = $image->resource(); + + $mergeX = floor(abs($x - $newXsize) * 0.5); + $mergeY = floor(abs($y - $newYsize) * 0.5); + + imagecopy($backgroundlayer, $image, $mergeX, $mergeY, 0, 0, $newXsize, $newYsize); + + //$black = imagecolorallocate(0,0,0); + //imagecolortransparent($transparentlayer, $black); + + $image = new \OC_Image($backgroundlayer); + + $this->preview = $image; + return; + } + } + + /** + * @brief register a new preview provider to be used + * @param string $provider class name of a Preview_Provider + * @param array $options + * @return void + */ + public static function registerProvider($class, $options=array()) { + self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); + } + + /** + * @brief create instances of all the registered preview providers + * @return void + */ + private static function initProviders() { + if(!\OC_Config::getValue('enable_previews', true)) { + $provider = new Preview\Unknown(array()); + self::$providers = array($provider->getMimeType() => $provider); + return; + } + + if(count(self::$providers)>0) { + return; + } + + foreach(self::$registeredProviders as $provider) { + $class=$provider['class']; + $options=$provider['options']; + + $object = new $class($options); + + self::$providers[$object->getMimeType()] = $object; + } + + $keys = array_map('strlen', array_keys(self::$providers)); + array_multisort($keys, SORT_DESC, self::$providers); + } + + public static function post_write($args) { + self::post_delete($args); + } + + public static function post_delete($args) { + $path = $args['path']; + if(substr($path, 0, 1) === '/') { + $path = substr($path, 1); + } + $preview = new Preview(\OC_User::getUser(), 'files/', $path); + $preview->deleteAllPreviews(); + } + + public static function isMimeSupported($mimetype) { + if(!\OC_Config::getValue('enable_previews', true)) { + return false; + } + + //check if there are preview backends + if(empty(self::$providers)) { + self::initProviders(); + } + + //remove last element because it has the mimetype * + $providers = array_slice(self::$providers, 0, -1); + foreach($providers as $supportedMimetype => $provider) { + if(preg_match($supportedMimetype, $mimetype)) { + return true; + } + } + return false; + } +} diff --git a/lib/private/preview/image.php b/lib/private/preview/image.php new file mode 100644 index 00000000000..9aec967282d --- /dev/null +++ b/lib/private/preview/image.php @@ -0,0 +1,36 @@ +getFileInfo($path); + if(!$fileInfo) { + return false; + } + + //check if file is encrypted + if($fileInfo['encrypted'] === true) { + $image = new \OC_Image(stream_get_contents($fileview->fopen($path, 'r'))); + }else{ + $image = new \OC_Image(); + $image->loadFromFile($fileview->getLocalFile($path)); + } + + return $image->valid() ? $image : false; + } +} + +\OC\Preview::registerProvider('OC\Preview\Image'); \ No newline at end of file diff --git a/lib/private/preview/movies.php b/lib/private/preview/movies.php new file mode 100644 index 00000000000..c318137ff0e --- /dev/null +++ b/lib/private/preview/movies.php @@ -0,0 +1,47 @@ +fopen($path, 'rb'); + + $firstmb = stream_get_contents($handle, 1048576); //1024 * 1024 = 1048576 + file_put_contents($absPath, $firstmb); + + //$cmd = 'ffmpeg -y -i ' . escapeshellarg($absPath) . ' -f mjpeg -vframes 1 -ss 1 -s ' . escapeshellarg($maxX) . 'x' . escapeshellarg($maxY) . ' ' . $tmpPath; + $cmd = 'avconv -an -y -ss 1 -i ' . escapeshellarg($absPath) . ' -f mjpeg -vframes 1 ' . escapeshellarg($tmpPath); + + shell_exec($cmd); + + $image = new \OC_Image($tmpPath); + + unlink($absPath); + unlink($tmpPath); + + return $image->valid() ? $image : false; + } + } + + \OC\Preview::registerProvider('OC\Preview\Movie'); +} \ No newline at end of file diff --git a/lib/private/preview/mp3.php b/lib/private/preview/mp3.php new file mode 100644 index 00000000000..1eed566315c --- /dev/null +++ b/lib/private/preview/mp3.php @@ -0,0 +1,48 @@ +toTmpFile($path); + + $tags = $getID3->analyze($tmpPath); + \getid3_lib::CopyTagsToComments($tags); + if(isset($tags['id3v2']['APIC'][0]['data'])) { + $picture = @$tags['id3v2']['APIC'][0]['data']; + unlink($tmpPath); + $image = new \OC_Image($picture); + return $image->valid() ? $image : $this->getNoCoverThumbnail(); + } + + return $this->getNoCoverThumbnail(); + } + + private function getNoCoverThumbnail() { + $icon = \OC::$SERVERROOT . '/core/img/filetypes/audio.png'; + + if(!file_exists($icon)) { + return false; + } + + $image = new \OC_Image($icon); + return $image->valid() ? $image : false; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MP3'); \ No newline at end of file diff --git a/lib/private/preview/office-cl.php b/lib/private/preview/office-cl.php new file mode 100644 index 00000000000..112909d6523 --- /dev/null +++ b/lib/private/preview/office-cl.php @@ -0,0 +1,134 @@ +initCmd(); + if(is_null($this->cmd)) { + return false; + } + + $absPath = $fileview->toTmpFile($path); + + $tmpDir = get_temp_dir(); + + $defaultParameters = ' --headless --nologo --nofirststartwizard --invisible --norestore -convert-to pdf -outdir '; + $clParameters = \OCP\Config::getSystemValue('preview_office_cl_parameters', $defaultParameters); + + $exec = $this->cmd . $clParameters . escapeshellarg($tmpDir) . ' ' . escapeshellarg($absPath); + $export = 'export HOME=/' . $tmpDir; + + shell_exec($export . "\n" . $exec); + + //create imagick object from pdf + try{ + $pdf = new \imagick($absPath . '.pdf' . '[0]'); + $pdf->setImageFormat('jpg'); + } catch (\Exception $e) { + unlink($absPath); + unlink($absPath . '.pdf'); + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } + + $image = new \OC_Image($pdf); + + unlink($absPath); + unlink($absPath . '.pdf'); + + return $image->valid() ? $image : false; + } + + private function initCmd() { + $cmd = ''; + + if(is_string(\OC_Config::getValue('preview_libreoffice_path', null))) { + $cmd = \OC_Config::getValue('preview_libreoffice_path', null); + } + + $whichLibreOffice = shell_exec('which libreoffice'); + if($cmd === '' && !empty($whichLibreOffice)) { + $cmd = 'libreoffice'; + } + + $whichOpenOffice = shell_exec('which openoffice'); + if($cmd === '' && !empty($whichOpenOffice)) { + $cmd = 'openoffice'; + } + + if($cmd === '') { + $cmd = null; + } + + $this->cmd = $cmd; + } +} + +//.doc, .dot +class MSOfficeDoc extends Office { + + public function getMimeType() { + return '/application\/msword/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MSOfficeDoc'); + +//.docm, .dotm, .xls(m), .xlt(m), .xla(m), .ppt(m), .pot(m), .pps(m), .ppa(m) +class MSOffice2003 extends Office { + + public function getMimeType() { + return '/application\/vnd.ms-.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MSOffice2003'); + +//.docx, .dotx, .xlsx, .xltx, .pptx, .potx, .ppsx +class MSOffice2007 extends Office { + + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MSOffice2007'); + +//.odt, .ott, .oth, .odm, .odg, .otg, .odp, .otp, .ods, .ots, .odc, .odf, .odb, .odi, .oxt +class OpenDocument extends Office { + + public function getMimeType() { + return '/application\/vnd.oasis.opendocument.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\OpenDocument'); + +//.sxw, .stw, .sxc, .stc, .sxd, .std, .sxi, .sti, .sxg, .sxm +class StarOffice extends Office { + + public function getMimeType() { + return '/application\/vnd.sun.xml.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\StarOffice'); \ No newline at end of file diff --git a/lib/private/preview/office-fallback.php b/lib/private/preview/office-fallback.php new file mode 100644 index 00000000000..e69ab0ab8cb --- /dev/null +++ b/lib/private/preview/office-fallback.php @@ -0,0 +1,142 @@ +toTmpFile($path); + + $transformdoc = new \TransformDoc(); + $transformdoc->setStrFile($tmpDoc); + $transformdoc->generatePDF($tmpDoc); + + $pdf = new \imagick($tmpDoc . '[0]'); + $pdf->setImageFormat('jpg'); + + unlink($tmpDoc); + + $image = new \OC_Image($pdf); + + return $image->valid() ? $image : false; + } + +} + +\OC\Preview::registerProvider('OC\Preview\DOCX'); + +class MSOfficeExcel extends Provider { + + public function getMimeType() { + return null; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + require_once('PHPExcel/Classes/PHPExcel.php'); + require_once('PHPExcel/Classes/PHPExcel/IOFactory.php'); + + $absPath = $fileview->toTmpFile($path); + $tmpPath = \OC_Helper::tmpFile(); + + $rendererName = \PHPExcel_Settings::PDF_RENDERER_DOMPDF; + $rendererLibraryPath = \OC::$THIRDPARTYROOT . '/3rdparty/dompdf'; + + \PHPExcel_Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + + $phpexcel = new \PHPExcel($absPath); + $excel = \PHPExcel_IOFactory::createWriter($phpexcel, 'PDF'); + $excel->save($tmpPath); + + $pdf = new \imagick($tmpPath . '[0]'); + $pdf->setImageFormat('jpg'); + + unlink($absPath); + unlink($tmpPath); + + $image = new \OC_Image($pdf); + + return $image->valid() ? $image : false; + } + +} + +class XLS extends MSOfficeExcel { + + public function getMimeType() { + return '/application\/vnd.ms-excel/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\XLS'); + +class XLSX extends MSOfficeExcel { + + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\XLSX'); + +/* //There is no (good) php-only solution for converting powerpoint documents to pdfs / pngs ... +class MSOfficePowerPoint extends Provider { + + public function getMimeType() { + return null; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + return false; + } + +} + +class PPT extends MSOfficePowerPoint { + + public function getMimeType() { + return '/application\/vnd.ms-powerpoint/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\PPT'); + +class PPTX extends MSOfficePowerPoint { + + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.presentationml.presentation/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\PPTX'); +*/ \ No newline at end of file diff --git a/lib/private/preview/office.php b/lib/private/preview/office.php new file mode 100644 index 00000000000..5287bbd6ac1 --- /dev/null +++ b/lib/private/preview/office.php @@ -0,0 +1,22 @@ +toTmpFile($path); + + //create imagick object from pdf + try{ + $pdf = new \imagick($tmpPath . '[0]'); + $pdf->setImageFormat('jpg'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } + + unlink($tmpPath); + + //new image object + $image = new \OC_Image($pdf); + //check if image object is valid + return $image->valid() ? $image : false; + } + } + + \OC\Preview::registerProvider('OC\Preview\PDF'); +} diff --git a/lib/private/preview/provider.php b/lib/private/preview/provider.php new file mode 100644 index 00000000000..e4a730bafc8 --- /dev/null +++ b/lib/private/preview/provider.php @@ -0,0 +1,19 @@ +options=$options; + } + + abstract public function getMimeType(); + + /** + * search for $query + * @param string $query + * @return + */ + abstract public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview); +} diff --git a/lib/private/preview/svg.php b/lib/private/preview/svg.php new file mode 100644 index 00000000000..b49e51720fa --- /dev/null +++ b/lib/private/preview/svg.php @@ -0,0 +1,46 @@ +setBackgroundColor(new \ImagickPixel('transparent')); + + $content = stream_get_contents($fileview->fopen($path, 'r')); + if(substr($content, 0, 5) !== '' . $content; + } + + $svg->readImageBlob($content); + $svg->setImageFormat('png32'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } + + + //new image object + $image = new \OC_Image(); + $image->loadFromData($svg); + //check if image object is valid + return $image->valid() ? $image : false; + } + } + + \OC\Preview::registerProvider('OC\Preview\SVG'); + +} \ No newline at end of file diff --git a/lib/private/preview/txt.php b/lib/private/preview/txt.php new file mode 100644 index 00000000000..77e728eb364 --- /dev/null +++ b/lib/private/preview/txt.php @@ -0,0 +1,83 @@ +getMimeType($path); + if(in_array($mimetype, self::$blacklist)) { + return false; + } + + $content = $fileview->fopen($path, 'r'); + $content = stream_get_contents($content); + + //don't create previews of empty text files + if(trim($content) === '') { + return false; + } + + $lines = preg_split("/\r\n|\n|\r/", $content); + + $fontSize = 5; //5px + $lineSize = ceil($fontSize * 1.25); + + $image = imagecreate($maxX, $maxY); + imagecolorallocate($image, 255, 255, 255); + $textColor = imagecolorallocate($image, 0, 0, 0); + + foreach($lines as $index => $line) { + $index = $index + 1; + + $x = (int) 1; + $y = (int) ($index * $lineSize) - $fontSize; + + imagestring($image, 1, $x, $y, $line, $textColor); + + if(($index * $lineSize) >= $maxY) { + break; + } + } + + $image = new \OC_Image($image); + + return $image->valid() ? $image : false; + } +} + +\OC\Preview::registerProvider('OC\Preview\TXT'); + +class PHP extends TXT { + + public function getMimeType() { + return '/application\/x-php/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\PHP'); + +class JavaScript extends TXT { + + public function getMimeType() { + return '/application\/javascript/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\JavaScript'); \ No newline at end of file diff --git a/lib/private/preview/unknown.php b/lib/private/preview/unknown.php new file mode 100644 index 00000000000..9e6cd68d401 --- /dev/null +++ b/lib/private/preview/unknown.php @@ -0,0 +1,27 @@ +getMimeType($path); + + $path = \OC_Helper::mimetypeIcon($mimetype); + $path = \OC::$SERVERROOT . substr($path, strlen(\OC::$WEBROOT)); + + return new \OC_Image($path); + } +} + +\OC\Preview::registerProvider('OC\Preview\Unknown'); \ No newline at end of file diff --git a/lib/private/previewmanager.php b/lib/private/previewmanager.php new file mode 100755 index 00000000000..ac9a866a75b --- /dev/null +++ b/lib/private/previewmanager.php @@ -0,0 +1,38 @@ +getPreview(); + } + + /** + * @brief returns true if the passed mime type is supported + * @param string $mimeType + * @return boolean + */ + function isMimeSupported($mimeType = '*') + { + return \OC\Preview::isMimeSupported($mimeType); + } +} diff --git a/lib/private/request.php b/lib/private/request.php new file mode 100755 index 00000000000..df33217f95d --- /dev/null +++ b/lib/private/request.php @@ -0,0 +1,184 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Request { + /** + * @brief Check overwrite condition + * @returns bool + */ + private static function isOverwriteCondition($type = '') { + $regex = '/' . OC_Config::getValue('overwritecondaddr', '') . '/'; + return $regex === '//' or preg_match($regex, $_SERVER['REMOTE_ADDR']) === 1 + or ($type !== 'protocol' and OC_Config::getValue('forcessl', false)); + } + + /** + * @brief Returns the server host + * @returns string the server host + * + * Returns the server host, even if the website uses one or more + * reverse proxies + */ + public static function serverHost() { + if(OC::$CLI) { + return 'localhost'; + } + if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) { + return OC_Config::getValue('overwritehost'); + } + if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { + if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { + $host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST']))); + } + else{ + $host=$_SERVER['HTTP_X_FORWARDED_HOST']; + } + } + else{ + if (isset($_SERVER['HTTP_HOST'])) { + return $_SERVER['HTTP_HOST']; + } + if (isset($_SERVER['SERVER_NAME'])) { + return $_SERVER['SERVER_NAME']; + } + return 'localhost'; + } + return $host; + } + + + /** + * @brief Returns the server protocol + * @returns string the server protocol + * + * Returns the server protocol. It respects reverse proxy servers and load balancers + */ + public static function serverProtocol() { + if(OC_Config::getValue('overwriteprotocol', '') !== '' and self::isOverwriteCondition('protocol')) { + return OC_Config::getValue('overwriteprotocol'); + } + if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + $proto = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']); + }else{ + if(isset($_SERVER['HTTPS']) and !empty($_SERVER['HTTPS']) and ($_SERVER['HTTPS']!='off')) { + $proto = 'https'; + }else{ + $proto = 'http'; + } + } + return $proto; + } + + /** + * @brief Returns the request uri + * @returns string the request uri + * + * Returns the request uri, even if the website uses one or more + * reverse proxies + */ + public static function requestUri() { + $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) { + $uri = self::scriptName() . substr($uri, strlen($_SERVER['SCRIPT_NAME'])); + } + return $uri; + } + + /** + * @brief Returns the script name + * @returns string the script name + * + * Returns the script name, even if the website uses one or more + * reverse proxies + */ + public static function scriptName() { + $name = $_SERVER['SCRIPT_NAME']; + if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) { + $serverroot = str_replace("\\", '/', substr(__DIR__, 0, -4)); + $suburi = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen($serverroot))); + $name = OC_Config::getValue('overwritewebroot', '') . $suburi; + } + return $name; + } + + /** + * @brief get Path info from request + * @returns string Path info or false when not found + */ + public static function getPathInfo() { + if (array_key_exists('PATH_INFO', $_SERVER)) { + $path_info = $_SERVER['PATH_INFO']; + }else{ + $path_info = self::getRawPathInfo(); + // following is taken from Sabre_DAV_URLUtil::decodePathSegment + $path_info = rawurldecode($path_info); + $encoding = mb_detect_encoding($path_info, array('UTF-8', 'ISO-8859-1')); + + switch($encoding) { + + case 'ISO-8859-1' : + $path_info = utf8_encode($path_info); + + } + // end copy + } + return $path_info; + } + + /** + * @brief get Path info from request, not urldecoded + * @returns string Path info or false when not found + */ + public static function getRawPathInfo() { + $path_info = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME'])); + // Remove the query string from REQUEST_URI + if ($pos = strpos($path_info, '?')) { + $path_info = substr($path_info, 0, $pos); + } + return $path_info; + } + + /** + * @brief Check if this is a no-cache request + * @returns boolean true for no-cache + */ + static public function isNoCache() { + if (!isset($_SERVER['HTTP_CACHE_CONTROL'])) { + return false; + } + return $_SERVER['HTTP_CACHE_CONTROL'] == 'no-cache'; + } + + /** + * @brief Check if the requestor understands gzip + * @returns boolean true for gzip encoding supported + */ + static public function acceptGZip() { + if (!isset($_SERVER['HTTP_ACCEPT_ENCODING'])) { + return false; + } + $HTTP_ACCEPT_ENCODING = $_SERVER["HTTP_ACCEPT_ENCODING"]; + if( strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') !== false ) + return 'x-gzip'; + else if( strpos($HTTP_ACCEPT_ENCODING, 'gzip') !== false ) + return 'gzip'; + return false; + } + + /** + * @brief Check if the requester sent along an mtime + * @returns false or an mtime + */ + static public function hasModificationTime () { + if (isset($_SERVER['HTTP_X_OC_MTIME'])) { + return $_SERVER['HTTP_X_OC_MTIME']; + } else { + return false; + } + } +} diff --git a/lib/private/response.php b/lib/private/response.php new file mode 100644 index 00000000000..674176d078b --- /dev/null +++ b/lib/private/response.php @@ -0,0 +1,167 @@ +0 cache time in seconds + * 0 and <0 enable default browser caching + * null cache indefinitly + */ + static public function enableCaching($cache_time = null) { + if (is_numeric($cache_time)) { + header('Pragma: public');// enable caching in IE + if ($cache_time > 0) { + self::setExpiresHeader('PT'.$cache_time.'S'); + header('Cache-Control: max-age='.$cache_time.', must-revalidate'); + } + else { + self::setExpiresHeader(0); + header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); + } + } + else { + header('Cache-Control: cache'); + header('Pragma: cache'); + } + + } + + /** + * @brief disable browser caching + * @see enableCaching with cache_time = 0 + */ + static public function disableCaching() { + self::enableCaching(0); + } + + /** + * @brief Set response status + * @param $status a HTTP status code, see also the STATUS constants + */ + static public function setStatus($status) { + $protocol = $_SERVER['SERVER_PROTOCOL']; + switch($status) { + case self::STATUS_NOT_MODIFIED: + $status = $status . ' Not Modified'; + break; + case self::STATUS_TEMPORARY_REDIRECT: + if ($protocol == 'HTTP/1.1') { + $status = $status . ' Temporary Redirect'; + break; + } else { + $status = self::STATUS_FOUND; + // fallthrough + } + case self::STATUS_FOUND; + $status = $status . ' Found'; + break; + case self::STATUS_NOT_FOUND; + $status = $status . ' Not Found'; + break; + case self::STATUS_INTERNAL_SERVER_ERROR; + $status = $status . ' Internal Server Error'; + break; + } + header($protocol.' '.$status); + } + + /** + * @brief Send redirect response + * @param $location to redirect to + */ + static public function redirect($location) { + self::setStatus(self::STATUS_TEMPORARY_REDIRECT); + header('Location: '.$location); + } + + /** + * @brief Set reponse expire time + * @param $expires date-time when the response expires + * string for DateInterval from now + * DateTime object when to expire response + */ + static public function setExpiresHeader($expires) { + if (is_string($expires) && $expires[0] == 'P') { + $interval = $expires; + $expires = new DateTime('now'); + $expires->add(new DateInterval($interval)); + } + if ($expires instanceof DateTime) { + $expires->setTimezone(new DateTimeZone('GMT')); + $expires = $expires->format(DateTime::RFC2822); + } + header('Expires: '.$expires); + } + + /** + * Checks and set ETag header, when the request matches sends a + * 'not modified' response + * @param $etag token to use for modification check + */ + static public function setETagHeader($etag) { + if (empty($etag)) { + return; + } + $etag = '"'.$etag.'"'; + if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && + trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { + self::setStatus(self::STATUS_NOT_MODIFIED); + exit; + } + header('ETag: '.$etag); + } + + /** + * Checks and set Last-Modified header, when the request matches sends a + * 'not modified' response + * @param $lastModified time when the reponse was last modified + */ + static public function setLastModifiedHeader($lastModified) { + if (empty($lastModified)) { + return; + } + if (is_int($lastModified)) { + $lastModified = gmdate(DateTime::RFC2822, $lastModified); + } + if ($lastModified instanceof DateTime) { + $lastModified = $lastModified->format(DateTime::RFC2822); + } + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && + trim($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) { + self::setStatus(self::STATUS_NOT_MODIFIED); + exit; + } + header('Last-Modified: '.$lastModified); + } + + /** + * @brief Send file as response, checking and setting caching headers + * @param $filepath of file to send + */ + static public function sendFile($filepath) { + $fp = fopen($filepath, 'rb'); + if ($fp) { + self::setLastModifiedHeader(filemtime($filepath)); + self::setETagHeader(md5_file($filepath)); + + header('Content-Length: '.filesize($filepath)); + fpassthru($fp); + } + else { + self::setStatus(self::STATUS_NOT_FOUND); + } + } +} diff --git a/lib/private/route.php b/lib/private/route.php new file mode 100644 index 00000000000..5901717c094 --- /dev/null +++ b/lib/private/route.php @@ -0,0 +1,116 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +use Symfony\Component\Routing\Route; + +class OC_Route extends Route { + /** + * Specify the method when this route is to be used + * + * @param string $method HTTP method (uppercase) + */ + public function method($method) { + $this->setRequirement('_method', strtoupper($method)); + return $this; + } + + /** + * Specify POST as the method to use with this route + */ + public function post() { + $this->method('POST'); + return $this; + } + + /** + * Specify GET as the method to use with this route + */ + public function get() { + $this->method('GET'); + return $this; + } + + /** + * Specify PUT as the method to use with this route + */ + public function put() { + $this->method('PUT'); + return $this; + } + + /** + * Specify DELETE as the method to use with this route + */ + public function delete() { + $this->method('DELETE'); + return $this; + } + + /** + * Defaults to use for this route + * + * @param array $defaults The defaults + */ + public function defaults($defaults) { + $action = $this->getDefault('action'); + $this->setDefaults($defaults); + if (isset($defaults['action'])) { + $action = $defaults['action']; + } + $this->action($action); + return $this; + } + + /** + * Requirements for this route + * + * @param array $requirements The requirements + */ + public function requirements($requirements) { + $method = $this->getRequirement('_method'); + $this->setRequirements($requirements); + if (isset($requirements['_method'])) { + $method = $requirements['_method']; + } + if ($method) { + $this->method($method); + } + return $this; + } + + /** + * The action to execute when this route matches + * @param string|callable $class the class or a callable + * @param string $function the function to use with the class + * + * This function is called with $class set to a callable or + * to the class with $function + */ + public function action($class, $function = null) { + $action = array($class, $function); + if (is_null($function)) { + $action = $class; + } + $this->setDefault('action', $action); + return $this; + } + + /** + * The action to execute when this route matches, includes a file like + * it is called directly + * @param $file + */ + public function actionInclude($file) { + $function = create_function('$param', + 'unset($param["_route"]);' + .'$_GET=array_merge($_GET, $param);' + .'unset($param);' + .'require_once "'.$file.'";'); + $this->action($function); + } +} diff --git a/lib/private/router.php b/lib/private/router.php new file mode 100644 index 00000000000..dbaca9e0d5d --- /dev/null +++ b/lib/private/router.php @@ -0,0 +1,183 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RouteCollection; +//use Symfony\Component\Routing\Route; + +class OC_Router { + protected $collections = array(); + protected $collection = null; + protected $root = null; + + protected $generator = null; + protected $routing_files; + protected $cache_key; + + public function __construct() { + $baseUrl = OC_Helper::linkTo('', 'index.php'); + if ( !OC::$CLI) { + $method = $_SERVER['REQUEST_METHOD']; + }else{ + $method = 'GET'; + } + $host = OC_Request::serverHost(); + $schema = OC_Request::serverProtocol(); + $this->context = new RequestContext($baseUrl, $method, $host, $schema); + // TODO cache + $this->root = $this->getCollection('root'); + } + + public function getRoutingFiles() { + if (!isset($this->routing_files)) { + $this->routing_files = array(); + foreach(OC_APP::getEnabledApps() as $app) { + $file = OC_App::getAppPath($app).'/appinfo/routes.php'; + if(file_exists($file)) { + $this->routing_files[$app] = $file; + } + } + } + return $this->routing_files; + } + + public function getCacheKey() { + if (!isset($this->cache_key)) { + $files = $this->getRoutingFiles(); + $files[] = 'settings/routes.php'; + $files[] = 'core/routes.php'; + $files[] = 'ocs/routes.php'; + $this->cache_key = OC_Cache::generateCacheKeyFromFiles($files); + } + return $this->cache_key; + } + + /** + * loads the api routes + */ + public function loadRoutes() { + foreach($this->getRoutingFiles() as $app => $file) { + $this->useCollection($app); + require_once $file; + $collection = $this->getCollection($app); + $this->root->addCollection($collection, '/apps/'.$app); + } + $this->useCollection('root'); + require_once 'settings/routes.php'; + require_once 'core/routes.php'; + + // include ocs routes + require_once 'ocs/routes.php'; + $collection = $this->getCollection('ocs'); + $this->root->addCollection($collection, '/ocs'); + } + + protected function getCollection($name) { + if (!isset($this->collections[$name])) { + $this->collections[$name] = new RouteCollection(); + } + return $this->collections[$name]; + } + + /** + * Sets the collection to use for adding routes + * + * @param string $name Name of the colletion to use. + */ + public function useCollection($name) { + $this->collection = $this->getCollection($name); + } + + /** + * Create a OC_Route. + * + * @param string $name Name of the route to create. + * @param string $pattern The pattern to match + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + */ + public function create($name, $pattern, array $defaults = array(), array $requirements = array()) { + $route = new OC_Route($pattern, $defaults, $requirements); + $this->collection->add($name, $route); + return $route; + } + + /** + * Find the route matching $url. + * + * @param string $url The url to find + */ + public function match($url) { + $matcher = new UrlMatcher($this->root, $this->context); + $parameters = $matcher->match($url); + if (isset($parameters['action'])) { + $action = $parameters['action']; + if (!is_callable($action)) { + var_dump($action); + throw new Exception('not a callable action'); + } + unset($parameters['action']); + call_user_func($action, $parameters); + } elseif (isset($parameters['file'])) { + include $parameters['file']; + } else { + throw new Exception('no action available'); + } + } + + /** + * Get the url generator + * + */ + public function getGenerator() + { + if (null !== $this->generator) { + return $this->generator; + } + + return $this->generator = new UrlGenerator($this->root, $this->context); + } + + /** + * Generate url based on $name and $parameters + * + * @param string $name Name of the route to use. + * @param array $parameters Parameters for the route + */ + public function generate($name, $parameters = array(), $absolute = false) + { + return $this->getGenerator()->generate($name, $parameters, $absolute); + } + + /** + * Generate JSON response for routing in javascript + */ + public static function JSRoutes() + { + $router = OC::getRouter(); + + $etag = $router->getCacheKey(); + OC_Response::enableCaching(); + OC_Response::setETagHeader($etag); + + $root = $router->getCollection('root'); + $routes = array(); + foreach($root->all() as $name => $route) { + $compiled_route = $route->compile(); + $defaults = $route->getDefaults(); + unset($defaults['action']); + $routes[$name] = array( + 'tokens' => $compiled_route->getTokens(), + 'defaults' => $defaults, + ); + } + OCP\JSON::success ( array( 'data' => $routes ) ); + } +} diff --git a/lib/private/search.php b/lib/private/search.php new file mode 100644 index 00000000000..b9c75dfc333 --- /dev/null +++ b/lib/private/search.php @@ -0,0 +1,90 @@ +. + * + */ + + +/** + * provides an interface to all search providers + */ +class OC_Search{ + static private $providers=array(); + static private $registeredProviders=array(); + + /** + * remove all registered search providers + */ + public static function clearProviders() { + self::$providers=array(); + self::$registeredProviders=array(); + } + + /** + * register a new search provider to be used + * @param string $provider class name of a OC_Search_Provider + */ + public static function registerProvider($class, $options=array()) { + self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); + } + + /** + * search all provider for $query + * @param string query + * @return array An array of OC_Search_Result's + */ + public static function search($query) { + self::initProviders(); + $results=array(); + foreach(self::$providers as $provider) { + $results=array_merge($results, $provider->search($query)); + } + return $results; + } + + /** + * remove an existing search provider + * @param string $provider class name of a OC_Search_Provider + */ + public static function removeProvider($provider) { + self::$registeredProviders = array_filter( + self::$registeredProviders, + function ($element) use ($provider) { + return ($element['class'] != $provider); + } + ); + // force regeneration of providers on next search + self::$providers=array(); + } + + + /** + * create instances of all the registered search providers + */ + private static function initProviders() { + if(count(self::$providers)>0) { + return; + } + foreach(self::$registeredProviders as $provider) { + $class=$provider['class']; + $options=$provider['options']; + self::$providers[]=new $class($options); + } + } +} diff --git a/lib/private/search/provider.php b/lib/private/search/provider.php new file mode 100644 index 00000000000..b617b9c5d94 --- /dev/null +++ b/lib/private/search/provider.php @@ -0,0 +1,18 @@ +options=$options; + } + + /** + * search for $query + * @param string $query + * @return array An array of OC_Search_Result's + */ + abstract public function search($query); +} diff --git a/lib/private/search/provider/file.php b/lib/private/search/provider/file.php new file mode 100644 index 00000000000..9bd50931517 --- /dev/null +++ b/lib/private/search/provider/file.php @@ -0,0 +1,46 @@ + $path)); + $type = (string)$l->t('Files'); + }else{ + $link = OC_Helper::linkToRoute( 'download', array('file' => $path)); + $mimeBase = $fileData['mimepart']; + switch($mimeBase) { + case 'audio': + $skip = true; + break; + case 'text': + $type = (string)$l->t('Text'); + break; + case 'image': + $type = (string)$l->t('Images'); + break; + default: + if($mime=='application/xml') { + $type = (string)$l->t('Text'); + }else{ + $type = (string)$l->t('Files'); + } + } + } + if(!$skip) { + $results[] = new OC_Search_Result($name, $text, $link, $type, $container); + } + } + return $results; + } +} diff --git a/lib/private/search/result.php b/lib/private/search/result.php new file mode 100644 index 00000000000..42275c2df11 --- /dev/null +++ b/lib/private/search/result.php @@ -0,0 +1,26 @@ +name=$name; + $this->text=$text; + $this->link=$link; + $this->type=$type; + $this->container=$container; + } +} diff --git a/lib/private/server.php b/lib/private/server.php new file mode 100644 index 00000000000..cabb15324ec --- /dev/null +++ b/lib/private/server.php @@ -0,0 +1,255 @@ +registerService('ContactsManager', function($c) { + return new ContactsManager(); + }); + $this->registerService('Request', function($c) { + $params = array(); + + // we json decode the body only in case of content type json + if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') !== false ) { + $params = json_decode(file_get_contents('php://input'), true); + $params = is_array($params) ? $params: array(); + } + + return new Request( + array( + 'get' => $_GET, + 'post' => $_POST, + 'files' => $_FILES, + 'server' => $_SERVER, + 'env' => $_ENV, + 'cookies' => $_COOKIE, + 'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) + ? $_SERVER['REQUEST_METHOD'] + : null, + 'params' => $params, + 'urlParams' => $c['urlParams'] + ) + ); + }); + $this->registerService('PreviewManager', function($c) { + return new PreviewManager(); + }); + $this->registerService('TagManager', function($c) { + $user = \OC_User::getUser(); + return new TagManager($user); + }); + $this->registerService('RootFolder', function($c) { + // TODO: get user and user manager from container as well + $user = \OC_User::getUser(); + /** @var $c SimpleContainer */ + $userManager = $c->query('UserManager'); + $user = $userManager->get($user); + $manager = \OC\Files\Filesystem::getMountManager(); + $view = new View(); + return new Root($manager, $view, $user); + }); + $this->registerService('UserManager', function($c) { + return new \OC\User\Manager(); + }); + $this->registerService('UserSession', function($c) { + /** @var $c SimpleContainer */ + $manager = $c->query('UserManager'); + $userSession = new \OC\User\Session($manager, \OC::$session); + $userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) { + \OC_Hook::emit('OC_User', 'pre_createUser', array('run' => true, 'uid' => $uid, 'password' => $password)); + }); + $userSession->listen('\OC\User', 'postCreateUser', function ($user, $password) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_createUser', array('uid' => $user->getUID(), 'password' => $password)); + }); + $userSession->listen('\OC\User', 'preDelete', function ($user) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'pre_deleteUser', array('run' => true, 'uid' => $user->getUID())); + }); + $userSession->listen('\OC\User', 'postDelete', function ($user) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_deleteUser', array('uid' => $user->getUID())); + }); + $userSession->listen('\OC\User', 'preSetPassword', function ($user, $password, $recoveryPassword) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'pre_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); + }); + $userSession->listen('\OC\User', 'postSetPassword', function ($user, $password, $recoveryPassword) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); + }); + $userSession->listen('\OC\User', 'preLogin', function ($uid, $password) { + \OC_Hook::emit('OC_User', 'pre_login', array('run' => true, 'uid' => $uid, 'password' => $password)); + }); + $userSession->listen('\OC\User', 'postLogin', function ($user, $password) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_login', array('run' => true, 'uid' => $user->getUID(), 'password' => $password)); + }); + $userSession->listen('\OC\User', 'logout', function () { + \OC_Hook::emit('OC_User', 'logout', array()); + }); + return $userSession; + }); + $this->registerService('NavigationManager', function($c) { + return new \OC\NavigationManager(); + }); + $this->registerService('AllConfig', function($c) { + return new \OC\AllConfig(); + }); + $this->registerService('UserCache', function($c) { + return new UserCache(); + }); + } + + /** + * @return \OCP\Contacts\IManager + */ + function getContactsManager() { + return $this->query('ContactsManager'); + } + + /** + * The current request object holding all information about the request + * currently being processed is returned from this method. + * In case the current execution was not initiated by a web request null is returned + * + * @return \OCP\IRequest|null + */ + function getRequest() { + return $this->query('Request'); + } + + /** + * Returns the preview manager which can create preview images for a given file + * + * @return \OCP\IPreview + */ + function getPreviewManager() { + return $this->query('PreviewManager'); + } + + /** + * Returns the tag manager which can get and set tags for different object types + * + * @see \OCP\ITagManager::load() + * @return \OCP\ITagManager + */ + function getTagManager() { + return $this->query('TagManager'); + } + + /** + * Returns the root folder of ownCloud's data directory + * + * @return \OCP\Files\Folder + */ + function getRootFolder() { + return $this->query('RootFolder'); + } + + /** + * Returns a view to ownCloud's files folder + * + * @return \OCP\Files\Folder + */ + function getUserFolder() { + + $dir = '/files'; + $root = $this->getRootFolder(); + $folder = null; + if(!$root->nodeExists($dir)) { + $folder = $root->newFolder($dir); + } else { + $folder = $root->get($dir); + } + return $folder; + } + + /** + * Returns an app-specific view in ownClouds data directory + * + * @return \OCP\Files\Folder + */ + function getAppFolder() { + + $dir = '/' . \OC_App::getCurrentApp(); + $root = $this->getRootFolder(); + $folder = null; + if(!$root->nodeExists($dir)) { + $folder = $root->newFolder($dir); + } else { + $folder = $root->get($dir); + } + return $folder; + } + + /** + * @return \OC\User\Manager + */ + function getUserManager() { + return $this->query('UserManager'); + } + + /** + * @return \OC\User\Session + */ + function getUserSession() { + return $this->query('UserSession'); + } + + /** + * @return \OC\NavigationManager + */ + function getNavigationManager() { + return $this->query('NavigationManager'); + } + + /** + * @return \OC\Config + */ + function getConfig() { + return $this->query('AllConfig'); + } + + /** + * Returns an ICache instance + * + * @return \OCP\ICache + */ + function getCache() { + return $this->query('UserCache'); + } + + /** + * Returns the current session + * + * @return \OCP\ISession + */ + function getSession() { + return \OC::$session; + } + + /** + * Returns the current session + * + * @return \OCP\IDBConnection + */ + function getDatabaseConnection() { + return \OC_DB::getConnection(); + } +} diff --git a/lib/private/session/internal.php b/lib/private/session/internal.php new file mode 100644 index 00000000000..60aecccc8aa --- /dev/null +++ b/lib/private/session/internal.php @@ -0,0 +1,39 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Session; + +/** + * Class Internal + * + * wrap php's internal session handling into the Session interface + * + * @package OC\Session + */ +class Internal extends Memory { + public function __construct($name) { + session_name($name); + session_start(); + if (!isset($_SESSION)) { + throw new \Exception('Failed to start session'); + } + $this->data = $_SESSION; + } + + public function __destruct() { + $_SESSION = $this->data; + session_write_close(); + } + + public function clear() { + session_unset(); + @session_regenerate_id(true); + @session_start(); + $this->data = $_SESSION = array(); + } +} diff --git a/lib/private/session/memory.php b/lib/private/session/memory.php new file mode 100644 index 00000000000..c148ff4b9b9 --- /dev/null +++ b/lib/private/session/memory.php @@ -0,0 +1,63 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Session; + +/** + * Class Internal + * + * store session data in an in-memory array, not persistance + * + * @package OC\Session + */ +class Memory extends Session { + protected $data; + + public function __construct($name) { + //no need to use $name since all data is already scoped to this instance + $this->data = array(); + } + + /** + * @param string $key + * @param mixed $value + */ + public function set($key, $value) { + $this->data[$key] = $value; + } + + /** + * @param string $key + * @return mixed + */ + public function get($key) { + if (!$this->exists($key)) { + return null; + } + return $this->data[$key]; + } + + /** + * @param string $key + * @return bool + */ + public function exists($key) { + return isset($this->data[$key]); + } + + /** + * @param string $key + */ + public function remove($key) { + unset($this->data[$key]); + } + + public function clear() { + $this->data = array(); + } +} diff --git a/lib/private/session/session.php b/lib/private/session/session.php new file mode 100644 index 00000000000..c55001eccac --- /dev/null +++ b/lib/private/session/session.php @@ -0,0 +1,79 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Session; + +abstract class Session implements \ArrayAccess, \OCP\ISession { + /** + * $name serves as a namespace for the session keys + * + * @param string $name + */ + abstract public function __construct($name); + + /** + * @param string $key + * @param mixed $value + */ + abstract public function set($key, $value); + + /** + * @param string $key + * @return mixed should return null if $key does not exist + */ + abstract public function get($key); + + /** + * @param string $key + * @return bool + */ + abstract public function exists($key); + + /** + * should not throw any errors if $key does not exist + * + * @param string $key + */ + abstract public function remove($key); + + /** + * removes all entries within the cache namespace + */ + abstract public function clear(); + + /** + * @param mixed $offset + * @return bool + */ + public function offsetExists($offset) { + return $this->exists($offset); + } + + /** + * @param mixed $offset + * @return mixed + */ + public function offsetGet($offset) { + return $this->get($offset); + } + + /** + * @param mixed $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) { + $this->set($offset, $value); + } + + /** + * @param mixed $offset + */ + public function offsetUnset($offset) { + $this->remove($offset); + } +} diff --git a/lib/private/setup.php b/lib/private/setup.php new file mode 100644 index 00000000000..6bf3c88370f --- /dev/null +++ b/lib/private/setup.php @@ -0,0 +1,192 @@ + '\OC\Setup\MySQL', + 'pgsql' => '\OC\Setup\PostgreSQL', + 'oci' => '\OC\Setup\OCI', + 'mssql' => '\OC\Setup\MSSQL', + 'sqlite' => '\OC\Setup\Sqlite', + 'sqlite3' => '\OC\Setup\Sqlite', + ); + + public static function getTrans(){ + return OC_L10N::get('lib'); + } + + public static function install($options) { + $l = self::getTrans(); + + $error = array(); + $dbtype = $options['dbtype']; + + if(empty($options['adminlogin'])) { + $error[] = $l->t('Set an admin username.'); + } + if(empty($options['adminpass'])) { + $error[] = $l->t('Set an admin password.'); + } + if(empty($options['directory'])) { + $options['directory'] = OC::$SERVERROOT."/data"; + } + + if (!isset(self::$dbSetupClasses[$dbtype])) { + $dbtype = 'sqlite'; + } + + $class = self::$dbSetupClasses[$dbtype]; + $dbSetup = new $class(self::getTrans(), 'db_structure.xml'); + $error = array_merge($error, $dbSetup->validate($options)); + + if(count($error) != 0) { + return $error; + } + + //no errors, good + $username = htmlspecialchars_decode($options['adminlogin']); + $password = htmlspecialchars_decode($options['adminpass']); + $datadir = htmlspecialchars_decode($options['directory']); + + if (OC_Util::runningOnWindows()) { + $datadir = rtrim(realpath($datadir), '\\'); + } + + //use sqlite3 when available, otherise sqlite2 will be used. + if($dbtype=='sqlite' and class_exists('SQLite3')) { + $dbtype='sqlite3'; + } + + //generate a random salt that is used to salt the local user passwords + $salt = OC_Util::generateRandomBytes(30); + OC_Config::setValue('passwordsalt', $salt); + + //write the config file + OC_Config::setValue('datadirectory', $datadir); + OC_Config::setValue('dbtype', $dbtype); + OC_Config::setValue('version', implode('.', OC_Util::getVersion())); + try { + $dbSetup->initialize($options); + $dbSetup->setupDatabase($username); + } catch (DatabaseSetupException $e) { + $error[] = array( + 'error' => $e->getMessage(), + 'hint' => $e->getHint() + ); + return($error); + } catch (Exception $e) { + $error[] = array( + 'error' => 'Error while trying to create admin user: ' . $e->getMessage(), + 'hint' => '' + ); + return($error); + } + + //create the user and group + try { + OC_User::createUser($username, $password); + } + catch(Exception $exception) { + $error[] = $exception->getMessage(); + } + + if(count($error) == 0) { + OC_Appconfig::setValue('core', 'installedat', microtime(true)); + OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true)); + OC_AppConfig::setValue('core', 'remote_core.css', '/core/minimizer.php'); + OC_AppConfig::setValue('core', 'remote_core.js', '/core/minimizer.php'); + + OC_Group::createGroup('admin'); + OC_Group::addToGroup($username, 'admin'); + OC_User::login($username, $password); + + //guess what this does + OC_Installer::installShippedApps(); + + //create htaccess files for apache hosts + if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) { + self::createHtaccess(); + } + + //and we are done + OC_Config::setValue('installed', true); + } + + return $error; + } + + /** + * create .htaccess files for apache hosts + */ + private static function createHtaccess() { + $content = "\n"; + $content.= "\n"; + $content.= "\n"; + $content.= "SetEnvIfNoCase ^Authorization$ \"(.+)\" XAUTHORIZATION=$1\n"; + $content.= "RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION\n"; + $content.= "\n"; + $content.= "\n"; + $content.= "\n"; + $content.= "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page + $content.= "ErrorDocument 404 ".OC::$WEBROOT."/core/templates/404.php\n";//custom 404 error page + $content.= "\n"; + $content.= "php_value upload_max_filesize 512M\n";//upload limit + $content.= "php_value post_max_size 512M\n"; + $content.= "php_value memory_limit 512M\n"; + $content.= "php_value mbstring.func_overload 0\n"; + $content.= "\n"; + $content.= " SetEnv htaccessWorking true\n"; + $content.= "\n"; + $content.= "\n"; + $content.= "\n"; + $content.= "RewriteEngine on\n"; + $content.= "RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n"; + $content.= "RewriteRule ^.well-known/host-meta /public.php?service=host-meta [QSA,L]\n"; + $content.= "RewriteRule ^.well-known/carddav /remote.php/carddav/ [R]\n"; + $content.= "RewriteRule ^.well-known/caldav /remote.php/caldav/ [R]\n"; + $content.= "RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]\n"; + $content.= "RewriteRule ^remote/(.*) remote.php [QSA,L]\n"; + $content.= "\n"; + $content.= "\n"; + $content.= "AddType image/svg+xml svg svgz\n"; + $content.= "AddEncoding gzip svgz\n"; + $content.= "\n"; + $content.= "\n"; + $content.= "DirectoryIndex index.php index.html\n"; + $content.= "\n"; + $content.= "AddDefaultCharset utf-8\n"; + $content.= "Options -Indexes\n"; + @file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it + + self::protectDataDirectory(); + } + + public static function protectDataDirectory() { + $content = "deny from all\n"; + $content.= "IndexIgnore *"; + file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content); + file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/index.html', ''); + } + + /** + * @brief Post installation checks + */ + public static function postSetupCheck($params) { + // setup was successful -> webdav testing now + $l = self::getTrans(); + if (OC_Util::isWebDAVWorking()) { + header("Location: ".OC::$WEBROOT.'/'); + } else { + + $error = $l->t('Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken.'); + $hint = $l->t('Please double check the installation guides.', + 'http://doc.owncloud.org/server/5.0/admin_manual/installation.html'); + + OC_Template::printErrorPage($error, $hint); + exit(); + } + } +} diff --git a/lib/private/setup/abstractdatabase.php b/lib/private/setup/abstractdatabase.php new file mode 100644 index 00000000000..0beada7bd29 --- /dev/null +++ b/lib/private/setup/abstractdatabase.php @@ -0,0 +1,50 @@ +trans = $trans; + $this->dbDefinitionFile = $dbDefinitionFile; + } + + public function validate($config) { + $errors = array(); + if(empty($config['dbuser'])) { + $errors[] = $this->trans->t("%s enter the database username.", array($this->dbprettyname)); + } + if(empty($config['dbname'])) { + $errors[] = $this->trans->t("%s enter the database name.", array($this->dbprettyname)); + } + if(substr_count($config['dbname'], '.') >= 1) { + $errors[] = $this->trans->t("%s you may not use dots in the database name", array($this->dbprettyname)); + } + return $errors; + } + + public function initialize($config) { + $dbuser = $config['dbuser']; + $dbpass = $config['dbpass']; + $dbname = $config['dbname']; + $dbhost = !empty($config['dbhost']) ? $config['dbhost'] : 'localhost'; + $dbtableprefix = isset($config['dbtableprefix']) ? $config['dbtableprefix'] : 'oc_'; + + \OC_Config::setValue('dbname', $dbname); + \OC_Config::setValue('dbhost', $dbhost); + \OC_Config::setValue('dbtableprefix', $dbtableprefix); + + $this->dbuser = $dbuser; + $this->dbpassword = $dbpass; + $this->dbname = $dbname; + $this->dbhost = $dbhost; + $this->tableprefix = $dbtableprefix; + } +} diff --git a/lib/private/setup/mssql.php b/lib/private/setup/mssql.php new file mode 100644 index 00000000000..b8329f99079 --- /dev/null +++ b/lib/private/setup/mssql.php @@ -0,0 +1,182 @@ + "master", "UID" => $this->dbuser, "PWD" => $this->dbpassword); + + $masterConnection = @sqlsrv_connect($this->dbhost, $masterConnectionInfo); + if(!$masterConnection) { + $entry = null; + if( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + throw new \DatabaseSetupException($this->trans->t('MS SQL username and/or password not valid: %s', array($entry)), + $this->trans->t('You need to enter either an existing account or the administrator.')); + } + + \OC_Config::setValue('dbuser', $this->dbuser); + \OC_Config::setValue('dbpassword', $this->dbpassword); + + $this->createDBLogin($masterConnection); + + $this->createDatabase($masterConnection); + + $this->createDBUser($masterConnection); + + sqlsrv_close($masterConnection); + + $this->createDatabaseStructure(); + } + + private function createDBLogin($connection) { + $query = "SELECT * FROM master.sys.server_principals WHERE name = '".$this->dbuser."';"; + $result = sqlsrv_query($connection, $query); + if ($result === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } else { + $row = sqlsrv_fetch_array($result); + + if ($row === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } else { + if ($row == null) { + $query = "CREATE LOGIN [".$this->dbuser."] WITH PASSWORD = '".$this->dbpassword."';"; + $result = sqlsrv_query($connection, $query); + if (!$result or $result === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } + } + } + } + } + + private function createDBUser($connection) { + $query = "SELECT * FROM [".$this->dbname."].sys.database_principals WHERE name = '".$this->dbuser."';"; + $result = sqlsrv_query($connection, $query); + if ($result === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } else { + $row = sqlsrv_fetch_array($result); + + if ($row === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } else { + if ($row == null) { + $query = "USE [".$this->dbname."]; CREATE USER [".$this->dbuser."] FOR LOGIN [".$this->dbuser."];"; + $result = sqlsrv_query($connection, $query); + if (!$result || $result === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry = 'DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } + } + + $query = "USE [".$this->dbname."]; EXEC sp_addrolemember 'db_owner', '".$this->dbuser."';"; + $result = sqlsrv_query($connection, $query); + if (!$result || $result === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } + } + } + } + + private function createDatabase($connection) { + $query = "CREATE DATABASE [".$this->dbname."];"; + $result = sqlsrv_query($connection, $query); + if (!$result || $result === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } + } + + private function createDatabaseStructure() { + $connectionInfo = array( "Database" => $this->dbname, "UID" => $this->dbuser, "PWD" => $this->dbpassword); + + $connection = @sqlsrv_connect($this->dbhost, $connectionInfo); + + //fill the database if needed + $query = "SELECT * FROM INFORMATION_SCHEMA.TABLES" + ." WHERE TABLE_SCHEMA = '".$this->dbname."'" + ." AND TABLE_NAME = '".$this->tableprefix."users'"; + $result = sqlsrv_query($connection, $query); + if ($result === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } else { + $row = sqlsrv_fetch_array($result); + + if ($row === false) { + if ( ($errors = sqlsrv_errors() ) != null) { + $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; + } else { + $entry = ''; + } + $entry.='Offending command was: '.$query.'
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } else { + if ($row == null) { + \OC_DB::createDbFromStructure($this->dbDefinitionFile); + } + } + } + + sqlsrv_close($connection); + } +} diff --git a/lib/private/setup/mysql.php b/lib/private/setup/mysql.php new file mode 100644 index 00000000000..d97b6d2602f --- /dev/null +++ b/lib/private/setup/mysql.php @@ -0,0 +1,95 @@ +dbhost, $this->dbuser, $this->dbpassword); + if(!$connection) { + throw new \DatabaseSetupException($this->trans->t('MySQL username and/or password not valid'), + $this->trans->t('You need to enter either an existing account or the administrator.')); + } + $oldUser=\OC_Config::getValue('dbuser', false); + + //this should be enough to check for admin rights in mysql + $query="SELECT user FROM mysql.user WHERE user='$this->dbuser'"; + if(mysql_query($query, $connection)) { + //use the admin login data for the new database user + + //add prefix to the mysql user name to prevent collisions + $this->dbuser=substr('oc_'.$username, 0, 16); + if($this->dbuser!=$oldUser) { + //hash the password so we don't need to store the admin config in the config file + $this->dbpassword=\OC_Util::generateRandomBytes(30); + + $this->createDBUser($connection); + + \OC_Config::setValue('dbuser', $this->dbuser); + \OC_Config::setValue('dbpassword', $this->dbpassword); + } + + //create the database + $this->createDatabase($connection); + } + else { + if($this->dbuser!=$oldUser) { + \OC_Config::setValue('dbuser', $this->dbuser); + \OC_Config::setValue('dbpassword', $this->dbpassword); + } + + //create the database + $this->createDatabase($connection); + } + + //fill the database if needed + $query='select count(*) from information_schema.tables' + ." where table_schema='".$this->dbname."' AND table_name = '".$this->tableprefix."users';"; + $result = mysql_query($query, $connection); + if($result) { + $row=mysql_fetch_row($result); + } + if(!$result or $row[0]==0) { + \OC_DB::createDbFromStructure($this->dbDefinitionFile); + } + mysql_close($connection); + } + + private function createDatabase($connection) { + $name = $this->dbname; + $user = $this->dbuser; + //we cant use OC_BD functions here because we need to connect as the administrative user. + $query = "CREATE DATABASE IF NOT EXISTS `$name`"; + $result = mysql_query($query, $connection); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(mysql_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); + } + $query="GRANT ALL PRIVILEGES ON `$name` . * TO '$user'"; + + //this query will fail if there aren't the right permissions, ignore the error + mysql_query($query, $connection); + } + + private function createDBUser($connection) { + $name = $this->dbuser; + $password = $this->dbpassword; + // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one, + // the anonymous user would take precedence when there is one. + $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; + $result = mysql_query($query, $connection); + if (!$result) { + throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'localhost' exists already.", array($name)), + $this->trans->t("Drop this user from MySQL", array($name))); + } + $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; + $result = mysql_query($query, $connection); + if (!$result) { + throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'%%' already exists", array($name)), + $this->trans->t("Drop this user from MySQL.")); + } + } +} diff --git a/lib/private/setup/oci.php b/lib/private/setup/oci.php new file mode 100644 index 00000000000..326d7a00531 --- /dev/null +++ b/lib/private/setup/oci.php @@ -0,0 +1,210 @@ +dbtablespace = $config['dbtablespace']; + } else { + $this->dbtablespace = 'USERS'; + } + \OC_Config::setValue('dbtablespace', $this->dbtablespace); + } + + public function setupDatabase($username) { + $e_host = addslashes($this->dbhost); + $e_dbname = addslashes($this->dbname); + //check if the database user has admin right + if ($e_host == '') { + $easy_connect_string = $e_dbname; // use dbname as easy connect name + } else { + $easy_connect_string = '//'.$e_host.'/'.$e_dbname; + } + \OC_Log::write('setup oracle', 'connect string: ' . $easy_connect_string, \OC_Log::DEBUG); + $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string); + if(!$connection) { + $e = oci_error(); + if (is_array ($e) && isset ($e['message'])) { + throw new \DatabaseSetupException($this->trans->t('Oracle connection could not be established'), + $e['message'].' Check environment: ORACLE_HOME='.getenv('ORACLE_HOME') + .' ORACLE_SID='.getenv('ORACLE_SID') + .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH') + .' NLS_LANG='.getenv('NLS_LANG') + .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable'); + } + throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), + 'Check environment: ORACLE_HOME='.getenv('ORACLE_HOME') + .' ORACLE_SID='.getenv('ORACLE_SID') + .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH') + .' NLS_LANG='.getenv('NLS_LANG') + .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable'); + } + //check for roles creation rights in oracle + + $query='SELECT count(*) FROM user_role_privs, role_sys_privs' + ." WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'"; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_last_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + $result = oci_execute($stmt); + if($result) { + $row = oci_fetch_row($stmt); + } + if($result and $row[0] > 0) { + //use the admin login data for the new database user + + //add prefix to the oracle user name to prevent collisions + $this->dbuser='oc_'.$username; + //create a new password so we don't need to store the admin config in the config file + $this->dbpassword=\OC_Util::generateRandomBytes(30); + + //oracle passwords are treated as identifiers: + // must start with aphanumeric char + // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length. + $this->dbpassword=substr($this->dbpassword, 0, 30); + + $this->createDBUser($connection); + + \OC_Config::setValue('dbuser', $this->dbusername); + \OC_Config::setValue('dbname', $this->dbusername); + \OC_Config::setValue('dbpassword', $this->dbpassword); + + //create the database not neccessary, oracle implies user = schema + //$this->createDatabase($this->dbname, $this->dbusername, $connection); + } else { + + \OC_Config::setValue('dbuser', $this->dbuser); + \OC_Config::setValue('dbname', $this->dbname); + \OC_Config::setValue('dbpassword', $this->dbpassword); + + //create the database not neccessary, oracle implies user = schema + //$this->createDatabase($this->dbname, $this->dbuser, $connection); + } + + //FIXME check tablespace exists: select * from user_tablespaces + + // the connection to dbname=oracle is not needed anymore + oci_close($connection); + + // connect to the oracle database (schema=$this->dbuser) an check if the schema needs to be filled + $this->dbuser = \OC_Config::getValue('dbuser'); + //$this->dbname = \OC_Config::getValue('dbname'); + $this->dbpassword = \OC_Config::getValue('dbpassword'); + + $e_host = addslashes($this->dbhost); + $e_dbname = addslashes($this->dbname); + + if ($e_host == '') { + $easy_connect_string = $e_dbname; // use dbname as easy connect name + } else { + $easy_connect_string = '//'.$e_host.'/'.$e_dbname; + } + $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string); + if(!$connection) { + throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), + $this->trans->t('You need to enter either an existing account or the administrator.')); + } + $query = "SELECT count(*) FROM user_tables WHERE table_name = :un"; + $stmt = oci_parse($connection, $query); + $un = $this->dbtableprefix.'users'; + oci_bind_by_name($stmt, ':un', $un); + if (!$stmt) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + $result = oci_execute($stmt); + + if($result) { + $row = oci_fetch_row($stmt); + } + if(!$result or $row[0]==0) { + \OC_DB::createDbFromStructure($this->dbDefinitionFile); + } + } + + /** + * + * @param String $name + * @param String $password + * @param resource $connection + */ + private function createDBUser($connection) { + $name = $this->dbuser; + $password = $this->password; + $query = "SELECT * FROM all_users WHERE USERNAME = :un"; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + oci_bind_by_name($stmt, ':un', $name); + $result = oci_execute($stmt); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + + if(! oci_fetch_row($stmt)) { + //user does not exists let's create it :) + //password must start with alphabetic character in oracle + $query = 'CREATE USER '.$name.' IDENTIFIED BY "'.$password.'" DEFAULT TABLESPACE '.$this->dbtablespace; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + //oci_bind_by_name($stmt, ':un', $name); + $result = oci_execute($stmt); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s', + array($query, $name, $password)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + } else { // change password of the existing role + $query = "ALTER USER :un IDENTIFIED BY :pw"; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + oci_bind_by_name($stmt, ':un', $name); + oci_bind_by_name($stmt, ':pw', $password); + $result = oci_execute($stmt); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + } + // grant necessary roles + $query = 'GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER, UNLIMITED TABLESPACE TO '.$name; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + $result = oci_execute($stmt); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s', + array($query, $name, $password)) . '
'; + \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); + } + } +} diff --git a/lib/private/setup/postgresql.php b/lib/private/setup/postgresql.php new file mode 100644 index 00000000000..89d328ada19 --- /dev/null +++ b/lib/private/setup/postgresql.php @@ -0,0 +1,140 @@ +dbhost); + $e_user = addslashes($this->dbuser); + $e_password = addslashes($this->dbpassword); + + //check if the database user has admin rights + $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'"; + $connection = @pg_connect($connection_string); + if(!$connection) { + // Try if we can connect to the DB with the specified name + $e_dbname = addslashes($this->dbname); + $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'"; + $connection = @pg_connect($connection_string); + + if(!$connection) + throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), + $this->trans->t('You need to enter either an existing account or the administrator.')); + } + $e_user = pg_escape_string($this->dbuser); + //check for roles creation rights in postgresql + $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'"; + $result = pg_query($connection, $query); + if($result and pg_num_rows($result) > 0) { + //use the admin login data for the new database user + + //add prefix to the postgresql user name to prevent collisions + $this->dbuser='oc_'.$username; + //create a new password so we don't need to store the admin config in the config file + $this->dbpassword=\OC_Util::generateRandomBytes(30); + + $this->createDBUser($connection); + + \OC_Config::setValue('dbuser', $this->dbuser); + \OC_Config::setValue('dbpassword', $this->dbpassword); + + //create the database + $this->createDatabase($connection); + } + else { + \OC_Config::setValue('dbuser', $this->dbuser); + \OC_Config::setValue('dbpassword', $this->dbpassword); + + //create the database + $this->createDatabase($connection); + } + + // the connection to dbname=postgres is not needed anymore + pg_close($connection); + + // connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled + $this->dbuser = \OC_Config::getValue('dbuser'); + $this->dbpassword = \OC_Config::getValue('dbpassword'); + + $e_host = addslashes($this->dbhost); + $e_dbname = addslashes($this->dbname); + $e_user = addslashes($this->dbuser); + $e_password = addslashes($this->dbpassword); + + $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'"; + $connection = @pg_connect($connection_string); + if(!$connection) { + throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), + $this->trans->t('You need to enter either an existing account or the administrator.')); + } + $query = "select count(*) FROM pg_class WHERE relname='".$this->tableprefix."users' limit 1"; + $result = pg_query($connection, $query); + if($result) { + $row = pg_fetch_row($result); + } + if(!$result or $row[0]==0) { + \OC_DB::createDbFromStructure($this->dbDefinitionFile); + } + } + + private function createDatabase($connection) { + //we cant use OC_BD functions here because we need to connect as the administrative user. + $e_name = pg_escape_string($this->dbname); + $e_user = pg_escape_string($this->dbuser); + $query = "select datname from pg_database where datname = '$e_name'"; + $result = pg_query($connection, $query); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); + } + if(! pg_fetch_row($result)) { + //The database does not exists... let's create it + $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\""; + $result = pg_query($connection, $query); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); + } + else { + $query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC"; + pg_query($connection, $query); + } + } + } + + private function createDBUser($connection) { + $e_name = pg_escape_string($this->dbuser); + $e_password = pg_escape_string($this->dbpassword); + $query = "select * from pg_roles where rolname='$e_name';"; + $result = pg_query($connection, $query); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); + } + + if(! pg_fetch_row($result)) { + //user does not exists let's create it :) + $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';"; + $result = pg_query($connection, $query); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); + } + } + else { // change password of the existing role + $query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';"; + $result = pg_query($connection, $query); + if(!$result) { + $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; + $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; + \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); + } + } + } +} diff --git a/lib/private/setup/sqlite.php b/lib/private/setup/sqlite.php new file mode 100644 index 00000000000..fd4df792d62 --- /dev/null +++ b/lib/private/setup/sqlite.php @@ -0,0 +1,26 @@ +dbDefinitionFile); + } +} diff --git a/lib/private/subadmin.php b/lib/private/subadmin.php new file mode 100644 index 00000000000..8cda7240ac9 --- /dev/null +++ b/lib/private/subadmin.php @@ -0,0 +1,189 @@ +. + * + */ +OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_SubAdmin', 'post_deleteUser'); +OC_Hook::connect('OC_User', 'post_deleteGroup', 'OC_SubAdmin', 'post_deleteGroup'); +/** + * This class provides all methods needed for managing groups. + * + * Hooks provided: + * post_createSubAdmin($gid) + * post_deleteSubAdmin($gid) + */ +class OC_SubAdmin{ + + /** + * @brief add a SubAdmin + * @param $uid uid of the SubAdmin + * @param $gid gid of the group + * @return boolean + */ + public static function createSubAdmin($uid, $gid) { + $stmt = OC_DB::prepare('INSERT INTO `*PREFIX*group_admin` (`gid`,`uid`) VALUES(?,?)'); + $result = $stmt->execute(array($gid, $uid)); + OC_Hook::emit( "OC_SubAdmin", "post_createSubAdmin", array( "gid" => $gid )); + return true; + } + + /** + * @brief delete a SubAdmin + * @param $uid uid of the SubAdmin + * @param $gid gid of the group + * @return boolean + */ + public static function deleteSubAdmin($uid, $gid) { + $stmt = OC_DB::prepare('DELETE FROM `*PREFIX*group_admin` WHERE `gid` = ? AND `uid` = ?'); + $result = $stmt->execute(array($gid, $uid)); + OC_Hook::emit( "OC_SubAdmin", "post_deleteSubAdmin", array( "gid" => $gid )); + return true; + } + + /** + * @brief get groups of a SubAdmin + * @param $uid uid of the SubAdmin + * @return array + */ + public static function getSubAdminsGroups($uid) { + $stmt = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*group_admin` WHERE `uid` = ?'); + $result = $stmt->execute(array($uid)); + $gids = array(); + while($row = $result->fetchRow()) { + $gids[] = $row['gid']; + } + return $gids; + } + + /** + * @brief get SubAdmins of a group + * @param $gid gid of the group + * @return array + */ + public static function getGroupsSubAdmins($gid) { + $stmt = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*group_admin` WHERE `gid` = ?'); + $result = $stmt->execute(array($gid)); + $uids = array(); + while($row = $result->fetchRow()) { + $uids[] = $row['uid']; + } + return $uids; + } + + /** + * @brief get all SubAdmins + * @return array + */ + public static function getAllSubAdmins() { + $stmt = OC_DB::prepare('SELECT * FROM `*PREFIX*group_admin`'); + $result = $stmt->execute(); + $subadmins = array(); + while($row = $result->fetchRow()) { + $subadmins[] = $row; + } + return $subadmins; + } + + /** + * @brief checks if a user is a SubAdmin of a group + * @param $uid uid of the subadmin + * @param $gid gid of the group + * @return bool + */ + public static function isSubAdminofGroup($uid, $gid) { + $stmt = OC_DB::prepare('SELECT COUNT(*) AS `count` FROM `*PREFIX*group_admin` WHERE `uid` = ? AND `gid` = ?'); + $result = $stmt->execute(array($uid, $gid)); + $result = $result->fetchRow(); + if($result['count'] >= 1) { + return true; + } + return false; + } + + /** + * @brief checks if a user is a SubAdmin + * @param $uid uid of the subadmin + * @return bool + */ + public static function isSubAdmin($uid) { + // Check if the user is already an admin + if(OC_Group::inGroup($uid, 'admin' )) { + return true; + } + + $stmt = OC_DB::prepare('SELECT COUNT(*) AS `count` FROM `*PREFIX*group_admin` WHERE `uid` = ?'); + $result = $stmt->execute(array($uid)); + $result = $result->fetchRow(); + if($result['count'] > 0) { + return true; + } + return false; + } + + /** + * @brief checks if a user is a accessible by a subadmin + * @param $subadmin uid of the subadmin + * @param $user uid of the user + * @return bool + */ + public static function isUserAccessible($subadmin, $user) { + if(!self::isSubAdmin($subadmin)) { + return false; + } + if(OC_User::isAdminUser($user)) { + return false; + } + $accessiblegroups = self::getSubAdminsGroups($subadmin); + foreach($accessiblegroups as $accessiblegroup) { + if(OC_Group::inGroup($user, $accessiblegroup)) { + return true; + } + } + return false; + } + + /* + * @brief alias for self::isSubAdminofGroup() + */ + public static function isGroupAccessible($subadmin, $group) { + return self::isSubAdminofGroup($subadmin, $group); + } + + /** + * @brief delete all SubAdmins by uid + * @param $parameters + * @return boolean + */ + public static function post_deleteUser($parameters) { + $stmt = OC_DB::prepare('DELETE FROM `*PREFIX*group_admin` WHERE `uid` = ?'); + $result = $stmt->execute(array($parameters['uid'])); + return true; + } + + /** + * @brief delete all SubAdmins by gid + * @param $parameters + * @return boolean + */ + public static function post_deleteGroup($parameters) { + $stmt = OC_DB::prepare('DELETE FROM `*PREFIX*group_admin` WHERE `gid` = ?'); + $result = $stmt->execute(array($parameters['gid'])); + return true; + } +} diff --git a/lib/private/template.php b/lib/private/template.php new file mode 100644 index 00000000000..9b2c1211e61 --- /dev/null +++ b/lib/private/template.php @@ -0,0 +1,311 @@ +. + * + */ + +require_once __DIR__.'/template/functions.php'; + +/** + * This class provides the templates for ownCloud. + */ +class OC_Template extends \OC\Template\Base { + private $renderas; // Create a full page? + private $path; // The path to the template + private $headers=array(); //custom headers + + /** + * @brief Constructor + * @param string $app app providing the template + * @param string $name of the template file (without suffix) + * @param string $renderas = ""; produce a full page + * @return OC_Template object + * + * This function creates an OC_Template object. + * + * If $renderas is set, OC_Template will try to produce a full page in the + * according layout. For now, renderas can be set to "guest", "user" or + * "admin". + */ + public function __construct( $app, $name, $renderas = "" ) { + // Read the selected theme from the config file + $theme = OC_Util::getTheme(); + + // Read the detected formfactor and use the right file name. + $fext = self::getFormFactorExtension(); + + $requesttoken = OC::$session ? OC_Util::callRegister() : ''; + + $parts = explode('/', $app); // fix translation when app is something like core/lostpassword + $l10n = OC_L10N::get($parts[0]); + $themeDefaults = new OC_Defaults(); + + list($path, $template) = $this->findTemplate($theme, $app, $name, $fext); + + // Set the private data + $this->renderas = $renderas; + $this->path = $path; + + parent::__construct($template, $requesttoken, $l10n, $themeDefaults); + + // Some headers to enhance security + header('X-XSS-Protection: 1; mode=block'); // Enforce browser based XSS filters + header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE + + // iFrame Restriction Policy + $xFramePolicy = OC_Config::getValue('xframe_restriction', true); + if($xFramePolicy) { + header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains + } + + // Content Security Policy + // If you change the standard policy, please also change it in config.sample.php + $policy = OC_Config::getValue('custom_csp_policy', + 'default-src \'self\'; ' + .'script-src \'self\' \'unsafe-eval\'; ' + .'style-src \'self\' \'unsafe-inline\'; ' + .'frame-src *; ' + .'img-src *; ' + .'font-src \'self\' data:; ' + .'media-src *'); + header('Content-Security-Policy:'.$policy); // Standard + + } + + /** + * autodetect the formfactor of the used device + * default -> the normal desktop browser interface + * mobile -> interface for smartphones + * tablet -> interface for tablets + * standalone -> the default interface but without header, footer and + * sidebar, just the application. Useful to use just a specific + * app on the desktop in a standalone window. + */ + public static function detectFormfactor() { + // please add more useragent strings for other devices + if(isset($_SERVER['HTTP_USER_AGENT'])) { + if(stripos($_SERVER['HTTP_USER_AGENT'], 'ipad')>0) { + $mode='tablet'; + }elseif(stripos($_SERVER['HTTP_USER_AGENT'], 'iphone')>0) { + $mode='mobile'; + }elseif((stripos($_SERVER['HTTP_USER_AGENT'], 'N9')>0) + and (stripos($_SERVER['HTTP_USER_AGENT'], 'nokia')>0)) { + $mode='mobile'; + }else{ + $mode='default'; + } + }else{ + $mode='default'; + } + return($mode); + } + + /** + * @brief Returns the formfactor extension for current formfactor + */ + static public function getFormFactorExtension() + { + if (!\OC::$session) { + return ''; + } + // if the formfactor is not yet autodetected do the + // autodetection now. For possible formfactors check the + // detectFormfactor documentation + if (!\OC::$session->exists('formfactor')) { + \OC::$session->set('formfactor', self::detectFormfactor()); + } + // allow manual override via GET parameter + if(isset($_GET['formfactor'])) { + \OC::$session->set('formfactor', $_GET['formfactor']); + } + $formfactor = \OC::$session->get('formfactor'); + if($formfactor==='default') { + $fext=''; + }elseif($formfactor==='mobile') { + $fext='.mobile'; + }elseif($formfactor==='tablet') { + $fext='.tablet'; + }elseif($formfactor==='standalone') { + $fext='.standalone'; + }else{ + $fext=''; + } + return $fext; + } + + /** + * @brief find the template with the given name + * @param string $name of the template file (without suffix) + * + * Will select the template file for the selected theme and formfactor. + * Checking all the possible locations. + */ + protected function findTemplate($theme, $app, $name, $fext) { + // Check if it is a app template or not. + if( $app !== '' ) { + $dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app)); + } else { + $dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT); + } + $locator = new \OC\Template\TemplateFileLocator( $fext, $dirs ); + $template = $locator->find($name); + $path = $locator->getPath(); + return array($path, $template); + } + + /** + * @brief Add a custom element to the header + * @param string $tag tag name of the element + * @param array $attributes array of attributes for the element + * @param string $text the text content for the element + */ + public function addHeader( $tag, $attributes, $text='') { + $this->headers[]=array('tag'=>$tag,'attributes'=>$attributes, 'text'=>$text); + } + + /** + * @brief Process the template + * @return bool + * + * This function process the template. If $this->renderas is set, it + * will produce a full page. + */ + public function fetchPage() { + $data = parent::fetchPage(); + + if( $this->renderas ) { + $page = new OC_TemplateLayout($this->renderas); + + // Add custom headers + $page->assign('headers', $this->headers, false); + foreach(OC_Util::$headers as $header) { + $page->append('headers', $header); + } + + $page->assign( "content", $data, false ); + return $page->fetchPage(); + } + else{ + return $data; + } + } + + /** + * @brief Include template + * @return string returns content of included template + * + * Includes another template. use inc('template'); ?> to + * do this. + */ + public function inc( $file, $additionalparams = null ) { + return $this->load($this->path.$file.'.php', $additionalparams); + } + + /** + * @brief Shortcut to print a simple page for users + * @param string $application The application we render the template for + * @param string $name Name of the template + * @param array $parameters Parameters for the template + * @return bool + */ + public static function printUserPage( $application, $name, $parameters = array() ) { + $content = new OC_Template( $application, $name, "user" ); + foreach( $parameters as $key => $value ) { + $content->assign( $key, $value ); + } + print $content->printPage(); + } + + /** + * @brief Shortcut to print a simple page for admins + * @param string $application The application we render the template for + * @param string $name Name of the template + * @param array $parameters Parameters for the template + * @return bool + */ + public static function printAdminPage( $application, $name, $parameters = array() ) { + $content = new OC_Template( $application, $name, "admin" ); + foreach( $parameters as $key => $value ) { + $content->assign( $key, $value ); + } + return $content->printPage(); + } + + /** + * @brief Shortcut to print a simple page for guests + * @param string $application The application we render the template for + * @param string $name Name of the template + * @param string $parameters Parameters for the template + * @return bool + */ + public static function printGuestPage( $application, $name, $parameters = array() ) { + $content = new OC_Template( $application, $name, "guest" ); + foreach( $parameters as $key => $value ) { + $content->assign( $key, $value ); + } + return $content->printPage(); + } + + /** + * @brief Print a fatal error page and terminates the script + * @param string $error_msg The error message to show + * @param string $hint An optional hint message + * Warning: All data passed to $hint needs to get sanitized using OC_Util::sanitizeHTML + */ + public static function printErrorPage( $error_msg, $hint = '' ) { + $content = new OC_Template( '', 'error', 'error' ); + $errors = array(array('error' => $error_msg, 'hint' => $hint)); + $content->assign( 'errors', $errors ); + $content->printPage(); + die(); + } + + /** + * print error page using Exception details + * @param Exception $exception + */ + + public static function printExceptionErrorPage(Exception $exception) { + $error_msg = $exception->getMessage(); + if ($exception->getCode()) { + $error_msg = '['.$exception->getCode().'] '.$error_msg; + } + if (defined('DEBUG') and DEBUG) { + $hint = $exception->getTraceAsString(); + if (!empty($hint)) { + $hint = '
'.$hint.'
'; + } + $l = OC_L10N::get('lib'); + while (method_exists($exception, 'previous') && $exception = $exception->previous()) { + $error_msg .= '
'.$l->t('Caused by:').' '; + if ($exception->getCode()) { + $error_msg .= '['.$exception->getCode().'] '; + } + $error_msg .= $exception->getMessage(); + }; + } else { + $hint = ''; + if ($exception instanceof \OC\HintException) { + $hint = $exception->getHint(); + } + } + self::printErrorPage($error_msg, $hint); + } +} diff --git a/lib/private/template/base.php b/lib/private/template/base.php new file mode 100644 index 00000000000..88941bc7132 --- /dev/null +++ b/lib/private/template/base.php @@ -0,0 +1,134 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Template; + +class Base { + private $template; // The template + private $vars; // Vars + private $l10n; // The l10n-Object + private $theme; // theme defaults + + public function __construct( $template, $requesttoken, $l10n, $theme ) { + $this->vars = array(); + $this->vars['requesttoken'] = $requesttoken; + $this->l10n = $l10n; + $this->template = $template; + $this->theme = $theme; + } + + protected function getAppTemplateDirs($theme, $app, $serverroot, $app_dir) { + // Check if the app is in the app folder or in the root + if( file_exists($app_dir.'/templates/' )) { + return array( + $serverroot.'/themes/'.$theme.'/apps/'.$app.'/templates/', + $app_dir.'/templates/', + ); + } + return array( + $serverroot.'/themes/'.$theme.'/'.$app.'/templates/', + $serverroot.'/'.$app.'/templates/', + ); + } + + protected function getCoreTemplateDirs($theme, $serverroot) { + return array( + $serverroot.'/themes/'.$theme.'/core/templates/', + $serverroot.'/core/templates/', + ); + } + + /** + * @brief Assign variables + * @param string $key key + * @param string $value value + * @return bool + * + * This function assigns a variable. It can be accessed via $_[$key] in + * the template. + * + * If the key existed before, it will be overwritten + */ + public function assign( $key, $value) { + $this->vars[$key] = $value; + return true; + } + + /** + * @brief Appends a variable + * @param string $key key + * @param string $value value + * @return bool + * + * This function assigns a variable in an array context. If the key already + * exists, the value will be appended. It can be accessed via + * $_[$key][$position] in the template. + */ + public function append( $key, $value ) { + if( array_key_exists( $key, $this->vars )) { + $this->vars[$key][] = $value; + } + else{ + $this->vars[$key] = array( $value ); + } + } + + /** + * @brief Prints the proceeded template + * @return bool + * + * This function proceeds the template and prints its output. + */ + public function printPage() { + $data = $this->fetchPage(); + if( $data === false ) { + return false; + } + else{ + print $data; + return true; + } + } + + /** + * @brief Process the template + * @return bool + * + * This function processes the template. + */ + public function fetchPage() { + return $this->load($this->template); + } + + /** + * @brief doing the actual work + * @return string content + * + * Includes the template file, fetches its output + */ + protected function load( $file, $additionalparams = null ) { + // Register the variables + $_ = $this->vars; + $l = $this->l10n; + $theme = $this->theme; + + if( !is_null($additionalparams)) { + $_ = array_merge( $additionalparams, $this->vars ); + } + + // Include + ob_start(); + include $file; + $data = ob_get_contents(); + @ob_end_clean(); + + // Return data + return $data; + } + +} diff --git a/lib/private/template/cssresourcelocator.php b/lib/private/template/cssresourcelocator.php new file mode 100644 index 00000000000..8e7831ca549 --- /dev/null +++ b/lib/private/template/cssresourcelocator.php @@ -0,0 +1,43 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Template; + +class CSSResourceLocator extends ResourceLocator { + public function doFind( $style ) { + if (strpos($style, '3rdparty') === 0 + && $this->appendIfExist($this->thirdpartyroot, $style.'.css') + || $this->appendIfExist($this->serverroot, $style.$this->form_factor.'.css') + || $this->appendIfExist($this->serverroot, $style.'.css') + || $this->appendIfExist($this->serverroot, 'core/'.$style.$this->form_factor.'.css') + || $this->appendIfExist($this->serverroot, 'core/'.$style.'.css') + ) { + return; + } + $app = substr($style, 0, strpos($style, '/')); + $style = substr($style, strpos($style, '/')+1); + $app_path = \OC_App::getAppPath($app); + $app_url = $this->webroot . '/index.php/apps/' . $app; + if ($this->appendIfExist($app_path, $style.$this->form_factor.'.css', $app_url) + || $this->appendIfExist($app_path, $style.'.css', $app_url) + ) { + return; + } + throw new \Exception('css file not found: style:'.$style); + } + + public function doFindTheme( $style ) { + $theme_dir = 'themes/'.$this->theme.'/'; + $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.$this->form_factor.'.css') + || $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.'.css') + || $this->appendIfExist($this->serverroot, $theme_dir.$style.$this->form_factor.'.css') + || $this->appendIfExist($this->serverroot, $theme_dir.$style.'.css') + || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.$this->form_factor.'.css') + || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.'.css'); + } +} diff --git a/lib/private/template/functions.php b/lib/private/template/functions.php new file mode 100644 index 00000000000..501f8081bff --- /dev/null +++ b/lib/private/template/functions.php @@ -0,0 +1,134 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Prints an XSS escaped string + * @param string $string the string which will be escaped and printed + */ +function p($string) { + print(OC_Util::sanitizeHTML($string)); +} + +/** + * Prints an unescaped string + * @param string $string the string which will be printed as it is + */ +function print_unescaped($string) { + print($string); +} + +/** + * @brief make OC_Helper::linkTo available as a simple function + * @param string $app app + * @param string $file file + * @param array $args array with param=>value, will be appended to the returned url + * @return string link to the file + * + * For further information have a look at OC_Helper::linkTo + */ +function link_to( $app, $file, $args = array() ) { + return OC_Helper::linkTo( $app, $file, $args ); +} + +/** + * @brief make OC_Helper::imagePath available as a simple function + * @param string $app app + * @param string $image image + * @return string link to the image + * + * For further information have a look at OC_Helper::imagePath + */ +function image_path( $app, $image ) { + return OC_Helper::imagePath( $app, $image ); +} + +/** + * @brief make OC_Helper::mimetypeIcon available as a simple function + * @param string $mimetype mimetype + * @return string link to the image + * + * For further information have a look at OC_Helper::mimetypeIcon + */ +function mimetype_icon( $mimetype ) { + return OC_Helper::mimetypeIcon( $mimetype ); +} + +/** + * @brief make preview_icon available as a simple function + * Returns the path to the preview of the image. + * @param $path path of file + * @returns link to the preview + * + * For further information have a look at OC_Helper::previewIcon + */ +function preview_icon( $path ) { + return OC_Helper::previewIcon( $path ); +} + +function publicPreview_icon ( $path, $token ) { + return OC_Helper::publicPreviewIcon( $path, $token ); +} + +/** + * @brief make OC_Helper::humanFileSize available as a simple function + * @param int $bytes size in bytes + * @return string size as string + * + * For further information have a look at OC_Helper::humanFileSize + */ +function human_file_size( $bytes ) { + return OC_Helper::humanFileSize( $bytes ); +} + +function relative_modified_date($timestamp) { + $l=OC_L10N::get('lib'); + $timediff = time() - $timestamp; + $diffminutes = round($timediff/60); + $diffhours = round($diffminutes/60); + $diffdays = round($diffhours/24); + $diffmonths = round($diffdays/31); + + if($timediff < 60) { return $l->t('seconds ago'); } + else if($timediff < 3600) { return $l->n('%n minute ago', '%n minutes ago', $diffminutes); } + else if($timediff < 86400) { return $l->n('%n hour ago', '%n hours ago', $diffhours); } + else if((date('G')-$diffhours) > 0) { return $l->t('today'); } + else if((date('G')-$diffhours) > -24) { return $l->t('yesterday'); } + else if($timediff < 2678400) { return $l->n('%n day go', '%n days ago', $diffdays); } + else if($timediff < 5184000) { return $l->t('last month'); } + else if((date('n')-$diffmonths) > 0) { return $l->n('%n month ago', '%n months ago', $diffmonths); } + else if($timediff < 63113852) { return $l->t('last year'); } + else { return $l->t('years ago'); } +} + +function html_select_options($options, $selected, $params=array()) { + if (!is_array($selected)) { + $selected=array($selected); + } + if (isset($params['combine']) && $params['combine']) { + $options = array_combine($options, $options); + } + $value_name = $label_name = false; + if (isset($params['value'])) { + $value_name = $params['value']; + } + if (isset($params['label'])) { + $label_name = $params['label']; + } + $html = ''; + foreach($options as $value => $label) { + if ($value_name && is_array($label)) { + $value = $label[$value_name]; + } + if ($label_name && is_array($label)) { + $label = $label[$label_name]; + } + $select = in_array($value, $selected) ? ' selected="selected"' : ''; + $html .= ''."\n"; + } + return $html; +} diff --git a/lib/private/template/jsresourcelocator.php b/lib/private/template/jsresourcelocator.php new file mode 100644 index 00000000000..f8fe3817ce6 --- /dev/null +++ b/lib/private/template/jsresourcelocator.php @@ -0,0 +1,43 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Template; + +class JSResourceLocator extends ResourceLocator { + public function doFind( $script ) { + $theme_dir = 'themes/'.$this->theme.'/'; + if (strpos($script, '3rdparty') === 0 + && $this->appendIfExist($this->thirdpartyroot, $script.'.js') + || $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.$this->form_factor.'.js') + || $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js') + || $this->appendIfExist($this->serverroot, $theme_dir.$script.$this->form_factor.'.js') + || $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js') + || $this->appendIfExist($this->serverroot, $script.$this->form_factor.'.js') + || $this->appendIfExist($this->serverroot, $script.'.js') + || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.$this->form_factor.'.js') + || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js') + || $this->appendIfExist($this->serverroot, 'core/'.$script.$this->form_factor.'.js') + || $this->appendIfExist($this->serverroot, 'core/'.$script.'.js') + ) { + return; + } + $app = substr($script, 0, strpos($script, '/')); + $script = substr($script, strpos($script, '/')+1); + $app_path = \OC_App::getAppPath($app); + $app_url = \OC_App::getAppWebPath($app); + if ($this->appendIfExist($app_path, $script.$this->form_factor.'.js', $app_url) + || $this->appendIfExist($app_path, $script.'.js', $app_url) + ) { + return; + } + throw new \Exception('js file not found: script:'.$script); + } + + public function doFindTheme( $script ) { + } +} diff --git a/lib/private/template/resourcelocator.php b/lib/private/template/resourcelocator.php new file mode 100644 index 00000000000..9f83673664d --- /dev/null +++ b/lib/private/template/resourcelocator.php @@ -0,0 +1,70 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Template; + +abstract class ResourceLocator { + protected $theme; + protected $form_factor; + + protected $mapping; + protected $serverroot; + protected $thirdpartyroot; + protected $webroot; + + protected $resources = array(); + + public function __construct( $theme, $form_factor, $core_map, $party_map ) { + $this->theme = $theme; + $this->form_factor = $form_factor; + $this->mapping = $core_map + $party_map; + $this->serverroot = key($core_map); + $this->thirdpartyroot = key($party_map); + $this->webroot = $this->mapping[$this->serverroot]; + } + + abstract public function doFind( $resource ); + abstract public function doFindTheme( $resource ); + + public function find( $resources ) { + try { + foreach($resources as $resource) { + $this->doFind($resource); + } + if (!empty($this->theme)) { + foreach($resources as $resource) { + $this->doFindTheme($resource); + } + } + } catch (\Exception $e) { + throw new \Exception($e->getMessage().' formfactor:'.$this->form_factor + .' serverroot:'.$this->serverroot); + } + } + + /* + * @brief append the $file resource if exist at $root + * @param $root path to check + * @param $file the filename + * @param $web base for path, default map $root to $webroot + */ + protected function appendIfExist($root, $file, $webroot = null) { + if (is_file($root.'/'.$file)) { + if (!$webroot) { + $webroot = $this->mapping[$root]; + } + $this->resources[] = array($root, $webroot, $file); + return true; + } + return false; + } + + public function getResources() { + return $this->resources; + } +} diff --git a/lib/private/template/templatefilelocator.php b/lib/private/template/templatefilelocator.php new file mode 100644 index 00000000000..d5a484b1a14 --- /dev/null +++ b/lib/private/template/templatefilelocator.php @@ -0,0 +1,44 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Template; + +class TemplateFileLocator { + protected $form_factor; + protected $dirs; + private $path; + + public function __construct( $form_factor, $dirs ) { + $this->form_factor = $form_factor; + $this->dirs = $dirs; + } + + public function find( $template ) { + if ($template === '') { + throw new \InvalidArgumentException('Empty template name'); + } + + foreach($this->dirs as $dir) { + $file = $dir.$template.$this->form_factor.'.php'; + if (is_file($file)) { + $this->path = $dir; + return $file; + } + $file = $dir.$template.'.php'; + if (is_file($file)) { + $this->path = $dir; + return $file; + } + } + throw new \Exception('template file not found: template:'.$template.' formfactor:'.$this->form_factor); + } + + public function getPath() { + return $this->path; + } +} diff --git a/lib/private/templatelayout.php b/lib/private/templatelayout.php new file mode 100644 index 00000000000..625f3424a04 --- /dev/null +++ b/lib/private/templatelayout.php @@ -0,0 +1,114 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_TemplateLayout extends OC_Template { + public function __construct( $renderas ) { + // Decide which page we show + + if( $renderas == 'user' ) { + parent::__construct( 'core', 'layout.user' ); + if(in_array(OC_APP::getCurrentApp(), array('settings','admin', 'help'))!==false) { + $this->assign('bodyid', 'body-settings'); + }else{ + $this->assign('bodyid', 'body-user'); + } + + // Update notification + if(OC_Config::getValue('updatechecker', true) === true) { + $data=OC_Updater::check(); + if(isset($data['version']) && $data['version'] != '' and $data['version'] !== Array() && OC_User::isAdminUser(OC_User::getUser())) { + $this->assign('updateAvailable', true); + $this->assign('updateVersion', $data['versionstring']); + $this->assign('updateLink', $data['web']); + } else { + $this->assign('updateAvailable', false); // No update available or not an admin user + } + } else { + $this->assign('updateAvailable', false); // Update check is disabled + } + + // Add navigation entry + $this->assign( 'application', '', false ); + $navigation = OC_App::getNavigation(); + $this->assign( 'navigation', $navigation); + $this->assign( 'settingsnavigation', OC_App::getSettingsNavigation()); + foreach($navigation as $entry) { + if ($entry['active']) { + $this->assign( 'application', $entry['name'] ); + break; + } + } + $user_displayname = OC_User::getDisplayName(); + $this->assign( 'user_displayname', $user_displayname ); + $this->assign( 'user_uid', OC_User::getUser() ); + $this->assign('enableAvatars', \OC_Config::getValue('enable_avatars', true)); + } else if ($renderas == 'guest' || $renderas == 'error') { + parent::__construct('core', 'layout.guest'); + } else { + parent::__construct('core', 'layout.base'); + } + $versionParameter = '?v=' . md5(implode(OC_Util::getVersion())); + // Add the js files + $jsfiles = self::findJavascriptFiles(OC_Util::$scripts); + $this->assign('jsfiles', array(), false); + if (OC_Config::getValue('installed', false) && $renderas!='error') { + $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config') . $versionParameter); + } + if (!empty(OC_Util::$coreScripts)) { + $this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false) . $versionParameter); + } + foreach($jsfiles as $info) { + $root = $info[0]; + $web = $info[1]; + $file = $info[2]; + $this->append( 'jsfiles', $web.'/'.$file . $versionParameter); + } + + // Add the css files + $cssfiles = self::findStylesheetFiles(OC_Util::$styles); + $this->assign('cssfiles', array()); + if (!empty(OC_Util::$coreStyles)) { + $this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false) . $versionParameter); + } + foreach($cssfiles as $info) { + $root = $info[0]; + $web = $info[1]; + $file = $info[2]; + + $this->append( 'cssfiles', $web.'/'.$file . $versionParameter); + } + } + + static public function findStylesheetFiles($styles) { + // Read the selected theme from the config file + $theme = OC_Util::getTheme(); + + // Read the detected formfactor and use the right file name. + $fext = self::getFormFactorExtension(); + + $locator = new \OC\Template\CSSResourceLocator( $theme, $fext, + array( OC::$SERVERROOT => OC::$WEBROOT ), + array( OC::$THIRDPARTYROOT => OC::$THIRDPARTYWEBROOT )); + $locator->find($styles); + return $locator->getResources(); + } + + static public function findJavascriptFiles($scripts) { + // Read the selected theme from the config file + $theme = OC_Util::getTheme(); + + // Read the detected formfactor and use the right file name. + $fext = self::getFormFactorExtension(); + + $locator = new \OC\Template\JSResourceLocator( $theme, $fext, + array( OC::$SERVERROOT => OC::$WEBROOT ), + array( OC::$THIRDPARTYROOT => OC::$THIRDPARTYWEBROOT )); + $locator->find($scripts); + return $locator->getResources(); + } +} diff --git a/lib/private/updater.php b/lib/private/updater.php new file mode 100644 index 00000000000..df7332a96a9 --- /dev/null +++ b/lib/private/updater.php @@ -0,0 +1,159 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; +use OC\Hooks\BasicEmitter; + +/** + * Class that handles autoupdating of ownCloud + * + * Hooks provided in scope \OC\Updater + * - maintenanceStart() + * - maintenanceEnd() + * - dbUpgrade() + * - filecacheStart() + * - filecacheProgress(int $percentage) + * - filecacheDone() + * - failure(string $message) + */ +class Updater extends BasicEmitter { + + /** + * @var \OC\Log $log + */ + private $log; + + /** + * @param \OC\Log $log + */ + public function __construct($log = null) { + $this->log = $log; + } + + /** + * Check if a new version is available + * @param string $updateUrl the url to check, i.e. 'http://apps.owncloud.com/updater.php' + * @return array | bool + */ + public function check($updaterUrl) { + + // Look up the cache - it is invalidated all 30 minutes + if ((\OC_Appconfig::getValue('core', 'lastupdatedat') + 1800) > time()) { + return json_decode(\OC_Appconfig::getValue('core', 'lastupdateResult'), true); + } + + \OC_Appconfig::setValue('core', 'lastupdatedat', time()); + + if (\OC_Appconfig::getValue('core', 'installedat', '') == '') { + \OC_Appconfig::setValue('core', 'installedat', microtime(true)); + } + + $version = \OC_Util::getVersion(); + $version['installed'] = \OC_Appconfig::getValue('core', 'installedat'); + $version['updated'] = \OC_Appconfig::getValue('core', 'lastupdatedat'); + $version['updatechannel'] = 'stable'; + $version['edition'] = \OC_Util::getEditionString(); + $versionString = implode('x', $version); + + //fetch xml data from updater + $url = $updaterUrl . '?version=' . $versionString; + + // set a sensible timeout of 10 sec to stay responsive even if the update server is down. + $ctx = stream_context_create( + array( + 'http' => array( + 'timeout' => 10 + ) + ) + ); + $xml = @file_get_contents($url, 0, $ctx); + if ($xml == false) { + return array(); + } + $data = @simplexml_load_string($xml); + + $tmp = array(); + $tmp['version'] = $data->version; + $tmp['versionstring'] = $data->versionstring; + $tmp['url'] = $data->url; + $tmp['web'] = $data->web; + + // Cache the result + \OC_Appconfig::setValue('core', 'lastupdateResult', json_encode($data)); + + return $tmp; + } + + /** + * runs the update actions in maintenance mode, does not upgrade the source files + */ + public function upgrade() { + \OC_DB::enableCaching(false); + \OC_Config::setValue('maintenance', true); + $installedVersion = \OC_Config::getValue('version', '0.0.0'); + $currentVersion = implode('.', \OC_Util::getVersion()); + if ($this->log) { + $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core')); + } + $this->emit('\OC\Updater', 'maintenanceStart'); + try { + \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); + $this->emit('\OC\Updater', 'dbUpgrade'); + + // do a file cache upgrade for users with files + // this can take loooooooooooooooooooooooong + $this->upgradeFileCache(); + } catch (\Exception $exception) { + $this->emit('\OC\Updater', 'failure', array($exception->getMessage())); + } + \OC_Config::setValue('version', implode('.', \OC_Util::getVersion())); + \OC_App::checkAppsRequirements(); + // load all apps to also upgrade enabled apps + \OC_App::loadApps(); + \OC_Config::setValue('maintenance', false); + $this->emit('\OC\Updater', 'maintenanceEnd'); + } + + private function upgradeFileCache() { + try { + $query = \OC_DB::prepare(' + SELECT DISTINCT `user` + FROM `*PREFIX*fscache` + '); + $result = $query->execute(); + } catch (\Exception $e) { + return; + } + $users = $result->fetchAll(); + if (count($users) == 0) { + return; + } + $step = 100 / count($users); + $percentCompleted = 0; + $lastPercentCompletedOutput = 0; + $startInfoShown = false; + foreach ($users as $userRow) { + $user = $userRow['user']; + \OC\Files\Filesystem::initMountPoints($user); + \OC\Files\Cache\Upgrade::doSilentUpgrade($user); + if (!$startInfoShown) { + //We show it only now, because otherwise Info about upgraded apps + //will appear between this and progress info + $this->emit('\OC\Updater', 'filecacheStart'); + $startInfoShown = true; + } + $percentCompleted += $step; + $out = floor($percentCompleted); + if ($out != $lastPercentCompletedOutput) { + $this->emit('\OC\Updater', 'filecacheProgress', array($out)); + $lastPercentCompletedOutput = $out; + } + } + $this->emit('\OC\Updater', 'filecacheDone'); + } +} diff --git a/lib/private/user.php b/lib/private/user.php new file mode 100644 index 00000000000..15e807088b4 --- /dev/null +++ b/lib/private/user.php @@ -0,0 +1,500 @@ +. + * + */ + +/** + * This class provides wrapper methods for user management. Multiple backends are + * supported. User management operations are delegated to the configured backend for + * execution. + * + * Hooks provided: + * pre_createUser(&run, uid, password) + * post_createUser(uid, password) + * pre_deleteUser(&run, uid) + * post_deleteUser(uid) + * pre_setPassword(&run, uid, password, recoveryPassword) + * post_setPassword(uid, password, recoveryPassword) + * pre_login(&run, uid, password) + * post_login(uid) + * logout() + */ +class OC_User { + public static function getUserSession() { + return OC::$server->getUserSession(); + } + + /** + * @return \OC\User\Manager + */ + public static function getManager() { + return OC::$server->getUserManager(); + } + + private static $_backends = array(); + + private static $_usedBackends = array(); + + private static $_setupedBackends = array(); + + /** + * @brief registers backend + * @param string $backend name of the backend + * @deprecated Add classes by calling useBackend with a class instance instead + * @return bool + * + * Makes a list of backends that can be used by other modules + */ + public static function registerBackend($backend) { + self::$_backends[] = $backend; + return true; + } + + /** + * @brief gets available backends + * @deprecated + * @returns array of backends + * + * Returns the names of all backends. + */ + public static function getBackends() { + return self::$_backends; + } + + /** + * @brief gets used backends + * @deprecated + * @returns array of backends + * + * Returns the names of all used backends. + */ + public static function getUsedBackends() { + return array_keys(self::$_usedBackends); + } + + /** + * @brief Adds the backend to the list of used backends + * @param string | OC_User_Backend $backend default: database The backend to use for user management + * @return bool + * + * Set the User Authentication Module + */ + public static function useBackend($backend = 'database') { + if ($backend instanceof OC_User_Interface) { + self::$_usedBackends[get_class($backend)] = $backend; + self::getManager()->registerBackend($backend); + } else { + // You'll never know what happens + if (null === $backend OR !is_string($backend)) { + $backend = 'database'; + } + + // Load backend + switch ($backend) { + case 'database': + case 'mysql': + case 'sqlite': + OC_Log::write('core', 'Adding user backend ' . $backend . '.', OC_Log::DEBUG); + self::$_usedBackends[$backend] = new OC_User_Database(); + self::getManager()->registerBackend(self::$_usedBackends[$backend]); + break; + default: + OC_Log::write('core', 'Adding default user backend ' . $backend . '.', OC_Log::DEBUG); + $className = 'OC_USER_' . strToUpper($backend); + self::$_usedBackends[$backend] = new $className(); + self::getManager()->registerBackend(self::$_usedBackends[$backend]); + break; + } + } + return true; + } + + /** + * remove all used backends + */ + public static function clearBackends() { + self::$_usedBackends = array(); + self::getManager()->clearBackends(); + } + + /** + * setup the configured backends in config.php + */ + public static function setupBackends() { + OC_App::loadApps(array('prelogin')); + $backends = OC_Config::getValue('user_backends', array()); + foreach ($backends as $i => $config) { + $class = $config['class']; + $arguments = $config['arguments']; + if (class_exists($class)) { + if (array_search($i, self::$_setupedBackends) === false) { + // make a reflection object + $reflectionObj = new ReflectionClass($class); + + // use Reflection to create a new instance, using the $args + $backend = $reflectionObj->newInstanceArgs($arguments); + self::useBackend($backend); + self::$_setupedBackends[] = $i; + } else { + OC_Log::write('core', 'User backend ' . $class . ' already initialized.', OC_Log::DEBUG); + } + } else { + OC_Log::write('core', 'User backend ' . $class . ' not found.', OC_Log::ERROR); + } + } + } + + /** + * @brief Create a new user + * @param string $uid The username of the user to create + * @param string $password The password of the new user + * @throws Exception + * @return bool true/false + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + * + * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-" + */ + public static function createUser($uid, $password) { + return self::getManager()->createUser($uid, $password); + } + + /** + * @brief delete a user + * @param string $uid The username of the user to delete + * @return bool + * + * Deletes a user + */ + public static function deleteUser($uid) { + $user = self::getManager()->get($uid); + if ($user) { + $user->delete(); + + // We have to delete the user from all groups + foreach (OC_Group::getUserGroups($uid) as $i) { + OC_Group::removeFromGroup($uid, $i); + } + // Delete the user's keys in preferences + OC_Preferences::deleteUser($uid); + + // Delete user files in /data/ + OC_Helper::rmdirr(OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid . '/'); + } + } + + /** + * @brief Try to login a user + * @param $uid The username of the user to log in + * @param $password The password of the user + * @return bool + * + * Log in a user and regenerate a new session - if the password is ok + */ + public static function login($uid, $password) { + return self::getUserSession()->login($uid, $password); + } + + /** + * @brief Sets user id for session and triggers emit + */ + public static function setUserId($uid) { + OC::$session->set('user_id', $uid); + } + + /** + * @brief Sets user display name for session + */ + public static function setDisplayName($uid, $displayName = null) { + if (is_null($displayName)) { + $displayName = $uid; + } + $user = self::getManager()->get($uid); + if ($user) { + return $user->setDisplayName($displayName); + } else { + return false; + } + } + + /** + * @brief Logs the current user out and kills all the session data + * + * Logout, destroys session + */ + public static function logout() { + self::getUserSession()->logout(); + } + + /** + * @brief Check if the user is logged in + * @returns bool + * + * Checks if the user is logged in + */ + public static function isLoggedIn() { + if (\OC::$session->get('user_id')) { + OC_App::loadApps(array('authentication')); + self::setupBackends(); + return self::userExists(\OC::$session->get('user_id')); + } + return false; + } + + /** + * @brief Check if the user is an admin user + * @param string $uid uid of the admin + * @return bool + */ + public static function isAdminUser($uid) { + if (OC_Group::inGroup($uid, 'admin')) { + return true; + } + return false; + } + + + /** + * @brief get the user id of the user currently logged in. + * @return string uid or false + */ + public static function getUser() { + $uid = OC::$session ? OC::$session->get('user_id') : null; + if (!is_null($uid)) { + return $uid; + } else { + return false; + } + } + + /** + * @brief get the display name of the user currently logged in. + * @param string $uid + * @return string uid or false + */ + public static function getDisplayName($uid = null) { + if ($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->getDisplayName(); + } else { + return $uid; + } + } else { + $user = self::getUserSession()->getUser(); + if ($user) { + return $user->getDisplayName(); + } else { + return false; + } + } + } + + /** + * @brief Autogenerate a password + * @return string + * + * generates a password + */ + public static function generatePassword() { + return OC_Util::generateRandomBytes(30); + } + + /** + * @brief Set password + * @param string $uid The username + * @param string $password The new password + * @param string $recoveryPassword for the encryption app to reset encryption keys + * @return bool + * + * Change the password of a user + */ + public static function setPassword($uid, $password, $recoveryPassword = null) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->setPassword($password, $recoveryPassword); + } else { + return false; + } + } + + /** + * @brief Check whether user can change his password + * @param string $uid The username + * @return bool + * + * Check whether a specified user can change his password + */ + public static function canUserChangePassword($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->canChangePassword(); + } else { + return false; + } + } + + /** + * @brief Check whether user can change his display name + * @param string $uid The username + * @return bool + * + * Check whether a specified user can change his display name + */ + public static function canUserChangeDisplayName($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->canChangeDisplayName(); + } else { + return false; + } + } + + /** + * @brief Check if the password is correct + * @param string $uid The username + * @param string $password The password + * @return mixed user id a string on success, false otherwise + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + public static function checkPassword($uid, $password) { + $manager = self::getManager(); + $username = $manager->checkPassword($uid, $password); + if ($username !== false) { + return $username->getUID(); + } + return false; + } + + /** + * @param string $uid The username + * @return string + * + * returns the path to the users home directory + */ + public static function getHome($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->getHome(); + } else { + return OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid; + } + } + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public static function getUsers($search = '', $limit = null, $offset = null) { + $users = self::getManager()->search($search, $limit, $offset); + $uids = array(); + foreach ($users as $user) { + $uids[] = $user->getUID(); + } + return $uids; + } + + /** + * @brief Get a list of all users display name + * @param string $search + * @param int $limit + * @param int $offset + * @return array associative array with all display names (value) and corresponding uids (key) + * + * Get a list of all display names and user ids. + */ + public static function getDisplayNames($search = '', $limit = null, $offset = null) { + $displayNames = array(); + $users = self::getManager()->searchDisplayName($search, $limit, $offset); + foreach ($users as $user) { + $displayNames[$user->getUID()] = $user->getDisplayName(); + } + return $displayNames; + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public static function userExists($uid) { + return self::getManager()->userExists($uid); + } + + /** + * disables a user + * + * @param string $uid the user to disable + */ + public static function disableUser($uid) { + $user = self::getManager()->get($uid); + if ($user) { + $user->setEnabled(false); + } + } + + /** + * enable a user + * + * @param string $uid + */ + public static function enableUser($uid) { + $user = self::getManager()->get($uid); + if ($user) { + $user->setEnabled(true); + } + } + + /** + * checks if a user is enabled + * + * @param string $uid + * @return bool + */ + public static function isEnabled($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->isEnabled(); + } else { + return false; + } + } + + /** + * @brief Set cookie value to use in next page load + * @param string $username username to be set + * @param string $token + */ + public static function setMagicInCookie($username, $token) { + self::getUserSession()->setMagicInCookie($username, $token); + } + + /** + * @brief Remove cookie for "remember username" + */ + public static function unsetMagicInCookie() { + self::getUserSession()->unsetMagicInCookie(); + } +} diff --git a/lib/private/user/backend.php b/lib/private/user/backend.php new file mode 100644 index 00000000000..e9be08e429c --- /dev/null +++ b/lib/private/user/backend.php @@ -0,0 +1,159 @@ +. + * + */ + +/** + * error code for functions not provided by the user backend + */ +define('OC_USER_BACKEND_NOT_IMPLEMENTED', -501); + +/** + * actions that user backends can define + */ +define('OC_USER_BACKEND_CREATE_USER', 0x000001); +define('OC_USER_BACKEND_SET_PASSWORD', 0x000010); +define('OC_USER_BACKEND_CHECK_PASSWORD', 0x000100); +define('OC_USER_BACKEND_GET_HOME', 0x001000); +define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x010000); +define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x100000); + + +/** + * Abstract base class for user management. Provides methods for querying backend + * capabilities. + * + * Subclass this for your own backends, and see OC_User_Example for descriptions + */ +abstract class OC_User_Backend implements OC_User_Interface { + + protected $possibleActions = array( + OC_USER_BACKEND_CREATE_USER => 'createUser', + OC_USER_BACKEND_SET_PASSWORD => 'setPassword', + OC_USER_BACKEND_CHECK_PASSWORD => 'checkPassword', + OC_USER_BACKEND_GET_HOME => 'getHome', + OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName', + OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName', + ); + + /** + * @brief Get all supported actions + * @return int bitwise-or'ed actions + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function getSupportedActions() { + $actions = 0; + foreach($this->possibleActions AS $action => $methodName) { + if(method_exists($this, $methodName)) { + $actions |= $action; + } + } + + return $actions; + } + + /** + * @brief Check if backend implements actions + * @param int $actions bitwise-or'ed actions + * @return boolean + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function implementsActions($actions) { + return (bool)($this->getSupportedActions() & $actions); + } + + /** + * @brief delete a user + * @param string $uid The username of the user to delete + * @return bool + * + * Deletes a user + */ + public function deleteUser( $uid ) { + return false; + } + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null) { + return array(); + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + return false; + } + + /** + * @brief get the user's home directory + * @param string $uid the username + * @return boolean + */ + public function getHome($uid) { + return false; + } + + /** + * @brief get display name of the user + * @param string $uid user ID of the user + * @return string display name + */ + public function getDisplayName($uid) { + return $uid; + } + + /** + * @brief Get a list of all display names + * @returns array with all displayNames (value) and the corresponding uids (key) + * + * Get a list of all display names and user ids. + */ + public function getDisplayNames($search = '', $limit = null, $offset = null) { + $displayNames = array(); + $users = $this->getUsers($search, $limit, $offset); + foreach ( $users as $user) { + $displayNames[$user] = $user; + } + return $displayNames; + } + + /** + * @brief Check if a user list is available or not + * @return boolean if users can be listed or not + */ + public function hasUserListings() { + return false; + } +} diff --git a/lib/private/user/database.php b/lib/private/user/database.php new file mode 100644 index 00000000000..9f00a022d9f --- /dev/null +++ b/lib/private/user/database.php @@ -0,0 +1,269 @@ +. + * + */ +/* + * + * The following SQL statement is just a help for developers and will not be + * executed! + * + * CREATE TABLE `users` ( + * `uid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, + * `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + * PRIMARY KEY (`uid`) + * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + * + */ + +require_once 'phpass/PasswordHash.php'; + +/** + * Class for user management in a SQL Database (e.g. MySQL, SQLite) + */ +class OC_User_Database extends OC_User_Backend { + /** + * @var PasswordHash + */ + static private $hasher=null; + + private function getHasher() { + if(!self::$hasher) { + //we don't want to use DES based crypt(), since it doesn't return a hash with a recognisable prefix + $forcePortable=(CRYPT_BLOWFISH!=1); + self::$hasher=new PasswordHash(8, $forcePortable); + } + return self::$hasher; + + } + + /** + * @brief Create a new user + * @param $uid The username of the user to create + * @param $password The password of the new user + * @returns true/false + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ + public function createUser( $uid, $password ) { + if( $this->userExists($uid) ) { + return false; + }else{ + $hasher=$this->getHasher(); + $hash = $hasher->HashPassword($password.OC_Config::getValue('passwordsalt', '')); + $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )' ); + $result = $query->execute( array( $uid, $hash)); + + return $result ? true : false; + } + } + + /** + * @brief delete a user + * @param $uid The username of the user to delete + * @returns true/false + * + * Deletes a user + */ + public function deleteUser( $uid ) { + // Delete user-group-relation + $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*users` WHERE `uid` = ?' ); + $query->execute( array( $uid )); + return true; + } + + /** + * @brief Set password + * @param $uid The username + * @param $password The new password + * @returns true/false + * + * Change the password of a user + */ + public function setPassword( $uid, $password ) { + if( $this->userExists($uid) ) { + $hasher=$this->getHasher(); + $hash = $hasher->HashPassword($password.OC_Config::getValue('passwordsalt', '')); + $query = OC_DB::prepare( 'UPDATE `*PREFIX*users` SET `password` = ? WHERE `uid` = ?' ); + $query->execute( array( $hash, $uid )); + + return true; + }else{ + return false; + } + } + + /** + * @brief Set display name + * @param $uid The username + * @param $displayName The new display name + * @returns true/false + * + * Change the display name of a user + */ + public function setDisplayName( $uid, $displayName ) { + if( $this->userExists($uid) ) { + $query = OC_DB::prepare( 'UPDATE `*PREFIX*users` SET `displayname` = ? WHERE `uid` = ?' ); + $query->execute( array( $displayName, $uid )); + return true; + }else{ + return false; + } + } + + /** + * @brief get display name of the user + * @param $uid user ID of the user + * @return display name + */ + public function getDisplayName($uid) { + if( $this->userExists($uid) ) { + $query = OC_DB::prepare( 'SELECT `displayname` FROM `*PREFIX*users` WHERE `uid` = ?' ); + $result = $query->execute( array( $uid ))->fetchAll(); + $displayName = trim($result[0]['displayname'], ' '); + if ( !empty($displayName) ) { + return $displayName; + } else { + return $uid; + } + } + } + + /** + * @brief Get a list of all display names + * @returns array with all displayNames (value) and the correspondig uids (key) + * + * Get a list of all display names and user ids. + */ + public function getDisplayNames($search = '', $limit = null, $offset = null) { + $displayNames = array(); + $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`' + .' WHERE LOWER(`displayname`) LIKE LOWER(?)', $limit, $offset); + $result = $query->execute(array($search.'%')); + $users = array(); + while ($row = $result->fetchRow()) { + $displayNames[$row['uid']] = $row['displayname']; + } + + // let's see if we can also find some users who don't have a display name yet + $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`' + .' WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset); + $result = $query->execute(array($search.'%')); + while ($row = $result->fetchRow()) { + $displayName = trim($row['displayname'], ' '); + if ( empty($displayName) ) { + $displayNames[$row['uid']] = $row['uid']; + } + } + + + return $displayNames; + } + + /** + * @brief Check if the password is correct + * @param $uid The username + * @param $password The password + * @returns string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + public function checkPassword( $uid, $password ) { + $query = OC_DB::prepare( 'SELECT `uid`, `password` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' ); + $result = $query->execute( array( $uid)); + + $row=$result->fetchRow(); + if($row) { + $storedHash=$row['password']; + if ($storedHash[0]=='$') {//the new phpass based hashing + $hasher=$this->getHasher(); + if($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''), $storedHash)) { + return $row['uid']; + }else{ + return false; + } + }else{//old sha1 based hashing + if(sha1($password)==$storedHash) { + //upgrade to new hashing + $this->setPassword($row['uid'], $password); + return $row['uid']; + }else{ + return false; + } + } + }else{ + return false; + } + } + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null) { + $query = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*users` WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset); + $result = $query->execute(array($search.'%')); + $users = array(); + while ($row = $result->fetchRow()) { + $users[] = $row['uid']; + } + return $users; + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + $query = OC_DB::prepare( 'SELECT COUNT(*) FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' ); + $result = $query->execute( array( $uid )); + if (OC_DB::isError($result)) { + OC_Log::write('core', OC_DB::getErrorMessage($result), OC_Log::ERROR); + return false; + } + return $result->fetchOne() > 0; + } + + /** + * @brief get the user's home directory + * @param string $uid the username + * @return boolean + */ + public function getHome($uid) { + if($this->userExists($uid)) { + return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid; + }else{ + return false; + } + } + + /** + * @return bool + */ + public function hasUserListings() { + return true; + } + +} diff --git a/lib/private/user/dummy.php b/lib/private/user/dummy.php new file mode 100644 index 00000000000..b5b7a6c3c7a --- /dev/null +++ b/lib/private/user/dummy.php @@ -0,0 +1,126 @@ +. + * + */ + +/** + * dummy user backend, does not keep state, only for testing use + */ +class OC_User_Dummy extends OC_User_Backend { + private $users = array(); + + /** + * @brief Create a new user + * @param string $uid The username of the user to create + * @param string $password The password of the new user + * @return bool + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ + public function createUser($uid, $password) { + if (isset($this->users[$uid])) { + return false; + } else { + $this->users[$uid] = $password; + return true; + } + } + + /** + * @brief delete a user + * @param string $uid The username of the user to delete + * @return bool + * + * Deletes a user + */ + public function deleteUser($uid) { + if (isset($this->users[$uid])) { + unset($this->users[$uid]); + return true; + } else { + return false; + } + } + + /** + * @brief Set password + * @param string $uid The username + * @param string $password The new password + * @return bool + * + * Change the password of a user + */ + public function setPassword($uid, $password) { + if (isset($this->users[$uid])) { + $this->users[$uid] = $password; + return true; + } else { + return false; + } + } + + /** + * @brief Check if the password is correct + * @param string $uid The username + * @param string $password The password + * @return string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + public function checkPassword($uid, $password) { + if (isset($this->users[$uid])) { + return ($this->users[$uid] == $password); + } else { + return false; + } + } + + /** + * @brief Get a list of all users + * @param string $search + * @param int $limit + * @param int $offset + * @return array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null) { + return array_keys($this->users); + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + return isset($this->users[$uid]); + } + + /** + * @return bool + */ + public function hasUserListings() { + return true; + } +} diff --git a/lib/private/user/example.php b/lib/private/user/example.php new file mode 100644 index 00000000000..b2d0dc25410 --- /dev/null +++ b/lib/private/user/example.php @@ -0,0 +1,70 @@ +. + * + */ + +/** + * abstract reference class for user management + * this class should only be used as a reference for method signatures and their descriptions + */ +abstract class OC_User_Example extends OC_User_Backend { + /** + * @brief Create a new user + * @param $uid The username of the user to create + * @param $password The password of the new user + * @returns true/false + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ + abstract public function createUser($uid, $password); + + /** + * @brief Set password + * @param $uid The username + * @param $password The new password + * @returns true/false + * + * Change the password of a user + */ + abstract public function setPassword($uid, $password); + + /** + * @brief Check if the password is correct + * @param $uid The username + * @param $password The password + * @returns string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + abstract public function checkPassword($uid, $password); + + /** + * @brief get the user's home directory + * @param $uid The username + * @returns string + * + * get the user's home directory + * returns the path or false + */ + abstract public function getHome($uid); +} diff --git a/lib/private/user/http.php b/lib/private/user/http.php new file mode 100644 index 00000000000..e99afe59ba7 --- /dev/null +++ b/lib/private/user/http.php @@ -0,0 +1,110 @@ +. +* +*/ + +/** + * user backend using http auth requests + */ +class OC_User_HTTP extends OC_User_Backend { + /** + * split http://user@host/path into a user and url part + * @param string path + * @return array + */ + private function parseUrl($url) { + $parts=parse_url($url); + $url=$parts['scheme'].'://'.$parts['host']; + if(isset($parts['port'])) { + $url.=':'.$parts['port']; + } + $url.=$parts['path']; + if(isset($parts['query'])) { + $url.='?'.$parts['query']; + } + return array($parts['user'], $url); + + } + + /** + * check if an url is a valid login + * @param string url + * @return boolean + */ + private function matchUrl($url) { + return ! is_null(parse_url($url, PHP_URL_USER)); + } + + /** + * @brief Check if the password is correct + * @param $uid The username + * @param $password The password + * @returns string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ + public function checkPassword($uid, $password) { + if(!$this->matchUrl($uid)) { + return false; + } + list($user, $url)=$this->parseUrl($uid); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$password); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + curl_exec($ch); + + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + curl_close($ch); + + if($status === 200) { + return $uid; + } + + return false; + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + return $this->matchUrl($uid); + } + + /** + * @brief get the user's home directory + * @param string $uid the username + * @return boolean + */ + public function getHome($uid) { + if($this->userExists($uid)) { + return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid; + }else{ + return false; + } + } +} diff --git a/lib/private/user/interface.php b/lib/private/user/interface.php new file mode 100644 index 00000000000..c72bdfaf3fd --- /dev/null +++ b/lib/private/user/interface.php @@ -0,0 +1,80 @@ +. + * + */ + +interface OC_User_Interface { + + /** + * @brief Check if backend implements actions + * @param $actions bitwise-or'ed actions + * @returns boolean + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function implementsActions($actions); + + /** + * @brief delete a user + * @param $uid The username of the user to delete + * @returns true/false + * + * Deletes a user + */ + public function deleteUser($uid); + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public function getUsers($search = '', $limit = null, $offset = null); + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid); + + /** + * @brief get display name of the user + * @param $uid user ID of the user + * @return display name + */ + public function getDisplayName($uid); + + /** + * @brief Get a list of all display names + * @returns array with all displayNames (value) and the corresponding uids (key) + * + * Get a list of all display names and user ids. + */ + public function getDisplayNames($search = '', $limit = null, $offset = null); + + /** + * @brief Check if a user list is available or not + * @return boolean if users can be listed or not + */ + public function hasUserListings(); +} diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php new file mode 100644 index 00000000000..13286bc28a4 --- /dev/null +++ b/lib/private/user/manager.php @@ -0,0 +1,250 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\PublicEmitter; + +/** + * Class Manager + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user, string $password) + * + * @package OC\User + */ +class Manager extends PublicEmitter { + /** + * @var \OC_User_Backend[] $backends + */ + private $backends = array(); + + /** + * @var \OC\User\User[] $cachedUsers + */ + private $cachedUsers = array(); + + public function __construct() { + $cachedUsers = $this->cachedUsers; + $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) { + $i = array_search($user, $cachedUsers); + if ($i !== false) { + unset($cachedUsers[$i]); + } + }); + } + + /** + * register a user backend + * + * @param \OC_User_Backend $backend + */ + public function registerBackend($backend) { + $this->backends[] = $backend; + } + + /** + * remove a user backend + * + * @param \OC_User_Backend $backend + */ + public function removeBackend($backend) { + $this->cachedUsers = array(); + if (($i = array_search($backend, $this->backends)) !== false) { + unset($this->backends[$i]); + } + } + + /** + * remove all user backends + */ + public function clearBackends() { + $this->cachedUsers = array(); + $this->backends = array(); + } + + /** + * get a user by user id + * + * @param string $uid + * @return \OC\User\User + */ + public function get($uid) { + if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends + return $this->cachedUsers[$uid]; + } + foreach ($this->backends as $backend) { + if ($backend->userExists($uid)) { + return $this->getUserObject($uid, $backend); + } + } + return null; + } + + /** + * get or construct the user object + * + * @param string $uid + * @param \OC_User_Backend $backend + * @return \OC\User\User + */ + protected function getUserObject($uid, $backend) { + if (isset($this->cachedUsers[$uid])) { + return $this->cachedUsers[$uid]; + } + $this->cachedUsers[$uid] = new User($uid, $backend, $this); + return $this->cachedUsers[$uid]; + } + + /** + * check if a user exists + * + * @param string $uid + * @return bool + */ + public function userExists($uid) { + $user = $this->get($uid); + return ($user !== null); + } + + /** + * Check if the password is valid for the user + * + * @param $loginname + * @param $password + * @return mixed the User object on success, false otherwise + */ + public function checkPassword($loginname, $password) { + foreach ($this->backends as $backend) { + if($backend->implementsActions(\OC_USER_BACKEND_CHECK_PASSWORD)) { + $uid = $backend->checkPassword($loginname, $password); + if ($uid !== false) { + return $this->getUserObject($uid, $backend); + } + } + } + return false; + } + + /** + * search by user id + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function search($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getUsers($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid) { + $users[] = $this->getUserObject($uid, $backend); + if (!is_null($limit)) { + $limit--; + } + if (!is_null($offset) and $offset > 0) { + $offset--; + } + + } + } + } + + usort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getUID(), $b->getUID()); + }); + return $users; + } + + /** + * search by displayName + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function searchDisplayName($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid => $displayName) { + $users[] = $this->getUserObject($uid, $backend); + if (!is_null($limit)) { + $limit--; + } + if (!is_null($offset) and $offset > 0) { + $offset--; + } + + } + } + } + + usort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getDisplayName(), $b->getDisplayName()); + }); + return $users; + } + + /** + * @param string $uid + * @param string $password + * @throws \Exception + * @return bool | \OC\User\User the created user of false + */ + public function createUser($uid, $password) { + // Check the name for bad characters + // Allowed are: "a-z", "A-Z", "0-9" and "_.@-" + if (preg_match('/[^a-zA-Z0-9 _\.@\-]/', $uid)) { + throw new \Exception('Only the following characters are allowed in a username:' + . ' "a-z", "A-Z", "0-9", and "_.@-"'); + } + // No empty username + if (trim($uid) == '') { + throw new \Exception('A valid username must be provided'); + } + // No empty password + if (trim($password) == '') { + throw new \Exception('A valid password must be provided'); + } + + // Check if user already exists + if ($this->userExists($uid)) { + throw new \Exception('The username is already being used'); + } + + $this->emit('\OC\User', 'preCreateUser', array($uid, $password)); + foreach ($this->backends as $backend) { + if ($backend->implementsActions(\OC_USER_BACKEND_CREATE_USER)) { + $backend->createUser($uid, $password); + $user = $this->getUserObject($uid, $backend); + $this->emit('\OC\User', 'postCreateUser', array($user, $password)); + return $user; + } + } + return false; + } +} diff --git a/lib/private/user/session.php b/lib/private/user/session.php new file mode 100644 index 00000000000..525c65ab8a1 --- /dev/null +++ b/lib/private/user/session.php @@ -0,0 +1,174 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\Emitter; + +/** + * Class Session + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user) + * - preLogin(string $user, string $password) + * - postLogin(\OC\User\User $user) + * - logout() + * + * @package OC\User + */ +class Session implements Emitter, \OCP\IUserSession { + /** + * @var \OC\User\Manager $manager + */ + private $manager; + + /** + * @var \OC\Session\Session $session + */ + private $session; + + /** + * @var \OC\User\User $activeUser + */ + protected $activeUser; + + /** + * @param \OC\User\Manager $manager + * @param \OC\Session\Session $session + */ + public function __construct($manager, $session) { + $this->manager = $manager; + $this->session = $session; + } + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback) { + $this->manager->listen($scope, $method, $callback); + } + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, $callback = null) { + $this->manager->removeListener($scope, $method, $callback); + } + + /** + * get the manager object + * + * @return \OC\User\Manager + */ + public function getManager() { + return $this->manager; + } + + /** + * set the currently active user + * + * @param \OC\User\User $user + */ + public function setUser($user) { + if (is_null($user)) { + $this->session->remove('user_id'); + } else { + $this->session->set('user_id', $user->getUID()); + } + $this->activeUser = $user; + } + + /** + * get the current active user + * + * @return \OC\User\User + */ + public function getUser() { + if ($this->activeUser) { + return $this->activeUser; + } else { + $uid = $this->session->get('user_id'); + if ($uid) { + $this->activeUser = $this->manager->get($uid); + return $this->activeUser; + } else { + return null; + } + } + } + + /** + * try to login with the provided credentials + * + * @param string $uid + * @param string $password + * @return bool + */ + public function login($uid, $password) { + $this->manager->emit('\OC\User', 'preLogin', array($uid, $password)); + $user = $this->manager->checkPassword($uid, $password); + if($user !== false) { + if (!is_null($user)) { + if ($user->isEnabled()) { + $this->setUser($user); + $this->manager->emit('\OC\User', 'postLogin', array($user, $password)); + return true; + } else { + return false; + } + } + } else { + return false; + } + } + + /** + * logout the user from the session + */ + public function logout() { + $this->manager->emit('\OC\User', 'logout'); + $this->setUser(null); + $this->unsetMagicInCookie(); + } + + /** + * Set cookie value to use in next page load + * + * @param string $username username to be set + * @param string $token + */ + public function setMagicInCookie($username, $token) { + $secure_cookie = \OC_Config::getValue("forcessl", false); //TODO: DI for cookies and OC_Config + $expires = time() + \OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); + setcookie("oc_username", $username, $expires, \OC::$WEBROOT, '', $secure_cookie); + setcookie("oc_token", $token, $expires, \OC::$WEBROOT, '', $secure_cookie, true); + setcookie("oc_remember_login", true, $expires, \OC::$WEBROOT, '', $secure_cookie); + } + + /** + * Remove cookie for "remember username" + */ + public function unsetMagicInCookie() { + unset($_COOKIE["oc_username"]); //TODO: DI + unset($_COOKIE["oc_token"]); + unset($_COOKIE["oc_remember_login"]); + setcookie('oc_username', '', time()-3600, \OC::$WEBROOT); + setcookie('oc_token', '', time()-3600, \OC::$WEBROOT); + setcookie('oc_remember_login', '', time()-3600, \OC::$WEBROOT); + } +} diff --git a/lib/private/user/user.php b/lib/private/user/user.php new file mode 100644 index 00000000000..e5f842944f1 --- /dev/null +++ b/lib/private/user/user.php @@ -0,0 +1,179 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\Emitter; + +class User { + /** + * @var string $uid + */ + private $uid; + + /** + * @var string $displayName + */ + private $displayName; + + /** + * @var \OC_User_Backend $backend + */ + private $backend; + + /** + * @var bool $enabled + */ + private $enabled; + + /** + * @var Emitter | Manager $emitter + */ + private $emitter; + + /** + * @param string $uid + * @param \OC_User_Backend $backend + * @param Emitter $emitter + */ + public function __construct($uid, $backend, $emitter = null) { + $this->uid = $uid; + if ($backend and $backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) { + $this->displayName = $backend->getDisplayName($uid); + } else { + $this->displayName = $uid; + } + $this->backend = $backend; + $this->emitter = $emitter; + $enabled = \OC_Preferences::getValue($uid, 'core', 'enabled', 'true'); //TODO: DI for OC_Preferences + $this->enabled = ($enabled === 'true'); + } + + /** + * get the user id + * + * @return string + */ + public function getUID() { + return $this->uid; + } + + /** + * get the displayname for the user, if no specific displayname is set it will fallback to the user id + * + * @return string + */ + public function getDisplayName() { + return $this->displayName; + } + + /** + * set the displayname for the user + * + * @param string $displayName + * @return bool + */ + public function setDisplayName($displayName) { + if ($this->canChangeDisplayName()) { + $this->displayName = $displayName; + $result = $this->backend->setDisplayName($this->uid, $displayName); + return $result !== false; + } else { + return false; + } + } + + /** + * Delete the user + * + * @return bool + */ + public function delete() { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preDelete', array($this)); + } + $result = $this->backend->deleteUser($this->uid); + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postDelete', array($this)); + } + return !($result === false); + } + + /** + * Set the password of the user + * + * @param string $password + * @param string $recoveryPassword for the encryption app to reset encryption keys + * @return bool + */ + public function setPassword($password, $recoveryPassword) { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword)); + } + if ($this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD)) { + $result = $this->backend->setPassword($this->uid, $password); + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postSetPassword', array($this, $password, $recoveryPassword)); + } + return !($result === false); + } else { + return false; + } + } + + /** + * get the users home folder to mount + * + * @return string + */ + public function getHome() { + if ($this->backend->implementsActions(\OC_USER_BACKEND_GET_HOME) and $home = $this->backend->getHome($this->uid)) { + return $home; + } + return \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $this->uid; //TODO switch to Config object once implemented + } + + /** + * check if the backend supports changing passwords + * + * @return bool + */ + public function canChangePassword() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD); + } + + /** + * check if the backend supports changing display names + * + * @return bool + */ + public function canChangeDisplayName() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME); + } + + /** + * check if the user is enabled + * + * @return bool + */ + public function isEnabled() { + return $this->enabled; + } + + /** + * set the enabled status for the user + * + * @param bool $enabled + */ + public function setEnabled($enabled) { + $this->enabled = $enabled; + $enabled = ($enabled) ? 'true' : 'false'; + \OC_Preferences::setValue($this->uid, 'core', 'enabled', $enabled); + } +} diff --git a/lib/private/util.php b/lib/private/util.php new file mode 100755 index 00000000000..6be56d07c9a --- /dev/null +++ b/lib/private/util.php @@ -0,0 +1,1019 @@ +$configDataDirectory), '/'); + self::$rootMounted = true; + } + + //if we aren't logged in, there is no use to set up the filesystem + if( $user != "" ) { + $quota = self::getUserQuota($user); + if ($quota !== \OC\Files\SPACE_UNLIMITED) { + \OC\Files\Filesystem::addStorageWrapper(function($mountPoint, $storage) use ($quota, $user) { + if ($mountPoint === '/' . $user . '/'){ + return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota)); + } else { + return $storage; + } + }); + } + $userDir = '/'.$user.'/files'; + $userRoot = OC_User::getHome($user); + $userDirectory = $userRoot . '/files'; + if( !is_dir( $userDirectory )) { + mkdir( $userDirectory, 0755, true ); + } + //jail the user into his "home" directory + \OC\Files\Filesystem::init($user, $userDir); + + $fileOperationProxy = new OC_FileProxy_FileOperations(); + OC_FileProxy::register($fileOperationProxy); + + OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir)); + } + return true; + } + + public static function getUserQuota($user){ + $userQuota = OC_Preferences::getValue($user, 'files', 'quota', 'default'); + if($userQuota === 'default') { + $userQuota = OC_AppConfig::getValue('files', 'default_quota', 'none'); + } + if($userQuota === 'none') { + return \OC\Files\SPACE_UNLIMITED; + }else{ + return OC_Helper::computerFileSize($userQuota); + } + } + + /** + * @return void + */ + public static function tearDownFS() { + \OC\Files\Filesystem::tearDown(); + self::$fsSetup=false; + self::$rootMounted=false; + } + + /** + * @brief get the current installed version of ownCloud + * @return array + */ + public static function getVersion() { + // hint: We only can count up. Reset minor/patchlevel when + // updating major/minor version number. + return array(5, 80, 07); + } + + /** + * @brief get the current installed version string of ownCloud + * @return string + */ + public static function getVersionString() { + return '6.0 pre alpha'; + } + + /** + * @description get the current installed edition of ownCloud. There is the community + * edition that just returns an empty string and the enterprise edition + * that returns "Enterprise". + * @return string + */ + public static function getEditionString() { + return ''; + } + + /** + * @brief add a javascript file + * + * @param string $application + * @param filename $file + * @return void + */ + public static function addScript( $application, $file = null ) { + if ( is_null( $file )) { + $file = $application; + $application = ""; + } + if ( !empty( $application )) { + self::$scripts[] = "$application/js/$file"; + } else { + self::$scripts[] = "js/$file"; + } + } + + /** + * @brief add a css file + * + * @param string $application + * @param filename $file + * @return void + */ + public static function addStyle( $application, $file = null ) { + if ( is_null( $file )) { + $file = $application; + $application = ""; + } + if ( !empty( $application )) { + self::$styles[] = "$application/css/$file"; + } else { + self::$styles[] = "css/$file"; + } + } + + /** + * @brief Add a custom element to the header + * @param string $tag tag name of the element + * @param array $attributes array of attributes for the element + * @param string $text the text content for the element + * @return void + */ + public static function addHeader( $tag, $attributes, $text='') { + self::$headers[] = array( + 'tag'=>$tag, + 'attributes'=>$attributes, + 'text'=>$text + ); + } + + /** + * @brief formats a timestamp in the "right" way + * + * @param int $timestamp + * @param bool $dateOnly option to omit time from the result + * @return string timestamp + * @description adjust to clients timezone if we know it + */ + public static function formatDate( $timestamp, $dateOnly=false) { + if(\OC::$session->exists('timezone')) { + $systemTimeZone = intval(date('O')); + $systemTimeZone = (round($systemTimeZone/100, 0)*60) + ($systemTimeZone%100); + $clientTimeZone = \OC::$session->get('timezone')*60; + $offset = $clientTimeZone - $systemTimeZone; + $timestamp = $timestamp + $offset*60; + } + $l = OC_L10N::get('lib'); + return $l->l($dateOnly ? 'date' : 'datetime', $timestamp); + } + + /** + * @brief check if the current server configuration is suitable for ownCloud + * @return array arrays with error messages and hints + */ + public static function checkServer() { + // Assume that if checkServer() succeeded before in this session, then all is fine. + if(\OC::$session->exists('checkServer_suceeded') && \OC::$session->get('checkServer_suceeded')) { + return array(); + } + + $errors = array(); + + $defaults = new \OC_Defaults(); + + $webServerRestart = false; + //check for database drivers + if(!(is_callable('sqlite_open') or class_exists('SQLite3')) + and !is_callable('mysql_connect') + and !is_callable('pg_connect') + and !is_callable('oci_connect')) { + $errors[] = array( + 'error'=>'No database drivers (sqlite, mysql, or postgresql) installed.', + 'hint'=>'' //TODO: sane hint + ); + $webServerRestart = true; + } + + //common hint for all file permissions error messages + $permissionsHint = 'Permissions can usually be fixed by ' + .'giving the webserver write access to the root directory.'; + + // Check if config folder is writable. + if(!is_writable(OC::$SERVERROOT."/config/") or !is_readable(OC::$SERVERROOT."/config/")) { + $errors[] = array( + 'error' => "Can't write into config directory", + 'hint' => 'This can usually be fixed by ' + .'giving the webserver write access to the config directory.' + ); + } + + // Check if there is a writable install folder. + if(OC_Config::getValue('appstoreenabled', true)) { + if( OC_App::getInstallPath() === null + || !is_writable(OC_App::getInstallPath()) + || !is_readable(OC_App::getInstallPath()) ) { + $errors[] = array( + 'error' => "Can't write into apps directory", + 'hint' => 'This can usually be fixed by ' + .'giving the webserver write access to the apps directory ' + .'or disabling the appstore in the config file.' + ); + } + } + $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); + // Create root dir. + if(!is_dir($CONFIG_DATADIRECTORY)) { + $success=@mkdir($CONFIG_DATADIRECTORY); + if ($success) { + $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); + } else { + $errors[] = array( + 'error' => "Can't create data directory (".$CONFIG_DATADIRECTORY.")", + 'hint' => 'This can usually be fixed by ' + .'giving the webserver write access to the root directory.' + ); + } + } else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) { + $errors[] = array( + 'error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud', + 'hint'=>$permissionsHint + ); + } else { + $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); + } + + $moduleHint = "Please ask your server administrator to install the module."; + // check if all required php modules are present + if(!class_exists('ZipArchive')) { + $errors[] = array( + 'error'=>'PHP module zip not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(!class_exists('DOMDocument')) { + $errors[] = array( + 'error' => 'PHP module dom not installed.', + 'hint' => $moduleHint + ); + $webServerRestart =true; + } + if(!function_exists('xml_parser_create')) { + $errors[] = array( + 'error' => 'PHP module libxml not installed.', + 'hint' => $moduleHint + ); + $webServerRestart = true; + } + if(!function_exists('mb_detect_encoding')) { + $errors[] = array( + 'error'=>'PHP module mb multibyte not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(!function_exists('ctype_digit')) { + $errors[] = array( + 'error'=>'PHP module ctype is not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(!function_exists('json_encode')) { + $errors[] = array( + 'error'=>'PHP module JSON is not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(!extension_loaded('gd') || !function_exists('gd_info')) { + $errors[] = array( + 'error'=>'PHP module GD is not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(!function_exists('gzencode')) { + $errors[] = array( + 'error'=>'PHP module zlib is not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(!function_exists('iconv')) { + $errors[] = array( + 'error'=>'PHP module iconv is not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(!function_exists('simplexml_load_string')) { + $errors[] = array( + 'error'=>'PHP module SimpleXML is not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if(floatval(phpversion()) < 5.3) { + $errors[] = array( + 'error'=>'PHP 5.3 is required.', + 'hint'=>'Please ask your server administrator to update PHP to version 5.3 or higher.' + .' PHP 5.2 is no longer supported by ownCloud and the PHP community.' + ); + $webServerRestart = true; + } + if(!defined('PDO::ATTR_DRIVER_NAME')) { + $errors[] = array( + 'error'=>'PHP PDO module is not installed.', + 'hint'=>$moduleHint + ); + $webServerRestart = true; + } + if (((strtolower(@ini_get('safe_mode')) == 'on') + || (strtolower(@ini_get('safe_mode')) == 'yes') + || (strtolower(@ini_get('safe_mode')) == 'true') + || (ini_get("safe_mode") == 1 ))) { + $errors[] = array( + 'error'=>'PHP Safe Mode is enabled. ownCloud requires that it is disabled to work properly.', + 'hint'=>'PHP Safe Mode is a deprecated and mostly useless setting that should be disabled. ' + .'Please ask your server administrator to disable it in php.ini or in your webserver config.' + ); + $webServerRestart = true; + } + if (get_magic_quotes_gpc() == 1 ) { + $errors[] = array( + 'error'=>'Magic Quotes is enabled. ownCloud requires that it is disabled to work properly.', + 'hint'=>'Magic Quotes is a deprecated and mostly useless setting that should be disabled. ' + .'Please ask your server administrator to disable it in php.ini or in your webserver config.' + ); + $webServerRestart = true; + } + + if($webServerRestart) { + $errors[] = array( + 'error'=>'PHP modules have been installed, but they are still listed as missing?', + 'hint'=>'Please ask your server administrator to restart the web server.' + ); + } + + // Cache the result of this function + \OC::$session->set('checkServer_suceeded', count($errors) == 0); + + return $errors; + } + + /** + * @brief check if there are still some encrypted files stored + * @return boolean + */ + public static function encryptedFiles() { + //check if encryption was enabled in the past + $encryptedFiles = false; + if (OC_App::isEnabled('files_encryption') === false) { + $view = new OC\Files\View('/' . OCP\User::getUser()); + $keyfilePath = '/files_encryption/keyfiles'; + if ($view->is_dir($keyfilePath)) { + $dircontent = $view->getDirectoryContent($keyfilePath); + if (!empty($dircontent)) { + $encryptedFiles = true; + } + } + } + + return $encryptedFiles; + } + + /** + * @brief Check for correct file permissions of data directory + * @paran string $dataDirectory + * @return array arrays with error messages and hints + */ + public static function checkDataDirectoryPermissions($dataDirectory) { + $errors = array(); + if (self::runningOnWindows()) { + //TODO: permissions checks for windows hosts + } else { + $permissionsModHint = 'Please change the permissions to 0770 so that the directory' + .' cannot be listed by other users.'; + $perms = substr(decoct(@fileperms($dataDirectory)), -3); + if (substr($perms, -1) != '0') { + OC_Helper::chmodr($dataDirectory, 0770); + clearstatcache(); + $perms = substr(decoct(@fileperms($dataDirectory)), -3); + if (substr($perms, 2, 1) != '0') { + $errors[] = array( + 'error' => 'Data directory ('.$dataDirectory.') is readable for other users', + 'hint' => $permissionsModHint + ); + } + } + } + return $errors; + } + + /** + * @return void + */ + public static function displayLoginPage($errors = array()) { + $parameters = array(); + foreach( $errors as $key => $value ) { + $parameters[$value] = true; + } + if (!empty($_POST['user'])) { + $parameters["username"] = $_POST['user']; + $parameters['user_autofocus'] = false; + } else { + $parameters["username"] = ''; + $parameters['user_autofocus'] = true; + } + if (isset($_REQUEST['redirect_url'])) { + $redirectUrl = $_REQUEST['redirect_url']; + $parameters['redirect_url'] = urlencode($redirectUrl); + } + + $parameters['alt_login'] = OC_App::getAlternativeLogIns(); + OC_Template::printGuestPage("", "login", $parameters); + } + + + /** + * @brief Check if the app is enabled, redirects to home if not + * @return void + */ + public static function checkAppEnabled($app) { + if( !OC_App::isEnabled($app)) { + header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); + exit(); + } + } + + /** + * Check if the user is logged in, redirects to home if not. With + * redirect URL parameter to the request URI. + * @return void + */ + public static function checkLoggedIn() { + // Check if we are a user + if( !OC_User::isLoggedIn()) { + header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', + array('redirectUrl' => OC_Request::requestUri()) + )); + exit(); + } + } + + /** + * @brief Check if the user is a admin, redirects to home if not + * @return void + */ + public static function checkAdminUser() { + if( !OC_User::isAdminUser(OC_User::getUser())) { + header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); + exit(); + } + } + + /** + * @brief Check if the user is a subadmin, redirects to home if not + * @return array $groups where the current user is subadmin + */ + public static function checkSubAdminUser() { + if(!OC_SubAdmin::isSubAdmin(OC_User::getUser())) { + header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); + exit(); + } + return true; + } + + /** + * @brief Redirect to the user default page + * @return void + */ + public static function redirectToDefaultPage() { + if(isset($_REQUEST['redirect_url'])) { + $location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url'])); + } + else if (isset(OC::$REQUESTEDAPP) && !empty(OC::$REQUESTEDAPP)) { + $location = OC_Helper::linkToAbsolute( OC::$REQUESTEDAPP, 'index.php' ); + } else { + $defaultPage = OC_Appconfig::getValue('core', 'defaultpage'); + if ($defaultPage) { + $location = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/'.$defaultPage); + } else { + $location = OC_Helper::linkToAbsolute( 'files', 'index.php' ); + } + } + OC_Log::write('core', 'redirectToDefaultPage: '.$location, OC_Log::DEBUG); + header( 'Location: '.$location ); + exit(); + } + + /** + * @brief get an id unique for this instance + * @return string + */ + public static function getInstanceId() { + $id = OC_Config::getValue('instanceid', null); + if(is_null($id)) { + // We need to guarantee at least one letter in instanceid so it can be used as the session_name + $id = 'oc' . self::generateRandomBytes(10); + OC_Config::setValue('instanceid', $id); + } + return $id; + } + + /** + * @brief Static lifespan (in seconds) when a request token expires. + * @see OC_Util::callRegister() + * @see OC_Util::isCallRegistered() + * @description + * Also required for the client side to compute the point in time when to + * request a fresh token. The client will do so when nearly 97% of the + * time span coded here has expired. + */ + public static $callLifespan = 3600; // 3600 secs = 1 hour + + /** + * @brief Register an get/post call. Important to prevent CSRF attacks. + * @todo Write howto: CSRF protection guide + * @return $token Generated token. + * @description + * Creates a 'request token' (random) and stores it inside the session. + * Ever subsequent (ajax) request must use such a valid token to succeed, + * otherwise the request will be denied as a protection against CSRF. + * The tokens expire after a fixed lifespan. + * @see OC_Util::$callLifespan + * @see OC_Util::isCallRegistered() + */ + public static function callRegister() { + // Check if a token exists + if(!\OC::$session->exists('requesttoken')) { + // No valid token found, generate a new one. + $requestToken = self::generateRandomBytes(20); + \OC::$session->set('requesttoken', $requestToken); + } else { + // Valid token already exists, send it + $requestToken = \OC::$session->get('requesttoken'); + } + return($requestToken); + } + + /** + * @brief Check an ajax get/post call if the request token is valid. + * @return boolean False if request token is not set or is invalid. + * @see OC_Util::$callLifespan + * @see OC_Util::callRegister() + */ + public static function isCallRegistered() { + if(!\OC::$session->exists('requesttoken')) { + return false; + } + + if(isset($_GET['requesttoken'])) { + $token = $_GET['requesttoken']; + } elseif(isset($_POST['requesttoken'])) { + $token = $_POST['requesttoken']; + } elseif(isset($_SERVER['HTTP_REQUESTTOKEN'])) { + $token = $_SERVER['HTTP_REQUESTTOKEN']; + } else { + //no token found. + return false; + } + + // Check if the token is valid + if($token !== \OC::$session->get('requesttoken')) { + // Not valid + return false; + } else { + // Valid token + return true; + } + } + + /** + * @brief Check an ajax get/post call if the request token is valid. exit if not. + * @todo Write howto + * @return void + */ + public static function callCheck() { + if(!OC_Util::isCallRegistered()) { + exit(); + } + } + + /** + * @brief Public function to sanitize HTML + * + * This function is used to sanitize HTML and should be applied on any + * string or array of strings before displaying it on a web page. + * + * @param string|array of strings + * @return array with sanitized strings or a single sanitized string, depends on the input parameter. + */ + public static function sanitizeHTML( &$value ) { + if (is_array($value)) { + array_walk_recursive($value, 'OC_Util::sanitizeHTML'); + } else { + //Specify encoding for PHP<5.4 + $value = htmlentities((string)$value, ENT_QUOTES, 'UTF-8'); + } + return $value; + } + + /** + * @brief Public function to encode url parameters + * + * This function is used to encode path to file before output. + * Encoding is done according to RFC 3986 with one exception: + * Character '/' is preserved as is. + * + * @param string $component part of URI to encode + * @return string + */ + public static function encodePath($component) { + $encoded = rawurlencode($component); + $encoded = str_replace('%2F', '/', $encoded); + return $encoded; + } + + /** + * @brief Check if the htaccess file is working + * @return bool + * @description Check if the htaccess file is working by creating a test + * file in the data directory and trying to access via http + */ + public static function isHtAccessWorking() { + // testdata + $fileName = '/htaccesstest.txt'; + $testContent = 'testcontent'; + + // creating a test file + $testFile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$fileName; + + if(file_exists($testFile)) {// already running this test, possible recursive call + return false; + } + + $fp = @fopen($testFile, 'w'); + @fwrite($fp, $testContent); + @fclose($fp); + + // accessing the file via http + $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$fileName); + $fp = @fopen($url, 'r'); + $content=@fread($fp, 2048); + @fclose($fp); + + // cleanup + @unlink($testFile); + + // does it work ? + if($content==$testContent) { + return false; + } else { + return true; + } + } + + /** + * @brief test if webDAV is working properly + * @return bool + * @description + * The basic assumption is that if the server returns 401/Not Authenticated for an unauthenticated PROPFIND + * the web server it self is setup properly. + * + * Why not an authenticated PROPFIND and other verbs? + * - We don't have the password available + * - We have no idea about other auth methods implemented (e.g. OAuth with Bearer header) + * + */ + public static function isWebDAVWorking() { + if (!function_exists('curl_init')) { + return true; + } + $settings = array( + 'baseUri' => OC_Helper::linkToRemote('webdav'), + ); + + $client = new \Sabre_DAV_Client($settings); + + // for this self test we don't care if the ssl certificate is self signed and the peer cannot be verified. + $client->setVerifyPeer(false); + + $return = true; + try { + // test PROPFIND + $client->propfind('', array('{DAV:}resourcetype')); + } catch (\Sabre_DAV_Exception_NotAuthenticated $e) { + $return = true; + } catch (\Exception $e) { + OC_Log::write('core', 'isWebDAVWorking: NO - Reason: '.$e->getMessage(). ' ('.get_class($e).')', OC_Log::WARN); + $return = false; + } + + return $return; + } + + /** + * Check if the setlocal call does not work. This can happen if the right + * local packages are not available on the server. + * @return bool + */ + public static function isSetLocaleWorking() { + // setlocale test is pointless on Windows + if (OC_Util::runningOnWindows() ) { + return true; + } + + $result = setlocale(LC_ALL, 'en_US.UTF-8', 'en_US.UTF8'); + if($result == false) { + return false; + } + return true; + } + + /** + * @brief Check if the PHP module fileinfo is loaded. + * @return bool + */ + public static function fileInfoLoaded() { + return function_exists('finfo_open'); + } + + /** + * @brief Check if the ownCloud server can connect to the internet + * @return bool + */ + public static function isInternetConnectionWorking() { + // in case there is no internet connection on purpose return false + if (self::isInternetConnectionEnabled() === false) { + return false; + } + + // try to connect to owncloud.org to see if http connections to the internet are possible. + $connected = @fsockopen("www.owncloud.org", 80); + if ($connected) { + fclose($connected); + return true; + } else { + // second try in case one server is down + $connected = @fsockopen("apps.owncloud.com", 80); + if ($connected) { + fclose($connected); + return true; + } else { + return false; + } + } + } + + /** + * @brief Check if the connection to the internet is disabled on purpose + * @return bool + */ + public static function isInternetConnectionEnabled(){ + return \OC_Config::getValue("has_internet_connection", true); + } + + /** + * @brief clear all levels of output buffering + * @return void + */ + public static function obEnd(){ + while (ob_get_level()) { + ob_end_clean(); + } + } + + + /** + * @brief Generates a cryptographic secure pseudo-random string + * @param Int $length of the random string + * @return String + * Please also update secureRNGAvailable if you change something here + */ + public static function generateRandomBytes($length = 30) { + // Try to use openssl_random_pseudo_bytes + if (function_exists('openssl_random_pseudo_bytes')) { + $pseudoByte = bin2hex(openssl_random_pseudo_bytes($length, $strong)); + if($strong == true) { + return substr($pseudoByte, 0, $length); // Truncate it to match the length + } + } + + // Try to use /dev/urandom + if (!self::runningOnWindows()) { + $fp = @file_get_contents('/dev/urandom', false, null, 0, $length); + if ($fp !== false) { + $string = substr(bin2hex($fp), 0, $length); + return $string; + } + } + + // Fallback to mt_rand() + $characters = '0123456789'; + $characters .= 'abcdefghijklmnopqrstuvwxyz'; + $charactersLength = strlen($characters)-1; + $pseudoByte = ""; + + // Select some random characters + for ($i = 0; $i < $length; $i++) { + $pseudoByte .= $characters[mt_rand(0, $charactersLength)]; + } + return $pseudoByte; + } + + /** + * @brief Checks if a secure random number generator is available + * @return bool + */ + public static function secureRNGAvailable() { + // Check openssl_random_pseudo_bytes + if(function_exists('openssl_random_pseudo_bytes')) { + openssl_random_pseudo_bytes(1, $strong); + if($strong == true) { + return true; + } + } + + // Check /dev/urandom + if (!self::runningOnWindows()) { + $fp = @file_get_contents('/dev/urandom', false, null, 0, 1); + if ($fp !== false) { + return true; + } + } + + return false; + } + + /** + * @Brief Get file content via curl. + * @param string $url Url to get content + * @return string of the response or false on error + * This function get the content of a page via curl, if curl is enabled. + * If not, file_get_element is used. + */ + public static function getUrlContent($url){ + if (function_exists('curl_init')) { + $curl = curl_init(); + + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_MAXREDIRS, 10); + + curl_setopt($curl, CURLOPT_USERAGENT, "ownCloud Server Crawler"); + if(OC_Config::getValue('proxy', '') != '') { + curl_setopt($curl, CURLOPT_PROXY, OC_Config::getValue('proxy')); + } + if(OC_Config::getValue('proxyuserpwd', '') != '') { + curl_setopt($curl, CURLOPT_PROXYUSERPWD, OC_Config::getValue('proxyuserpwd')); + } + $data = curl_exec($curl); + curl_close($curl); + + } else { + $contextArray = null; + + if(OC_Config::getValue('proxy', '') != '') { + $contextArray = array( + 'http' => array( + 'timeout' => 10, + 'proxy' => OC_Config::getValue('proxy') + ) + ); + } else { + $contextArray = array( + 'http' => array( + 'timeout' => 10 + ) + ); + } + + $ctx = stream_context_create( + $contextArray + ); + $data = @file_get_contents($url, 0, $ctx); + + } + return $data; + } + + /** + * @return bool - well are we running on windows or not + */ + public static function runningOnWindows() { + return (substr(PHP_OS, 0, 3) === "WIN"); + } + + /** + * Handles the case that there may not be a theme, then check if a "default" + * theme exists and take that one + * @return string the theme + */ + public static function getTheme() { + $theme = OC_Config::getValue("theme", ''); + + if($theme === '') { + if(is_dir(OC::$SERVERROOT . '/themes/default')) { + $theme = 'default'; + } + } + + return $theme; + } + + /** + * @brief Clear the opcode cache if one exists + * This is necessary for writing to the config file + * in case the opcode cache does not re-validate files + * @return void + */ + public static function clearOpcodeCache() { + // APC + if (function_exists('apc_clear_cache')) { + apc_clear_cache(); + } + // Zend Opcache + if (function_exists('accelerator_reset')) { + accelerator_reset(); + } + // XCache + if (function_exists('xcache_clear_cache')) { + xcache_clear_cache(XC_TYPE_VAR, 0); + } + // Opcache (PHP >= 5.5) + if (function_exists('opcache_reset')) { + opcache_reset(); + } + } + + /** + * Normalize a unicode string + * @param string $value a not normalized string + * @return bool|string + */ + public static function normalizeUnicode($value) { + if(class_exists('Patchwork\PHP\Shim\Normalizer')) { + $normalizedValue = \Patchwork\PHP\Shim\Normalizer::normalize($value); + if($normalizedValue === false) { + \OC_Log::write( 'core', 'normalizing failed for "' . $value . '"', \OC_Log::WARN); + } else { + $value = $normalizedValue; + } + } + + return $value; + } + + /** + * @return string + */ + public static function basename($file) { + $file = rtrim($file, '/'); + $t = explode('/', $file); + return array_pop($t); + } +} diff --git a/lib/private/vobject.php b/lib/private/vobject.php new file mode 100644 index 00000000000..267176ebc07 --- /dev/null +++ b/lib/private/vobject.php @@ -0,0 +1,207 @@ +. + * + */ + +/** + * This class provides a streamlined interface to the Sabre VObject classes + */ +class OC_VObject{ + /** @var Sabre\VObject\Component */ + protected $vobject; + + /** + * @returns Sabre\VObject\Component + */ + public function getVObject() { + return $this->vobject; + } + + /** + * @brief Parses the VObject + * @param string VObject as string + * @returns Sabre_VObject or null + */ + public static function parse($data) { + try { + Sabre\VObject\Property::$classMap['LAST-MODIFIED'] = 'Sabre\VObject\Property\DateTime'; + $vobject = Sabre\VObject\Reader::read($data); + if ($vobject instanceof Sabre\VObject\Component) { + $vobject = new OC_VObject($vobject); + } + return $vobject; + } catch (Exception $e) { + OC_Log::write('vobject', $e->getMessage(), OC_Log::ERROR); + return null; + } + } + + /** + * @brief Escapes semicolons + * @param string $value + * @return string + */ + public static function escapeSemicolons($value) { + foreach($value as &$i ) { + $i = implode("\\\\;", explode(';', $i)); + } + return implode(';', $value); + } + + /** + * @brief Creates an array out of a multivalue property + * @param string $value + * @return array + */ + public static function unescapeSemicolons($value) { + $array = explode(';', $value); + for($i=0;$ivobject = $vobject_or_name; + } else { + $this->vobject = new Sabre\VObject\Component($vobject_or_name); + } + } + + public function add($item, $itemValue = null) { + if ($item instanceof OC_VObject) { + $item = $item->getVObject(); + } + $this->vobject->add($item, $itemValue); + } + + /** + * @brief Add property to vobject + * @param object $name of property + * @param object $value of property + * @param object $parameters of property + * @returns Sabre_VObject_Property newly created + */ + public function addProperty($name, $value, $parameters=array()) { + if(is_array($value)) { + $value = OC_VObject::escapeSemicolons($value); + } + $property = new Sabre\VObject\Property( $name, $value ); + foreach($parameters as $name => $value) { + $property->parameters[] = new Sabre\VObject\Parameter($name, $value); + } + + $this->vobject->add($property); + return $property; + } + + public function setUID() { + $uid = substr(md5(rand().time()), 0, 10); + $this->vobject->add('UID', $uid); + } + + public function setString($name, $string) { + if ($string != '') { + $string = strtr($string, array("\r\n"=>"\n")); + $this->vobject->__set($name, $string); + }else{ + $this->vobject->__unset($name); + } + } + + /** + * Sets or unsets the Date and Time for a property. + * When $datetime is set to 'now', use the current time + * When $datetime is null, unset the property + * + * @param string property name + * @param DateTime $datetime + * @param int $dateType + * @return void + */ + public function setDateTime($name, $datetime, $dateType=Sabre\VObject\Property\DateTime::LOCALTZ) { + if ($datetime == 'now') { + $datetime = new DateTime(); + } + if ($datetime instanceof DateTime) { + $datetime_element = new Sabre\VObject\Property\DateTime($name); + $datetime_element->setDateTime($datetime, $dateType); + $this->vobject->__set($name, $datetime_element); + }else{ + $this->vobject->__unset($name); + } + } + + public function getAsString($name) { + return $this->vobject->__isset($name) ? + $this->vobject->__get($name)->value : + ''; + } + + public function getAsArray($name) { + $values = array(); + if ($this->vobject->__isset($name)) { + $values = explode(',', $this->getAsString($name)); + $values = array_map('trim', $values); + } + return $values; + } + + public function &__get($name) { + if ($name == 'children') { + return $this->vobject->children; + } + $return = $this->vobject->__get($name); + if ($return instanceof Sabre\VObject\Component) { + $return = new OC_VObject($return); + } + return $return; + } + + public function __set($name, $value) { + return $this->vobject->__set($name, $value); + } + + public function __unset($name) { + return $this->vobject->__unset($name); + } + + public function __isset($name) { + return $this->vobject->__isset($name); + } + + public function __call($function, $arguments) { + return call_user_func_array(array($this->vobject, $function), $arguments); + } +} diff --git a/lib/private/vobject/compoundproperty.php b/lib/private/vobject/compoundproperty.php new file mode 100644 index 00000000000..7fe42574bed --- /dev/null +++ b/lib/private/vobject/compoundproperty.php @@ -0,0 +1,70 @@ +. + * + */ + +namespace OC\VObject; + +/** + * This class overrides \Sabre\VObject\Property::serialize() to not + * double escape commas and semi-colons in compound properties. +*/ +class CompoundProperty extends \Sabre\VObject\Property\Compound { + + /** + * Turns the object back into a serialized blob. + * + * @return string + */ + public function serialize() { + + $str = $this->name; + if ($this->group) { + $str = $this->group . '.' . $this->name; + } + + foreach($this->parameters as $param) { + $str.=';' . $param->serialize(); + } + $src = array( + "\n", + ); + $out = array( + '\n', + ); + $str.=':' . str_replace($src, $out, $this->value); + + $out = ''; + while(strlen($str) > 0) { + if (strlen($str) > 75) { + $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n"; + $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8'); + } else { + $out .= $str . "\r\n"; + $str = ''; + break; + } + } + + return $out; + + } + +} diff --git a/lib/private/vobject/stringproperty.php b/lib/private/vobject/stringproperty.php new file mode 100644 index 00000000000..a9d63a0a789 --- /dev/null +++ b/lib/private/vobject/stringproperty.php @@ -0,0 +1,80 @@ +. + * + */ + +namespace OC\VObject; + +/** + * This class overrides \Sabre\VObject\Property::serialize() properly + * escape commas and semi-colons in string properties. +*/ +class StringProperty extends \Sabre\VObject\Property { + + /** + * Turns the object back into a serialized blob. + * + * @return string + */ + public function serialize() { + + $str = $this->name; + if ($this->group) { + $str = $this->group . '.' . $this->name; + } + + foreach($this->parameters as $param) { + $str.=';' . $param->serialize(); + } + + $src = array( + '\\', + "\n", + ';', + ',', + ); + $out = array( + '\\\\', + '\n', + '\;', + '\,', + ); + $value = strtr($this->value, array('\,' => ',', '\;' => ';', '\\\\' => '\\')); + $str.=':' . str_replace($src, $out, $value); + + $out = ''; + while(strlen($str) > 0) { + if (strlen($str) > 75) { + $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n"; + $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8'); + } else { + $out .= $str . "\r\n"; + $str = ''; + break; + } + } + + return $out; + + } + +} diff --git a/lib/request.php b/lib/request.php deleted file mode 100755 index df33217f95d..00000000000 --- a/lib/request.php +++ /dev/null @@ -1,184 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_Request { - /** - * @brief Check overwrite condition - * @returns bool - */ - private static function isOverwriteCondition($type = '') { - $regex = '/' . OC_Config::getValue('overwritecondaddr', '') . '/'; - return $regex === '//' or preg_match($regex, $_SERVER['REMOTE_ADDR']) === 1 - or ($type !== 'protocol' and OC_Config::getValue('forcessl', false)); - } - - /** - * @brief Returns the server host - * @returns string the server host - * - * Returns the server host, even if the website uses one or more - * reverse proxies - */ - public static function serverHost() { - if(OC::$CLI) { - return 'localhost'; - } - if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) { - return OC_Config::getValue('overwritehost'); - } - if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { - if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { - $host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST']))); - } - else{ - $host=$_SERVER['HTTP_X_FORWARDED_HOST']; - } - } - else{ - if (isset($_SERVER['HTTP_HOST'])) { - return $_SERVER['HTTP_HOST']; - } - if (isset($_SERVER['SERVER_NAME'])) { - return $_SERVER['SERVER_NAME']; - } - return 'localhost'; - } - return $host; - } - - - /** - * @brief Returns the server protocol - * @returns string the server protocol - * - * Returns the server protocol. It respects reverse proxy servers and load balancers - */ - public static function serverProtocol() { - if(OC_Config::getValue('overwriteprotocol', '') !== '' and self::isOverwriteCondition('protocol')) { - return OC_Config::getValue('overwriteprotocol'); - } - if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { - $proto = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']); - }else{ - if(isset($_SERVER['HTTPS']) and !empty($_SERVER['HTTPS']) and ($_SERVER['HTTPS']!='off')) { - $proto = 'https'; - }else{ - $proto = 'http'; - } - } - return $proto; - } - - /** - * @brief Returns the request uri - * @returns string the request uri - * - * Returns the request uri, even if the website uses one or more - * reverse proxies - */ - public static function requestUri() { - $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; - if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) { - $uri = self::scriptName() . substr($uri, strlen($_SERVER['SCRIPT_NAME'])); - } - return $uri; - } - - /** - * @brief Returns the script name - * @returns string the script name - * - * Returns the script name, even if the website uses one or more - * reverse proxies - */ - public static function scriptName() { - $name = $_SERVER['SCRIPT_NAME']; - if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) { - $serverroot = str_replace("\\", '/', substr(__DIR__, 0, -4)); - $suburi = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen($serverroot))); - $name = OC_Config::getValue('overwritewebroot', '') . $suburi; - } - return $name; - } - - /** - * @brief get Path info from request - * @returns string Path info or false when not found - */ - public static function getPathInfo() { - if (array_key_exists('PATH_INFO', $_SERVER)) { - $path_info = $_SERVER['PATH_INFO']; - }else{ - $path_info = self::getRawPathInfo(); - // following is taken from Sabre_DAV_URLUtil::decodePathSegment - $path_info = rawurldecode($path_info); - $encoding = mb_detect_encoding($path_info, array('UTF-8', 'ISO-8859-1')); - - switch($encoding) { - - case 'ISO-8859-1' : - $path_info = utf8_encode($path_info); - - } - // end copy - } - return $path_info; - } - - /** - * @brief get Path info from request, not urldecoded - * @returns string Path info or false when not found - */ - public static function getRawPathInfo() { - $path_info = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME'])); - // Remove the query string from REQUEST_URI - if ($pos = strpos($path_info, '?')) { - $path_info = substr($path_info, 0, $pos); - } - return $path_info; - } - - /** - * @brief Check if this is a no-cache request - * @returns boolean true for no-cache - */ - static public function isNoCache() { - if (!isset($_SERVER['HTTP_CACHE_CONTROL'])) { - return false; - } - return $_SERVER['HTTP_CACHE_CONTROL'] == 'no-cache'; - } - - /** - * @brief Check if the requestor understands gzip - * @returns boolean true for gzip encoding supported - */ - static public function acceptGZip() { - if (!isset($_SERVER['HTTP_ACCEPT_ENCODING'])) { - return false; - } - $HTTP_ACCEPT_ENCODING = $_SERVER["HTTP_ACCEPT_ENCODING"]; - if( strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') !== false ) - return 'x-gzip'; - else if( strpos($HTTP_ACCEPT_ENCODING, 'gzip') !== false ) - return 'gzip'; - return false; - } - - /** - * @brief Check if the requester sent along an mtime - * @returns false or an mtime - */ - static public function hasModificationTime () { - if (isset($_SERVER['HTTP_X_OC_MTIME'])) { - return $_SERVER['HTTP_X_OC_MTIME']; - } else { - return false; - } - } -} diff --git a/lib/response.php b/lib/response.php deleted file mode 100644 index 674176d078b..00000000000 --- a/lib/response.php +++ /dev/null @@ -1,167 +0,0 @@ -0 cache time in seconds - * 0 and <0 enable default browser caching - * null cache indefinitly - */ - static public function enableCaching($cache_time = null) { - if (is_numeric($cache_time)) { - header('Pragma: public');// enable caching in IE - if ($cache_time > 0) { - self::setExpiresHeader('PT'.$cache_time.'S'); - header('Cache-Control: max-age='.$cache_time.', must-revalidate'); - } - else { - self::setExpiresHeader(0); - header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); - } - } - else { - header('Cache-Control: cache'); - header('Pragma: cache'); - } - - } - - /** - * @brief disable browser caching - * @see enableCaching with cache_time = 0 - */ - static public function disableCaching() { - self::enableCaching(0); - } - - /** - * @brief Set response status - * @param $status a HTTP status code, see also the STATUS constants - */ - static public function setStatus($status) { - $protocol = $_SERVER['SERVER_PROTOCOL']; - switch($status) { - case self::STATUS_NOT_MODIFIED: - $status = $status . ' Not Modified'; - break; - case self::STATUS_TEMPORARY_REDIRECT: - if ($protocol == 'HTTP/1.1') { - $status = $status . ' Temporary Redirect'; - break; - } else { - $status = self::STATUS_FOUND; - // fallthrough - } - case self::STATUS_FOUND; - $status = $status . ' Found'; - break; - case self::STATUS_NOT_FOUND; - $status = $status . ' Not Found'; - break; - case self::STATUS_INTERNAL_SERVER_ERROR; - $status = $status . ' Internal Server Error'; - break; - } - header($protocol.' '.$status); - } - - /** - * @brief Send redirect response - * @param $location to redirect to - */ - static public function redirect($location) { - self::setStatus(self::STATUS_TEMPORARY_REDIRECT); - header('Location: '.$location); - } - - /** - * @brief Set reponse expire time - * @param $expires date-time when the response expires - * string for DateInterval from now - * DateTime object when to expire response - */ - static public function setExpiresHeader($expires) { - if (is_string($expires) && $expires[0] == 'P') { - $interval = $expires; - $expires = new DateTime('now'); - $expires->add(new DateInterval($interval)); - } - if ($expires instanceof DateTime) { - $expires->setTimezone(new DateTimeZone('GMT')); - $expires = $expires->format(DateTime::RFC2822); - } - header('Expires: '.$expires); - } - - /** - * Checks and set ETag header, when the request matches sends a - * 'not modified' response - * @param $etag token to use for modification check - */ - static public function setETagHeader($etag) { - if (empty($etag)) { - return; - } - $etag = '"'.$etag.'"'; - if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && - trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { - self::setStatus(self::STATUS_NOT_MODIFIED); - exit; - } - header('ETag: '.$etag); - } - - /** - * Checks and set Last-Modified header, when the request matches sends a - * 'not modified' response - * @param $lastModified time when the reponse was last modified - */ - static public function setLastModifiedHeader($lastModified) { - if (empty($lastModified)) { - return; - } - if (is_int($lastModified)) { - $lastModified = gmdate(DateTime::RFC2822, $lastModified); - } - if ($lastModified instanceof DateTime) { - $lastModified = $lastModified->format(DateTime::RFC2822); - } - if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && - trim($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) { - self::setStatus(self::STATUS_NOT_MODIFIED); - exit; - } - header('Last-Modified: '.$lastModified); - } - - /** - * @brief Send file as response, checking and setting caching headers - * @param $filepath of file to send - */ - static public function sendFile($filepath) { - $fp = fopen($filepath, 'rb'); - if ($fp) { - self::setLastModifiedHeader(filemtime($filepath)); - self::setETagHeader(md5_file($filepath)); - - header('Content-Length: '.filesize($filepath)); - fpassthru($fp); - } - else { - self::setStatus(self::STATUS_NOT_FOUND); - } - } -} diff --git a/lib/route.php b/lib/route.php deleted file mode 100644 index 5901717c094..00000000000 --- a/lib/route.php +++ /dev/null @@ -1,116 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -use Symfony\Component\Routing\Route; - -class OC_Route extends Route { - /** - * Specify the method when this route is to be used - * - * @param string $method HTTP method (uppercase) - */ - public function method($method) { - $this->setRequirement('_method', strtoupper($method)); - return $this; - } - - /** - * Specify POST as the method to use with this route - */ - public function post() { - $this->method('POST'); - return $this; - } - - /** - * Specify GET as the method to use with this route - */ - public function get() { - $this->method('GET'); - return $this; - } - - /** - * Specify PUT as the method to use with this route - */ - public function put() { - $this->method('PUT'); - return $this; - } - - /** - * Specify DELETE as the method to use with this route - */ - public function delete() { - $this->method('DELETE'); - return $this; - } - - /** - * Defaults to use for this route - * - * @param array $defaults The defaults - */ - public function defaults($defaults) { - $action = $this->getDefault('action'); - $this->setDefaults($defaults); - if (isset($defaults['action'])) { - $action = $defaults['action']; - } - $this->action($action); - return $this; - } - - /** - * Requirements for this route - * - * @param array $requirements The requirements - */ - public function requirements($requirements) { - $method = $this->getRequirement('_method'); - $this->setRequirements($requirements); - if (isset($requirements['_method'])) { - $method = $requirements['_method']; - } - if ($method) { - $this->method($method); - } - return $this; - } - - /** - * The action to execute when this route matches - * @param string|callable $class the class or a callable - * @param string $function the function to use with the class - * - * This function is called with $class set to a callable or - * to the class with $function - */ - public function action($class, $function = null) { - $action = array($class, $function); - if (is_null($function)) { - $action = $class; - } - $this->setDefault('action', $action); - return $this; - } - - /** - * The action to execute when this route matches, includes a file like - * it is called directly - * @param $file - */ - public function actionInclude($file) { - $function = create_function('$param', - 'unset($param["_route"]);' - .'$_GET=array_merge($_GET, $param);' - .'unset($param);' - .'require_once "'.$file.'";'); - $this->action($function); - } -} diff --git a/lib/router.php b/lib/router.php deleted file mode 100644 index dbaca9e0d5d..00000000000 --- a/lib/router.php +++ /dev/null @@ -1,183 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -use Symfony\Component\Routing\Matcher\UrlMatcher; -use Symfony\Component\Routing\Generator\UrlGenerator; -use Symfony\Component\Routing\RequestContext; -use Symfony\Component\Routing\RouteCollection; -//use Symfony\Component\Routing\Route; - -class OC_Router { - protected $collections = array(); - protected $collection = null; - protected $root = null; - - protected $generator = null; - protected $routing_files; - protected $cache_key; - - public function __construct() { - $baseUrl = OC_Helper::linkTo('', 'index.php'); - if ( !OC::$CLI) { - $method = $_SERVER['REQUEST_METHOD']; - }else{ - $method = 'GET'; - } - $host = OC_Request::serverHost(); - $schema = OC_Request::serverProtocol(); - $this->context = new RequestContext($baseUrl, $method, $host, $schema); - // TODO cache - $this->root = $this->getCollection('root'); - } - - public function getRoutingFiles() { - if (!isset($this->routing_files)) { - $this->routing_files = array(); - foreach(OC_APP::getEnabledApps() as $app) { - $file = OC_App::getAppPath($app).'/appinfo/routes.php'; - if(file_exists($file)) { - $this->routing_files[$app] = $file; - } - } - } - return $this->routing_files; - } - - public function getCacheKey() { - if (!isset($this->cache_key)) { - $files = $this->getRoutingFiles(); - $files[] = 'settings/routes.php'; - $files[] = 'core/routes.php'; - $files[] = 'ocs/routes.php'; - $this->cache_key = OC_Cache::generateCacheKeyFromFiles($files); - } - return $this->cache_key; - } - - /** - * loads the api routes - */ - public function loadRoutes() { - foreach($this->getRoutingFiles() as $app => $file) { - $this->useCollection($app); - require_once $file; - $collection = $this->getCollection($app); - $this->root->addCollection($collection, '/apps/'.$app); - } - $this->useCollection('root'); - require_once 'settings/routes.php'; - require_once 'core/routes.php'; - - // include ocs routes - require_once 'ocs/routes.php'; - $collection = $this->getCollection('ocs'); - $this->root->addCollection($collection, '/ocs'); - } - - protected function getCollection($name) { - if (!isset($this->collections[$name])) { - $this->collections[$name] = new RouteCollection(); - } - return $this->collections[$name]; - } - - /** - * Sets the collection to use for adding routes - * - * @param string $name Name of the colletion to use. - */ - public function useCollection($name) { - $this->collection = $this->getCollection($name); - } - - /** - * Create a OC_Route. - * - * @param string $name Name of the route to create. - * @param string $pattern The pattern to match - * @param array $defaults An array of default parameter values - * @param array $requirements An array of requirements for parameters (regexes) - */ - public function create($name, $pattern, array $defaults = array(), array $requirements = array()) { - $route = new OC_Route($pattern, $defaults, $requirements); - $this->collection->add($name, $route); - return $route; - } - - /** - * Find the route matching $url. - * - * @param string $url The url to find - */ - public function match($url) { - $matcher = new UrlMatcher($this->root, $this->context); - $parameters = $matcher->match($url); - if (isset($parameters['action'])) { - $action = $parameters['action']; - if (!is_callable($action)) { - var_dump($action); - throw new Exception('not a callable action'); - } - unset($parameters['action']); - call_user_func($action, $parameters); - } elseif (isset($parameters['file'])) { - include $parameters['file']; - } else { - throw new Exception('no action available'); - } - } - - /** - * Get the url generator - * - */ - public function getGenerator() - { - if (null !== $this->generator) { - return $this->generator; - } - - return $this->generator = new UrlGenerator($this->root, $this->context); - } - - /** - * Generate url based on $name and $parameters - * - * @param string $name Name of the route to use. - * @param array $parameters Parameters for the route - */ - public function generate($name, $parameters = array(), $absolute = false) - { - return $this->getGenerator()->generate($name, $parameters, $absolute); - } - - /** - * Generate JSON response for routing in javascript - */ - public static function JSRoutes() - { - $router = OC::getRouter(); - - $etag = $router->getCacheKey(); - OC_Response::enableCaching(); - OC_Response::setETagHeader($etag); - - $root = $router->getCollection('root'); - $routes = array(); - foreach($root->all() as $name => $route) { - $compiled_route = $route->compile(); - $defaults = $route->getDefaults(); - unset($defaults['action']); - $routes[$name] = array( - 'tokens' => $compiled_route->getTokens(), - 'defaults' => $defaults, - ); - } - OCP\JSON::success ( array( 'data' => $routes ) ); - } -} diff --git a/lib/search.php b/lib/search.php deleted file mode 100644 index b9c75dfc333..00000000000 --- a/lib/search.php +++ /dev/null @@ -1,90 +0,0 @@ -. - * - */ - - -/** - * provides an interface to all search providers - */ -class OC_Search{ - static private $providers=array(); - static private $registeredProviders=array(); - - /** - * remove all registered search providers - */ - public static function clearProviders() { - self::$providers=array(); - self::$registeredProviders=array(); - } - - /** - * register a new search provider to be used - * @param string $provider class name of a OC_Search_Provider - */ - public static function registerProvider($class, $options=array()) { - self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); - } - - /** - * search all provider for $query - * @param string query - * @return array An array of OC_Search_Result's - */ - public static function search($query) { - self::initProviders(); - $results=array(); - foreach(self::$providers as $provider) { - $results=array_merge($results, $provider->search($query)); - } - return $results; - } - - /** - * remove an existing search provider - * @param string $provider class name of a OC_Search_Provider - */ - public static function removeProvider($provider) { - self::$registeredProviders = array_filter( - self::$registeredProviders, - function ($element) use ($provider) { - return ($element['class'] != $provider); - } - ); - // force regeneration of providers on next search - self::$providers=array(); - } - - - /** - * create instances of all the registered search providers - */ - private static function initProviders() { - if(count(self::$providers)>0) { - return; - } - foreach(self::$registeredProviders as $provider) { - $class=$provider['class']; - $options=$provider['options']; - self::$providers[]=new $class($options); - } - } -} diff --git a/lib/search/provider.php b/lib/search/provider.php deleted file mode 100644 index b617b9c5d94..00000000000 --- a/lib/search/provider.php +++ /dev/null @@ -1,18 +0,0 @@ -options=$options; - } - - /** - * search for $query - * @param string $query - * @return array An array of OC_Search_Result's - */ - abstract public function search($query); -} diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php deleted file mode 100644 index 9bd50931517..00000000000 --- a/lib/search/provider/file.php +++ /dev/null @@ -1,46 +0,0 @@ - $path)); - $type = (string)$l->t('Files'); - }else{ - $link = OC_Helper::linkToRoute( 'download', array('file' => $path)); - $mimeBase = $fileData['mimepart']; - switch($mimeBase) { - case 'audio': - $skip = true; - break; - case 'text': - $type = (string)$l->t('Text'); - break; - case 'image': - $type = (string)$l->t('Images'); - break; - default: - if($mime=='application/xml') { - $type = (string)$l->t('Text'); - }else{ - $type = (string)$l->t('Files'); - } - } - } - if(!$skip) { - $results[] = new OC_Search_Result($name, $text, $link, $type, $container); - } - } - return $results; - } -} diff --git a/lib/search/result.php b/lib/search/result.php deleted file mode 100644 index 42275c2df11..00000000000 --- a/lib/search/result.php +++ /dev/null @@ -1,26 +0,0 @@ -name=$name; - $this->text=$text; - $this->link=$link; - $this->type=$type; - $this->container=$container; - } -} diff --git a/lib/server.php b/lib/server.php deleted file mode 100644 index cabb15324ec..00000000000 --- a/lib/server.php +++ /dev/null @@ -1,255 +0,0 @@ -registerService('ContactsManager', function($c) { - return new ContactsManager(); - }); - $this->registerService('Request', function($c) { - $params = array(); - - // we json decode the body only in case of content type json - if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') !== false ) { - $params = json_decode(file_get_contents('php://input'), true); - $params = is_array($params) ? $params: array(); - } - - return new Request( - array( - 'get' => $_GET, - 'post' => $_POST, - 'files' => $_FILES, - 'server' => $_SERVER, - 'env' => $_ENV, - 'cookies' => $_COOKIE, - 'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) - ? $_SERVER['REQUEST_METHOD'] - : null, - 'params' => $params, - 'urlParams' => $c['urlParams'] - ) - ); - }); - $this->registerService('PreviewManager', function($c) { - return new PreviewManager(); - }); - $this->registerService('TagManager', function($c) { - $user = \OC_User::getUser(); - return new TagManager($user); - }); - $this->registerService('RootFolder', function($c) { - // TODO: get user and user manager from container as well - $user = \OC_User::getUser(); - /** @var $c SimpleContainer */ - $userManager = $c->query('UserManager'); - $user = $userManager->get($user); - $manager = \OC\Files\Filesystem::getMountManager(); - $view = new View(); - return new Root($manager, $view, $user); - }); - $this->registerService('UserManager', function($c) { - return new \OC\User\Manager(); - }); - $this->registerService('UserSession', function($c) { - /** @var $c SimpleContainer */ - $manager = $c->query('UserManager'); - $userSession = new \OC\User\Session($manager, \OC::$session); - $userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) { - \OC_Hook::emit('OC_User', 'pre_createUser', array('run' => true, 'uid' => $uid, 'password' => $password)); - }); - $userSession->listen('\OC\User', 'postCreateUser', function ($user, $password) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'post_createUser', array('uid' => $user->getUID(), 'password' => $password)); - }); - $userSession->listen('\OC\User', 'preDelete', function ($user) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'pre_deleteUser', array('run' => true, 'uid' => $user->getUID())); - }); - $userSession->listen('\OC\User', 'postDelete', function ($user) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'post_deleteUser', array('uid' => $user->getUID())); - }); - $userSession->listen('\OC\User', 'preSetPassword', function ($user, $password, $recoveryPassword) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'pre_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); - }); - $userSession->listen('\OC\User', 'postSetPassword', function ($user, $password, $recoveryPassword) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'post_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); - }); - $userSession->listen('\OC\User', 'preLogin', function ($uid, $password) { - \OC_Hook::emit('OC_User', 'pre_login', array('run' => true, 'uid' => $uid, 'password' => $password)); - }); - $userSession->listen('\OC\User', 'postLogin', function ($user, $password) { - /** @var $user \OC\User\User */ - \OC_Hook::emit('OC_User', 'post_login', array('run' => true, 'uid' => $user->getUID(), 'password' => $password)); - }); - $userSession->listen('\OC\User', 'logout', function () { - \OC_Hook::emit('OC_User', 'logout', array()); - }); - return $userSession; - }); - $this->registerService('NavigationManager', function($c) { - return new \OC\NavigationManager(); - }); - $this->registerService('AllConfig', function($c) { - return new \OC\AllConfig(); - }); - $this->registerService('UserCache', function($c) { - return new UserCache(); - }); - } - - /** - * @return \OCP\Contacts\IManager - */ - function getContactsManager() { - return $this->query('ContactsManager'); - } - - /** - * The current request object holding all information about the request - * currently being processed is returned from this method. - * In case the current execution was not initiated by a web request null is returned - * - * @return \OCP\IRequest|null - */ - function getRequest() { - return $this->query('Request'); - } - - /** - * Returns the preview manager which can create preview images for a given file - * - * @return \OCP\IPreview - */ - function getPreviewManager() { - return $this->query('PreviewManager'); - } - - /** - * Returns the tag manager which can get and set tags for different object types - * - * @see \OCP\ITagManager::load() - * @return \OCP\ITagManager - */ - function getTagManager() { - return $this->query('TagManager'); - } - - /** - * Returns the root folder of ownCloud's data directory - * - * @return \OCP\Files\Folder - */ - function getRootFolder() { - return $this->query('RootFolder'); - } - - /** - * Returns a view to ownCloud's files folder - * - * @return \OCP\Files\Folder - */ - function getUserFolder() { - - $dir = '/files'; - $root = $this->getRootFolder(); - $folder = null; - if(!$root->nodeExists($dir)) { - $folder = $root->newFolder($dir); - } else { - $folder = $root->get($dir); - } - return $folder; - } - - /** - * Returns an app-specific view in ownClouds data directory - * - * @return \OCP\Files\Folder - */ - function getAppFolder() { - - $dir = '/' . \OC_App::getCurrentApp(); - $root = $this->getRootFolder(); - $folder = null; - if(!$root->nodeExists($dir)) { - $folder = $root->newFolder($dir); - } else { - $folder = $root->get($dir); - } - return $folder; - } - - /** - * @return \OC\User\Manager - */ - function getUserManager() { - return $this->query('UserManager'); - } - - /** - * @return \OC\User\Session - */ - function getUserSession() { - return $this->query('UserSession'); - } - - /** - * @return \OC\NavigationManager - */ - function getNavigationManager() { - return $this->query('NavigationManager'); - } - - /** - * @return \OC\Config - */ - function getConfig() { - return $this->query('AllConfig'); - } - - /** - * Returns an ICache instance - * - * @return \OCP\ICache - */ - function getCache() { - return $this->query('UserCache'); - } - - /** - * Returns the current session - * - * @return \OCP\ISession - */ - function getSession() { - return \OC::$session; - } - - /** - * Returns the current session - * - * @return \OCP\IDBConnection - */ - function getDatabaseConnection() { - return \OC_DB::getConnection(); - } -} diff --git a/lib/session/internal.php b/lib/session/internal.php deleted file mode 100644 index 60aecccc8aa..00000000000 --- a/lib/session/internal.php +++ /dev/null @@ -1,39 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Session; - -/** - * Class Internal - * - * wrap php's internal session handling into the Session interface - * - * @package OC\Session - */ -class Internal extends Memory { - public function __construct($name) { - session_name($name); - session_start(); - if (!isset($_SESSION)) { - throw new \Exception('Failed to start session'); - } - $this->data = $_SESSION; - } - - public function __destruct() { - $_SESSION = $this->data; - session_write_close(); - } - - public function clear() { - session_unset(); - @session_regenerate_id(true); - @session_start(); - $this->data = $_SESSION = array(); - } -} diff --git a/lib/session/memory.php b/lib/session/memory.php deleted file mode 100644 index c148ff4b9b9..00000000000 --- a/lib/session/memory.php +++ /dev/null @@ -1,63 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Session; - -/** - * Class Internal - * - * store session data in an in-memory array, not persistance - * - * @package OC\Session - */ -class Memory extends Session { - protected $data; - - public function __construct($name) { - //no need to use $name since all data is already scoped to this instance - $this->data = array(); - } - - /** - * @param string $key - * @param mixed $value - */ - public function set($key, $value) { - $this->data[$key] = $value; - } - - /** - * @param string $key - * @return mixed - */ - public function get($key) { - if (!$this->exists($key)) { - return null; - } - return $this->data[$key]; - } - - /** - * @param string $key - * @return bool - */ - public function exists($key) { - return isset($this->data[$key]); - } - - /** - * @param string $key - */ - public function remove($key) { - unset($this->data[$key]); - } - - public function clear() { - $this->data = array(); - } -} diff --git a/lib/session/session.php b/lib/session/session.php deleted file mode 100644 index c55001eccac..00000000000 --- a/lib/session/session.php +++ /dev/null @@ -1,79 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Session; - -abstract class Session implements \ArrayAccess, \OCP\ISession { - /** - * $name serves as a namespace for the session keys - * - * @param string $name - */ - abstract public function __construct($name); - - /** - * @param string $key - * @param mixed $value - */ - abstract public function set($key, $value); - - /** - * @param string $key - * @return mixed should return null if $key does not exist - */ - abstract public function get($key); - - /** - * @param string $key - * @return bool - */ - abstract public function exists($key); - - /** - * should not throw any errors if $key does not exist - * - * @param string $key - */ - abstract public function remove($key); - - /** - * removes all entries within the cache namespace - */ - abstract public function clear(); - - /** - * @param mixed $offset - * @return bool - */ - public function offsetExists($offset) { - return $this->exists($offset); - } - - /** - * @param mixed $offset - * @return mixed - */ - public function offsetGet($offset) { - return $this->get($offset); - } - - /** - * @param mixed $offset - * @param mixed $value - */ - public function offsetSet($offset, $value) { - $this->set($offset, $value); - } - - /** - * @param mixed $offset - */ - public function offsetUnset($offset) { - $this->remove($offset); - } -} diff --git a/lib/setup.php b/lib/setup.php deleted file mode 100644 index 6bf3c88370f..00000000000 --- a/lib/setup.php +++ /dev/null @@ -1,192 +0,0 @@ - '\OC\Setup\MySQL', - 'pgsql' => '\OC\Setup\PostgreSQL', - 'oci' => '\OC\Setup\OCI', - 'mssql' => '\OC\Setup\MSSQL', - 'sqlite' => '\OC\Setup\Sqlite', - 'sqlite3' => '\OC\Setup\Sqlite', - ); - - public static function getTrans(){ - return OC_L10N::get('lib'); - } - - public static function install($options) { - $l = self::getTrans(); - - $error = array(); - $dbtype = $options['dbtype']; - - if(empty($options['adminlogin'])) { - $error[] = $l->t('Set an admin username.'); - } - if(empty($options['adminpass'])) { - $error[] = $l->t('Set an admin password.'); - } - if(empty($options['directory'])) { - $options['directory'] = OC::$SERVERROOT."/data"; - } - - if (!isset(self::$dbSetupClasses[$dbtype])) { - $dbtype = 'sqlite'; - } - - $class = self::$dbSetupClasses[$dbtype]; - $dbSetup = new $class(self::getTrans(), 'db_structure.xml'); - $error = array_merge($error, $dbSetup->validate($options)); - - if(count($error) != 0) { - return $error; - } - - //no errors, good - $username = htmlspecialchars_decode($options['adminlogin']); - $password = htmlspecialchars_decode($options['adminpass']); - $datadir = htmlspecialchars_decode($options['directory']); - - if (OC_Util::runningOnWindows()) { - $datadir = rtrim(realpath($datadir), '\\'); - } - - //use sqlite3 when available, otherise sqlite2 will be used. - if($dbtype=='sqlite' and class_exists('SQLite3')) { - $dbtype='sqlite3'; - } - - //generate a random salt that is used to salt the local user passwords - $salt = OC_Util::generateRandomBytes(30); - OC_Config::setValue('passwordsalt', $salt); - - //write the config file - OC_Config::setValue('datadirectory', $datadir); - OC_Config::setValue('dbtype', $dbtype); - OC_Config::setValue('version', implode('.', OC_Util::getVersion())); - try { - $dbSetup->initialize($options); - $dbSetup->setupDatabase($username); - } catch (DatabaseSetupException $e) { - $error[] = array( - 'error' => $e->getMessage(), - 'hint' => $e->getHint() - ); - return($error); - } catch (Exception $e) { - $error[] = array( - 'error' => 'Error while trying to create admin user: ' . $e->getMessage(), - 'hint' => '' - ); - return($error); - } - - //create the user and group - try { - OC_User::createUser($username, $password); - } - catch(Exception $exception) { - $error[] = $exception->getMessage(); - } - - if(count($error) == 0) { - OC_Appconfig::setValue('core', 'installedat', microtime(true)); - OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true)); - OC_AppConfig::setValue('core', 'remote_core.css', '/core/minimizer.php'); - OC_AppConfig::setValue('core', 'remote_core.js', '/core/minimizer.php'); - - OC_Group::createGroup('admin'); - OC_Group::addToGroup($username, 'admin'); - OC_User::login($username, $password); - - //guess what this does - OC_Installer::installShippedApps(); - - //create htaccess files for apache hosts - if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) { - self::createHtaccess(); - } - - //and we are done - OC_Config::setValue('installed', true); - } - - return $error; - } - - /** - * create .htaccess files for apache hosts - */ - private static function createHtaccess() { - $content = "\n"; - $content.= "\n"; - $content.= "\n"; - $content.= "SetEnvIfNoCase ^Authorization$ \"(.+)\" XAUTHORIZATION=$1\n"; - $content.= "RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION\n"; - $content.= "\n"; - $content.= "\n"; - $content.= "\n"; - $content.= "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page - $content.= "ErrorDocument 404 ".OC::$WEBROOT."/core/templates/404.php\n";//custom 404 error page - $content.= "\n"; - $content.= "php_value upload_max_filesize 512M\n";//upload limit - $content.= "php_value post_max_size 512M\n"; - $content.= "php_value memory_limit 512M\n"; - $content.= "php_value mbstring.func_overload 0\n"; - $content.= "\n"; - $content.= " SetEnv htaccessWorking true\n"; - $content.= "\n"; - $content.= "\n"; - $content.= "\n"; - $content.= "RewriteEngine on\n"; - $content.= "RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n"; - $content.= "RewriteRule ^.well-known/host-meta /public.php?service=host-meta [QSA,L]\n"; - $content.= "RewriteRule ^.well-known/carddav /remote.php/carddav/ [R]\n"; - $content.= "RewriteRule ^.well-known/caldav /remote.php/caldav/ [R]\n"; - $content.= "RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]\n"; - $content.= "RewriteRule ^remote/(.*) remote.php [QSA,L]\n"; - $content.= "\n"; - $content.= "\n"; - $content.= "AddType image/svg+xml svg svgz\n"; - $content.= "AddEncoding gzip svgz\n"; - $content.= "\n"; - $content.= "\n"; - $content.= "DirectoryIndex index.php index.html\n"; - $content.= "\n"; - $content.= "AddDefaultCharset utf-8\n"; - $content.= "Options -Indexes\n"; - @file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it - - self::protectDataDirectory(); - } - - public static function protectDataDirectory() { - $content = "deny from all\n"; - $content.= "IndexIgnore *"; - file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content); - file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/index.html', ''); - } - - /** - * @brief Post installation checks - */ - public static function postSetupCheck($params) { - // setup was successful -> webdav testing now - $l = self::getTrans(); - if (OC_Util::isWebDAVWorking()) { - header("Location: ".OC::$WEBROOT.'/'); - } else { - - $error = $l->t('Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken.'); - $hint = $l->t('Please double check the installation guides.', - 'http://doc.owncloud.org/server/5.0/admin_manual/installation.html'); - - OC_Template::printErrorPage($error, $hint); - exit(); - } - } -} diff --git a/lib/setup/abstractdatabase.php b/lib/setup/abstractdatabase.php deleted file mode 100644 index 0beada7bd29..00000000000 --- a/lib/setup/abstractdatabase.php +++ /dev/null @@ -1,50 +0,0 @@ -trans = $trans; - $this->dbDefinitionFile = $dbDefinitionFile; - } - - public function validate($config) { - $errors = array(); - if(empty($config['dbuser'])) { - $errors[] = $this->trans->t("%s enter the database username.", array($this->dbprettyname)); - } - if(empty($config['dbname'])) { - $errors[] = $this->trans->t("%s enter the database name.", array($this->dbprettyname)); - } - if(substr_count($config['dbname'], '.') >= 1) { - $errors[] = $this->trans->t("%s you may not use dots in the database name", array($this->dbprettyname)); - } - return $errors; - } - - public function initialize($config) { - $dbuser = $config['dbuser']; - $dbpass = $config['dbpass']; - $dbname = $config['dbname']; - $dbhost = !empty($config['dbhost']) ? $config['dbhost'] : 'localhost'; - $dbtableprefix = isset($config['dbtableprefix']) ? $config['dbtableprefix'] : 'oc_'; - - \OC_Config::setValue('dbname', $dbname); - \OC_Config::setValue('dbhost', $dbhost); - \OC_Config::setValue('dbtableprefix', $dbtableprefix); - - $this->dbuser = $dbuser; - $this->dbpassword = $dbpass; - $this->dbname = $dbname; - $this->dbhost = $dbhost; - $this->tableprefix = $dbtableprefix; - } -} diff --git a/lib/setup/mssql.php b/lib/setup/mssql.php deleted file mode 100644 index b8329f99079..00000000000 --- a/lib/setup/mssql.php +++ /dev/null @@ -1,182 +0,0 @@ - "master", "UID" => $this->dbuser, "PWD" => $this->dbpassword); - - $masterConnection = @sqlsrv_connect($this->dbhost, $masterConnectionInfo); - if(!$masterConnection) { - $entry = null; - if( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - throw new \DatabaseSetupException($this->trans->t('MS SQL username and/or password not valid: %s', array($entry)), - $this->trans->t('You need to enter either an existing account or the administrator.')); - } - - \OC_Config::setValue('dbuser', $this->dbuser); - \OC_Config::setValue('dbpassword', $this->dbpassword); - - $this->createDBLogin($masterConnection); - - $this->createDatabase($masterConnection); - - $this->createDBUser($masterConnection); - - sqlsrv_close($masterConnection); - - $this->createDatabaseStructure(); - } - - private function createDBLogin($connection) { - $query = "SELECT * FROM master.sys.server_principals WHERE name = '".$this->dbuser."';"; - $result = sqlsrv_query($connection, $query); - if ($result === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } else { - $row = sqlsrv_fetch_array($result); - - if ($row === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } else { - if ($row == null) { - $query = "CREATE LOGIN [".$this->dbuser."] WITH PASSWORD = '".$this->dbpassword."';"; - $result = sqlsrv_query($connection, $query); - if (!$result or $result === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } - } - } - } - } - - private function createDBUser($connection) { - $query = "SELECT * FROM [".$this->dbname."].sys.database_principals WHERE name = '".$this->dbuser."';"; - $result = sqlsrv_query($connection, $query); - if ($result === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } else { - $row = sqlsrv_fetch_array($result); - - if ($row === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } else { - if ($row == null) { - $query = "USE [".$this->dbname."]; CREATE USER [".$this->dbuser."] FOR LOGIN [".$this->dbuser."];"; - $result = sqlsrv_query($connection, $query); - if (!$result || $result === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry = 'DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } - } - - $query = "USE [".$this->dbname."]; EXEC sp_addrolemember 'db_owner', '".$this->dbuser."';"; - $result = sqlsrv_query($connection, $query); - if (!$result || $result === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } - } - } - } - - private function createDatabase($connection) { - $query = "CREATE DATABASE [".$this->dbname."];"; - $result = sqlsrv_query($connection, $query); - if (!$result || $result === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } - } - - private function createDatabaseStructure() { - $connectionInfo = array( "Database" => $this->dbname, "UID" => $this->dbuser, "PWD" => $this->dbpassword); - - $connection = @sqlsrv_connect($this->dbhost, $connectionInfo); - - //fill the database if needed - $query = "SELECT * FROM INFORMATION_SCHEMA.TABLES" - ." WHERE TABLE_SCHEMA = '".$this->dbname."'" - ." AND TABLE_NAME = '".$this->tableprefix."users'"; - $result = sqlsrv_query($connection, $query); - if ($result === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } else { - $row = sqlsrv_fetch_array($result); - - if ($row === false) { - if ( ($errors = sqlsrv_errors() ) != null) { - $entry='DB Error: "'.print_r(sqlsrv_errors()).'"
'; - } else { - $entry = ''; - } - $entry.='Offending command was: '.$query.'
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } else { - if ($row == null) { - \OC_DB::createDbFromStructure($this->dbDefinitionFile); - } - } - } - - sqlsrv_close($connection); - } -} diff --git a/lib/setup/mysql.php b/lib/setup/mysql.php deleted file mode 100644 index d97b6d2602f..00000000000 --- a/lib/setup/mysql.php +++ /dev/null @@ -1,95 +0,0 @@ -dbhost, $this->dbuser, $this->dbpassword); - if(!$connection) { - throw new \DatabaseSetupException($this->trans->t('MySQL username and/or password not valid'), - $this->trans->t('You need to enter either an existing account or the administrator.')); - } - $oldUser=\OC_Config::getValue('dbuser', false); - - //this should be enough to check for admin rights in mysql - $query="SELECT user FROM mysql.user WHERE user='$this->dbuser'"; - if(mysql_query($query, $connection)) { - //use the admin login data for the new database user - - //add prefix to the mysql user name to prevent collisions - $this->dbuser=substr('oc_'.$username, 0, 16); - if($this->dbuser!=$oldUser) { - //hash the password so we don't need to store the admin config in the config file - $this->dbpassword=\OC_Util::generateRandomBytes(30); - - $this->createDBUser($connection); - - \OC_Config::setValue('dbuser', $this->dbuser); - \OC_Config::setValue('dbpassword', $this->dbpassword); - } - - //create the database - $this->createDatabase($connection); - } - else { - if($this->dbuser!=$oldUser) { - \OC_Config::setValue('dbuser', $this->dbuser); - \OC_Config::setValue('dbpassword', $this->dbpassword); - } - - //create the database - $this->createDatabase($connection); - } - - //fill the database if needed - $query='select count(*) from information_schema.tables' - ." where table_schema='".$this->dbname."' AND table_name = '".$this->tableprefix."users';"; - $result = mysql_query($query, $connection); - if($result) { - $row=mysql_fetch_row($result); - } - if(!$result or $row[0]==0) { - \OC_DB::createDbFromStructure($this->dbDefinitionFile); - } - mysql_close($connection); - } - - private function createDatabase($connection) { - $name = $this->dbname; - $user = $this->dbuser; - //we cant use OC_BD functions here because we need to connect as the administrative user. - $query = "CREATE DATABASE IF NOT EXISTS `$name`"; - $result = mysql_query($query, $connection); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(mysql_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN); - } - $query="GRANT ALL PRIVILEGES ON `$name` . * TO '$user'"; - - //this query will fail if there aren't the right permissions, ignore the error - mysql_query($query, $connection); - } - - private function createDBUser($connection) { - $name = $this->dbuser; - $password = $this->dbpassword; - // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one, - // the anonymous user would take precedence when there is one. - $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; - $result = mysql_query($query, $connection); - if (!$result) { - throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'localhost' exists already.", array($name)), - $this->trans->t("Drop this user from MySQL", array($name))); - } - $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; - $result = mysql_query($query, $connection); - if (!$result) { - throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'%%' already exists", array($name)), - $this->trans->t("Drop this user from MySQL.")); - } - } -} diff --git a/lib/setup/oci.php b/lib/setup/oci.php deleted file mode 100644 index 326d7a00531..00000000000 --- a/lib/setup/oci.php +++ /dev/null @@ -1,210 +0,0 @@ -dbtablespace = $config['dbtablespace']; - } else { - $this->dbtablespace = 'USERS'; - } - \OC_Config::setValue('dbtablespace', $this->dbtablespace); - } - - public function setupDatabase($username) { - $e_host = addslashes($this->dbhost); - $e_dbname = addslashes($this->dbname); - //check if the database user has admin right - if ($e_host == '') { - $easy_connect_string = $e_dbname; // use dbname as easy connect name - } else { - $easy_connect_string = '//'.$e_host.'/'.$e_dbname; - } - \OC_Log::write('setup oracle', 'connect string: ' . $easy_connect_string, \OC_Log::DEBUG); - $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string); - if(!$connection) { - $e = oci_error(); - if (is_array ($e) && isset ($e['message'])) { - throw new \DatabaseSetupException($this->trans->t('Oracle connection could not be established'), - $e['message'].' Check environment: ORACLE_HOME='.getenv('ORACLE_HOME') - .' ORACLE_SID='.getenv('ORACLE_SID') - .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH') - .' NLS_LANG='.getenv('NLS_LANG') - .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable'); - } - throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), - 'Check environment: ORACLE_HOME='.getenv('ORACLE_HOME') - .' ORACLE_SID='.getenv('ORACLE_SID') - .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH') - .' NLS_LANG='.getenv('NLS_LANG') - .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable'); - } - //check for roles creation rights in oracle - - $query='SELECT count(*) FROM user_role_privs, role_sys_privs' - ." WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'"; - $stmt = oci_parse($connection, $query); - if (!$stmt) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_last_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - $result = oci_execute($stmt); - if($result) { - $row = oci_fetch_row($stmt); - } - if($result and $row[0] > 0) { - //use the admin login data for the new database user - - //add prefix to the oracle user name to prevent collisions - $this->dbuser='oc_'.$username; - //create a new password so we don't need to store the admin config in the config file - $this->dbpassword=\OC_Util::generateRandomBytes(30); - - //oracle passwords are treated as identifiers: - // must start with aphanumeric char - // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length. - $this->dbpassword=substr($this->dbpassword, 0, 30); - - $this->createDBUser($connection); - - \OC_Config::setValue('dbuser', $this->dbusername); - \OC_Config::setValue('dbname', $this->dbusername); - \OC_Config::setValue('dbpassword', $this->dbpassword); - - //create the database not neccessary, oracle implies user = schema - //$this->createDatabase($this->dbname, $this->dbusername, $connection); - } else { - - \OC_Config::setValue('dbuser', $this->dbuser); - \OC_Config::setValue('dbname', $this->dbname); - \OC_Config::setValue('dbpassword', $this->dbpassword); - - //create the database not neccessary, oracle implies user = schema - //$this->createDatabase($this->dbname, $this->dbuser, $connection); - } - - //FIXME check tablespace exists: select * from user_tablespaces - - // the connection to dbname=oracle is not needed anymore - oci_close($connection); - - // connect to the oracle database (schema=$this->dbuser) an check if the schema needs to be filled - $this->dbuser = \OC_Config::getValue('dbuser'); - //$this->dbname = \OC_Config::getValue('dbname'); - $this->dbpassword = \OC_Config::getValue('dbpassword'); - - $e_host = addslashes($this->dbhost); - $e_dbname = addslashes($this->dbname); - - if ($e_host == '') { - $easy_connect_string = $e_dbname; // use dbname as easy connect name - } else { - $easy_connect_string = '//'.$e_host.'/'.$e_dbname; - } - $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string); - if(!$connection) { - throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), - $this->trans->t('You need to enter either an existing account or the administrator.')); - } - $query = "SELECT count(*) FROM user_tables WHERE table_name = :un"; - $stmt = oci_parse($connection, $query); - $un = $this->dbtableprefix.'users'; - oci_bind_by_name($stmt, ':un', $un); - if (!$stmt) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - $result = oci_execute($stmt); - - if($result) { - $row = oci_fetch_row($stmt); - } - if(!$result or $row[0]==0) { - \OC_DB::createDbFromStructure($this->dbDefinitionFile); - } - } - - /** - * - * @param String $name - * @param String $password - * @param resource $connection - */ - private function createDBUser($connection) { - $name = $this->dbuser; - $password = $this->password; - $query = "SELECT * FROM all_users WHERE USERNAME = :un"; - $stmt = oci_parse($connection, $query); - if (!$stmt) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - oci_bind_by_name($stmt, ':un', $name); - $result = oci_execute($stmt); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - - if(! oci_fetch_row($stmt)) { - //user does not exists let's create it :) - //password must start with alphabetic character in oracle - $query = 'CREATE USER '.$name.' IDENTIFIED BY "'.$password.'" DEFAULT TABLESPACE '.$this->dbtablespace; - $stmt = oci_parse($connection, $query); - if (!$stmt) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - //oci_bind_by_name($stmt, ':un', $name); - $result = oci_execute($stmt); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s', - array($query, $name, $password)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - } else { // change password of the existing role - $query = "ALTER USER :un IDENTIFIED BY :pw"; - $stmt = oci_parse($connection, $query); - if (!$stmt) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - oci_bind_by_name($stmt, ':un', $name); - oci_bind_by_name($stmt, ':pw', $password); - $result = oci_execute($stmt); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - } - // grant necessary roles - $query = 'GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER, UNLIMITED TABLESPACE TO '.$name; - $stmt = oci_parse($connection, $query); - if (!$stmt) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - $result = oci_execute($stmt); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s', - array($query, $name, $password)) . '
'; - \OC_Log::write('setup.oci', $entry, \OC_Log::WARN); - } - } -} diff --git a/lib/setup/postgresql.php b/lib/setup/postgresql.php deleted file mode 100644 index 89d328ada19..00000000000 --- a/lib/setup/postgresql.php +++ /dev/null @@ -1,140 +0,0 @@ -dbhost); - $e_user = addslashes($this->dbuser); - $e_password = addslashes($this->dbpassword); - - //check if the database user has admin rights - $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'"; - $connection = @pg_connect($connection_string); - if(!$connection) { - // Try if we can connect to the DB with the specified name - $e_dbname = addslashes($this->dbname); - $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'"; - $connection = @pg_connect($connection_string); - - if(!$connection) - throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), - $this->trans->t('You need to enter either an existing account or the administrator.')); - } - $e_user = pg_escape_string($this->dbuser); - //check for roles creation rights in postgresql - $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'"; - $result = pg_query($connection, $query); - if($result and pg_num_rows($result) > 0) { - //use the admin login data for the new database user - - //add prefix to the postgresql user name to prevent collisions - $this->dbuser='oc_'.$username; - //create a new password so we don't need to store the admin config in the config file - $this->dbpassword=\OC_Util::generateRandomBytes(30); - - $this->createDBUser($connection); - - \OC_Config::setValue('dbuser', $this->dbuser); - \OC_Config::setValue('dbpassword', $this->dbpassword); - - //create the database - $this->createDatabase($connection); - } - else { - \OC_Config::setValue('dbuser', $this->dbuser); - \OC_Config::setValue('dbpassword', $this->dbpassword); - - //create the database - $this->createDatabase($connection); - } - - // the connection to dbname=postgres is not needed anymore - pg_close($connection); - - // connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled - $this->dbuser = \OC_Config::getValue('dbuser'); - $this->dbpassword = \OC_Config::getValue('dbpassword'); - - $e_host = addslashes($this->dbhost); - $e_dbname = addslashes($this->dbname); - $e_user = addslashes($this->dbuser); - $e_password = addslashes($this->dbpassword); - - $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'"; - $connection = @pg_connect($connection_string); - if(!$connection) { - throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), - $this->trans->t('You need to enter either an existing account or the administrator.')); - } - $query = "select count(*) FROM pg_class WHERE relname='".$this->tableprefix."users' limit 1"; - $result = pg_query($connection, $query); - if($result) { - $row = pg_fetch_row($result); - } - if(!$result or $row[0]==0) { - \OC_DB::createDbFromStructure($this->dbDefinitionFile); - } - } - - private function createDatabase($connection) { - //we cant use OC_BD functions here because we need to connect as the administrative user. - $e_name = pg_escape_string($this->dbname); - $e_user = pg_escape_string($this->dbuser); - $query = "select datname from pg_database where datname = '$e_name'"; - $result = pg_query($connection, $query); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); - } - if(! pg_fetch_row($result)) { - //The database does not exists... let's create it - $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\""; - $result = pg_query($connection, $query); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); - } - else { - $query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC"; - pg_query($connection, $query); - } - } - } - - private function createDBUser($connection) { - $e_name = pg_escape_string($this->dbuser); - $e_password = pg_escape_string($this->dbpassword); - $query = "select * from pg_roles where rolname='$e_name';"; - $result = pg_query($connection, $query); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); - } - - if(! pg_fetch_row($result)) { - //user does not exists let's create it :) - $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';"; - $result = pg_query($connection, $query); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); - } - } - else { // change password of the existing role - $query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';"; - $result = pg_query($connection, $query); - if(!$result) { - $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '
'; - $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; - \OC_Log::write('setup.pg', $entry, \OC_Log::WARN); - } - } - } -} diff --git a/lib/setup/sqlite.php b/lib/setup/sqlite.php deleted file mode 100644 index fd4df792d62..00000000000 --- a/lib/setup/sqlite.php +++ /dev/null @@ -1,26 +0,0 @@ -dbDefinitionFile); - } -} diff --git a/lib/subadmin.php b/lib/subadmin.php deleted file mode 100644 index 8cda7240ac9..00000000000 --- a/lib/subadmin.php +++ /dev/null @@ -1,189 +0,0 @@ -. - * - */ -OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_SubAdmin', 'post_deleteUser'); -OC_Hook::connect('OC_User', 'post_deleteGroup', 'OC_SubAdmin', 'post_deleteGroup'); -/** - * This class provides all methods needed for managing groups. - * - * Hooks provided: - * post_createSubAdmin($gid) - * post_deleteSubAdmin($gid) - */ -class OC_SubAdmin{ - - /** - * @brief add a SubAdmin - * @param $uid uid of the SubAdmin - * @param $gid gid of the group - * @return boolean - */ - public static function createSubAdmin($uid, $gid) { - $stmt = OC_DB::prepare('INSERT INTO `*PREFIX*group_admin` (`gid`,`uid`) VALUES(?,?)'); - $result = $stmt->execute(array($gid, $uid)); - OC_Hook::emit( "OC_SubAdmin", "post_createSubAdmin", array( "gid" => $gid )); - return true; - } - - /** - * @brief delete a SubAdmin - * @param $uid uid of the SubAdmin - * @param $gid gid of the group - * @return boolean - */ - public static function deleteSubAdmin($uid, $gid) { - $stmt = OC_DB::prepare('DELETE FROM `*PREFIX*group_admin` WHERE `gid` = ? AND `uid` = ?'); - $result = $stmt->execute(array($gid, $uid)); - OC_Hook::emit( "OC_SubAdmin", "post_deleteSubAdmin", array( "gid" => $gid )); - return true; - } - - /** - * @brief get groups of a SubAdmin - * @param $uid uid of the SubAdmin - * @return array - */ - public static function getSubAdminsGroups($uid) { - $stmt = OC_DB::prepare('SELECT `gid` FROM `*PREFIX*group_admin` WHERE `uid` = ?'); - $result = $stmt->execute(array($uid)); - $gids = array(); - while($row = $result->fetchRow()) { - $gids[] = $row['gid']; - } - return $gids; - } - - /** - * @brief get SubAdmins of a group - * @param $gid gid of the group - * @return array - */ - public static function getGroupsSubAdmins($gid) { - $stmt = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*group_admin` WHERE `gid` = ?'); - $result = $stmt->execute(array($gid)); - $uids = array(); - while($row = $result->fetchRow()) { - $uids[] = $row['uid']; - } - return $uids; - } - - /** - * @brief get all SubAdmins - * @return array - */ - public static function getAllSubAdmins() { - $stmt = OC_DB::prepare('SELECT * FROM `*PREFIX*group_admin`'); - $result = $stmt->execute(); - $subadmins = array(); - while($row = $result->fetchRow()) { - $subadmins[] = $row; - } - return $subadmins; - } - - /** - * @brief checks if a user is a SubAdmin of a group - * @param $uid uid of the subadmin - * @param $gid gid of the group - * @return bool - */ - public static function isSubAdminofGroup($uid, $gid) { - $stmt = OC_DB::prepare('SELECT COUNT(*) AS `count` FROM `*PREFIX*group_admin` WHERE `uid` = ? AND `gid` = ?'); - $result = $stmt->execute(array($uid, $gid)); - $result = $result->fetchRow(); - if($result['count'] >= 1) { - return true; - } - return false; - } - - /** - * @brief checks if a user is a SubAdmin - * @param $uid uid of the subadmin - * @return bool - */ - public static function isSubAdmin($uid) { - // Check if the user is already an admin - if(OC_Group::inGroup($uid, 'admin' )) { - return true; - } - - $stmt = OC_DB::prepare('SELECT COUNT(*) AS `count` FROM `*PREFIX*group_admin` WHERE `uid` = ?'); - $result = $stmt->execute(array($uid)); - $result = $result->fetchRow(); - if($result['count'] > 0) { - return true; - } - return false; - } - - /** - * @brief checks if a user is a accessible by a subadmin - * @param $subadmin uid of the subadmin - * @param $user uid of the user - * @return bool - */ - public static function isUserAccessible($subadmin, $user) { - if(!self::isSubAdmin($subadmin)) { - return false; - } - if(OC_User::isAdminUser($user)) { - return false; - } - $accessiblegroups = self::getSubAdminsGroups($subadmin); - foreach($accessiblegroups as $accessiblegroup) { - if(OC_Group::inGroup($user, $accessiblegroup)) { - return true; - } - } - return false; - } - - /* - * @brief alias for self::isSubAdminofGroup() - */ - public static function isGroupAccessible($subadmin, $group) { - return self::isSubAdminofGroup($subadmin, $group); - } - - /** - * @brief delete all SubAdmins by uid - * @param $parameters - * @return boolean - */ - public static function post_deleteUser($parameters) { - $stmt = OC_DB::prepare('DELETE FROM `*PREFIX*group_admin` WHERE `uid` = ?'); - $result = $stmt->execute(array($parameters['uid'])); - return true; - } - - /** - * @brief delete all SubAdmins by gid - * @param $parameters - * @return boolean - */ - public static function post_deleteGroup($parameters) { - $stmt = OC_DB::prepare('DELETE FROM `*PREFIX*group_admin` WHERE `gid` = ?'); - $result = $stmt->execute(array($parameters['gid'])); - return true; - } -} diff --git a/lib/template.php b/lib/template.php deleted file mode 100644 index 9b2c1211e61..00000000000 --- a/lib/template.php +++ /dev/null @@ -1,311 +0,0 @@ -. - * - */ - -require_once __DIR__.'/template/functions.php'; - -/** - * This class provides the templates for ownCloud. - */ -class OC_Template extends \OC\Template\Base { - private $renderas; // Create a full page? - private $path; // The path to the template - private $headers=array(); //custom headers - - /** - * @brief Constructor - * @param string $app app providing the template - * @param string $name of the template file (without suffix) - * @param string $renderas = ""; produce a full page - * @return OC_Template object - * - * This function creates an OC_Template object. - * - * If $renderas is set, OC_Template will try to produce a full page in the - * according layout. For now, renderas can be set to "guest", "user" or - * "admin". - */ - public function __construct( $app, $name, $renderas = "" ) { - // Read the selected theme from the config file - $theme = OC_Util::getTheme(); - - // Read the detected formfactor and use the right file name. - $fext = self::getFormFactorExtension(); - - $requesttoken = OC::$session ? OC_Util::callRegister() : ''; - - $parts = explode('/', $app); // fix translation when app is something like core/lostpassword - $l10n = OC_L10N::get($parts[0]); - $themeDefaults = new OC_Defaults(); - - list($path, $template) = $this->findTemplate($theme, $app, $name, $fext); - - // Set the private data - $this->renderas = $renderas; - $this->path = $path; - - parent::__construct($template, $requesttoken, $l10n, $themeDefaults); - - // Some headers to enhance security - header('X-XSS-Protection: 1; mode=block'); // Enforce browser based XSS filters - header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE - - // iFrame Restriction Policy - $xFramePolicy = OC_Config::getValue('xframe_restriction', true); - if($xFramePolicy) { - header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains - } - - // Content Security Policy - // If you change the standard policy, please also change it in config.sample.php - $policy = OC_Config::getValue('custom_csp_policy', - 'default-src \'self\'; ' - .'script-src \'self\' \'unsafe-eval\'; ' - .'style-src \'self\' \'unsafe-inline\'; ' - .'frame-src *; ' - .'img-src *; ' - .'font-src \'self\' data:; ' - .'media-src *'); - header('Content-Security-Policy:'.$policy); // Standard - - } - - /** - * autodetect the formfactor of the used device - * default -> the normal desktop browser interface - * mobile -> interface for smartphones - * tablet -> interface for tablets - * standalone -> the default interface but without header, footer and - * sidebar, just the application. Useful to use just a specific - * app on the desktop in a standalone window. - */ - public static function detectFormfactor() { - // please add more useragent strings for other devices - if(isset($_SERVER['HTTP_USER_AGENT'])) { - if(stripos($_SERVER['HTTP_USER_AGENT'], 'ipad')>0) { - $mode='tablet'; - }elseif(stripos($_SERVER['HTTP_USER_AGENT'], 'iphone')>0) { - $mode='mobile'; - }elseif((stripos($_SERVER['HTTP_USER_AGENT'], 'N9')>0) - and (stripos($_SERVER['HTTP_USER_AGENT'], 'nokia')>0)) { - $mode='mobile'; - }else{ - $mode='default'; - } - }else{ - $mode='default'; - } - return($mode); - } - - /** - * @brief Returns the formfactor extension for current formfactor - */ - static public function getFormFactorExtension() - { - if (!\OC::$session) { - return ''; - } - // if the formfactor is not yet autodetected do the - // autodetection now. For possible formfactors check the - // detectFormfactor documentation - if (!\OC::$session->exists('formfactor')) { - \OC::$session->set('formfactor', self::detectFormfactor()); - } - // allow manual override via GET parameter - if(isset($_GET['formfactor'])) { - \OC::$session->set('formfactor', $_GET['formfactor']); - } - $formfactor = \OC::$session->get('formfactor'); - if($formfactor==='default') { - $fext=''; - }elseif($formfactor==='mobile') { - $fext='.mobile'; - }elseif($formfactor==='tablet') { - $fext='.tablet'; - }elseif($formfactor==='standalone') { - $fext='.standalone'; - }else{ - $fext=''; - } - return $fext; - } - - /** - * @brief find the template with the given name - * @param string $name of the template file (without suffix) - * - * Will select the template file for the selected theme and formfactor. - * Checking all the possible locations. - */ - protected function findTemplate($theme, $app, $name, $fext) { - // Check if it is a app template or not. - if( $app !== '' ) { - $dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app)); - } else { - $dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT); - } - $locator = new \OC\Template\TemplateFileLocator( $fext, $dirs ); - $template = $locator->find($name); - $path = $locator->getPath(); - return array($path, $template); - } - - /** - * @brief Add a custom element to the header - * @param string $tag tag name of the element - * @param array $attributes array of attributes for the element - * @param string $text the text content for the element - */ - public function addHeader( $tag, $attributes, $text='') { - $this->headers[]=array('tag'=>$tag,'attributes'=>$attributes, 'text'=>$text); - } - - /** - * @brief Process the template - * @return bool - * - * This function process the template. If $this->renderas is set, it - * will produce a full page. - */ - public function fetchPage() { - $data = parent::fetchPage(); - - if( $this->renderas ) { - $page = new OC_TemplateLayout($this->renderas); - - // Add custom headers - $page->assign('headers', $this->headers, false); - foreach(OC_Util::$headers as $header) { - $page->append('headers', $header); - } - - $page->assign( "content", $data, false ); - return $page->fetchPage(); - } - else{ - return $data; - } - } - - /** - * @brief Include template - * @return string returns content of included template - * - * Includes another template. use inc('template'); ?> to - * do this. - */ - public function inc( $file, $additionalparams = null ) { - return $this->load($this->path.$file.'.php', $additionalparams); - } - - /** - * @brief Shortcut to print a simple page for users - * @param string $application The application we render the template for - * @param string $name Name of the template - * @param array $parameters Parameters for the template - * @return bool - */ - public static function printUserPage( $application, $name, $parameters = array() ) { - $content = new OC_Template( $application, $name, "user" ); - foreach( $parameters as $key => $value ) { - $content->assign( $key, $value ); - } - print $content->printPage(); - } - - /** - * @brief Shortcut to print a simple page for admins - * @param string $application The application we render the template for - * @param string $name Name of the template - * @param array $parameters Parameters for the template - * @return bool - */ - public static function printAdminPage( $application, $name, $parameters = array() ) { - $content = new OC_Template( $application, $name, "admin" ); - foreach( $parameters as $key => $value ) { - $content->assign( $key, $value ); - } - return $content->printPage(); - } - - /** - * @brief Shortcut to print a simple page for guests - * @param string $application The application we render the template for - * @param string $name Name of the template - * @param string $parameters Parameters for the template - * @return bool - */ - public static function printGuestPage( $application, $name, $parameters = array() ) { - $content = new OC_Template( $application, $name, "guest" ); - foreach( $parameters as $key => $value ) { - $content->assign( $key, $value ); - } - return $content->printPage(); - } - - /** - * @brief Print a fatal error page and terminates the script - * @param string $error_msg The error message to show - * @param string $hint An optional hint message - * Warning: All data passed to $hint needs to get sanitized using OC_Util::sanitizeHTML - */ - public static function printErrorPage( $error_msg, $hint = '' ) { - $content = new OC_Template( '', 'error', 'error' ); - $errors = array(array('error' => $error_msg, 'hint' => $hint)); - $content->assign( 'errors', $errors ); - $content->printPage(); - die(); - } - - /** - * print error page using Exception details - * @param Exception $exception - */ - - public static function printExceptionErrorPage(Exception $exception) { - $error_msg = $exception->getMessage(); - if ($exception->getCode()) { - $error_msg = '['.$exception->getCode().'] '.$error_msg; - } - if (defined('DEBUG') and DEBUG) { - $hint = $exception->getTraceAsString(); - if (!empty($hint)) { - $hint = '
'.$hint.'
'; - } - $l = OC_L10N::get('lib'); - while (method_exists($exception, 'previous') && $exception = $exception->previous()) { - $error_msg .= '
'.$l->t('Caused by:').' '; - if ($exception->getCode()) { - $error_msg .= '['.$exception->getCode().'] '; - } - $error_msg .= $exception->getMessage(); - }; - } else { - $hint = ''; - if ($exception instanceof \OC\HintException) { - $hint = $exception->getHint(); - } - } - self::printErrorPage($error_msg, $hint); - } -} diff --git a/lib/template/base.php b/lib/template/base.php deleted file mode 100644 index 88941bc7132..00000000000 --- a/lib/template/base.php +++ /dev/null @@ -1,134 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Template; - -class Base { - private $template; // The template - private $vars; // Vars - private $l10n; // The l10n-Object - private $theme; // theme defaults - - public function __construct( $template, $requesttoken, $l10n, $theme ) { - $this->vars = array(); - $this->vars['requesttoken'] = $requesttoken; - $this->l10n = $l10n; - $this->template = $template; - $this->theme = $theme; - } - - protected function getAppTemplateDirs($theme, $app, $serverroot, $app_dir) { - // Check if the app is in the app folder or in the root - if( file_exists($app_dir.'/templates/' )) { - return array( - $serverroot.'/themes/'.$theme.'/apps/'.$app.'/templates/', - $app_dir.'/templates/', - ); - } - return array( - $serverroot.'/themes/'.$theme.'/'.$app.'/templates/', - $serverroot.'/'.$app.'/templates/', - ); - } - - protected function getCoreTemplateDirs($theme, $serverroot) { - return array( - $serverroot.'/themes/'.$theme.'/core/templates/', - $serverroot.'/core/templates/', - ); - } - - /** - * @brief Assign variables - * @param string $key key - * @param string $value value - * @return bool - * - * This function assigns a variable. It can be accessed via $_[$key] in - * the template. - * - * If the key existed before, it will be overwritten - */ - public function assign( $key, $value) { - $this->vars[$key] = $value; - return true; - } - - /** - * @brief Appends a variable - * @param string $key key - * @param string $value value - * @return bool - * - * This function assigns a variable in an array context. If the key already - * exists, the value will be appended. It can be accessed via - * $_[$key][$position] in the template. - */ - public function append( $key, $value ) { - if( array_key_exists( $key, $this->vars )) { - $this->vars[$key][] = $value; - } - else{ - $this->vars[$key] = array( $value ); - } - } - - /** - * @brief Prints the proceeded template - * @return bool - * - * This function proceeds the template and prints its output. - */ - public function printPage() { - $data = $this->fetchPage(); - if( $data === false ) { - return false; - } - else{ - print $data; - return true; - } - } - - /** - * @brief Process the template - * @return bool - * - * This function processes the template. - */ - public function fetchPage() { - return $this->load($this->template); - } - - /** - * @brief doing the actual work - * @return string content - * - * Includes the template file, fetches its output - */ - protected function load( $file, $additionalparams = null ) { - // Register the variables - $_ = $this->vars; - $l = $this->l10n; - $theme = $this->theme; - - if( !is_null($additionalparams)) { - $_ = array_merge( $additionalparams, $this->vars ); - } - - // Include - ob_start(); - include $file; - $data = ob_get_contents(); - @ob_end_clean(); - - // Return data - return $data; - } - -} diff --git a/lib/template/cssresourcelocator.php b/lib/template/cssresourcelocator.php deleted file mode 100644 index 8e7831ca549..00000000000 --- a/lib/template/cssresourcelocator.php +++ /dev/null @@ -1,43 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Template; - -class CSSResourceLocator extends ResourceLocator { - public function doFind( $style ) { - if (strpos($style, '3rdparty') === 0 - && $this->appendIfExist($this->thirdpartyroot, $style.'.css') - || $this->appendIfExist($this->serverroot, $style.$this->form_factor.'.css') - || $this->appendIfExist($this->serverroot, $style.'.css') - || $this->appendIfExist($this->serverroot, 'core/'.$style.$this->form_factor.'.css') - || $this->appendIfExist($this->serverroot, 'core/'.$style.'.css') - ) { - return; - } - $app = substr($style, 0, strpos($style, '/')); - $style = substr($style, strpos($style, '/')+1); - $app_path = \OC_App::getAppPath($app); - $app_url = $this->webroot . '/index.php/apps/' . $app; - if ($this->appendIfExist($app_path, $style.$this->form_factor.'.css', $app_url) - || $this->appendIfExist($app_path, $style.'.css', $app_url) - ) { - return; - } - throw new \Exception('css file not found: style:'.$style); - } - - public function doFindTheme( $style ) { - $theme_dir = 'themes/'.$this->theme.'/'; - $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.$this->form_factor.'.css') - || $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.'.css') - || $this->appendIfExist($this->serverroot, $theme_dir.$style.$this->form_factor.'.css') - || $this->appendIfExist($this->serverroot, $theme_dir.$style.'.css') - || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.$this->form_factor.'.css') - || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.'.css'); - } -} diff --git a/lib/template/functions.php b/lib/template/functions.php deleted file mode 100644 index 501f8081bff..00000000000 --- a/lib/template/functions.php +++ /dev/null @@ -1,134 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * Prints an XSS escaped string - * @param string $string the string which will be escaped and printed - */ -function p($string) { - print(OC_Util::sanitizeHTML($string)); -} - -/** - * Prints an unescaped string - * @param string $string the string which will be printed as it is - */ -function print_unescaped($string) { - print($string); -} - -/** - * @brief make OC_Helper::linkTo available as a simple function - * @param string $app app - * @param string $file file - * @param array $args array with param=>value, will be appended to the returned url - * @return string link to the file - * - * For further information have a look at OC_Helper::linkTo - */ -function link_to( $app, $file, $args = array() ) { - return OC_Helper::linkTo( $app, $file, $args ); -} - -/** - * @brief make OC_Helper::imagePath available as a simple function - * @param string $app app - * @param string $image image - * @return string link to the image - * - * For further information have a look at OC_Helper::imagePath - */ -function image_path( $app, $image ) { - return OC_Helper::imagePath( $app, $image ); -} - -/** - * @brief make OC_Helper::mimetypeIcon available as a simple function - * @param string $mimetype mimetype - * @return string link to the image - * - * For further information have a look at OC_Helper::mimetypeIcon - */ -function mimetype_icon( $mimetype ) { - return OC_Helper::mimetypeIcon( $mimetype ); -} - -/** - * @brief make preview_icon available as a simple function - * Returns the path to the preview of the image. - * @param $path path of file - * @returns link to the preview - * - * For further information have a look at OC_Helper::previewIcon - */ -function preview_icon( $path ) { - return OC_Helper::previewIcon( $path ); -} - -function publicPreview_icon ( $path, $token ) { - return OC_Helper::publicPreviewIcon( $path, $token ); -} - -/** - * @brief make OC_Helper::humanFileSize available as a simple function - * @param int $bytes size in bytes - * @return string size as string - * - * For further information have a look at OC_Helper::humanFileSize - */ -function human_file_size( $bytes ) { - return OC_Helper::humanFileSize( $bytes ); -} - -function relative_modified_date($timestamp) { - $l=OC_L10N::get('lib'); - $timediff = time() - $timestamp; - $diffminutes = round($timediff/60); - $diffhours = round($diffminutes/60); - $diffdays = round($diffhours/24); - $diffmonths = round($diffdays/31); - - if($timediff < 60) { return $l->t('seconds ago'); } - else if($timediff < 3600) { return $l->n('%n minute ago', '%n minutes ago', $diffminutes); } - else if($timediff < 86400) { return $l->n('%n hour ago', '%n hours ago', $diffhours); } - else if((date('G')-$diffhours) > 0) { return $l->t('today'); } - else if((date('G')-$diffhours) > -24) { return $l->t('yesterday'); } - else if($timediff < 2678400) { return $l->n('%n day go', '%n days ago', $diffdays); } - else if($timediff < 5184000) { return $l->t('last month'); } - else if((date('n')-$diffmonths) > 0) { return $l->n('%n month ago', '%n months ago', $diffmonths); } - else if($timediff < 63113852) { return $l->t('last year'); } - else { return $l->t('years ago'); } -} - -function html_select_options($options, $selected, $params=array()) { - if (!is_array($selected)) { - $selected=array($selected); - } - if (isset($params['combine']) && $params['combine']) { - $options = array_combine($options, $options); - } - $value_name = $label_name = false; - if (isset($params['value'])) { - $value_name = $params['value']; - } - if (isset($params['label'])) { - $label_name = $params['label']; - } - $html = ''; - foreach($options as $value => $label) { - if ($value_name && is_array($label)) { - $value = $label[$value_name]; - } - if ($label_name && is_array($label)) { - $label = $label[$label_name]; - } - $select = in_array($value, $selected) ? ' selected="selected"' : ''; - $html .= ''."\n"; - } - return $html; -} diff --git a/lib/template/jsresourcelocator.php b/lib/template/jsresourcelocator.php deleted file mode 100644 index f8fe3817ce6..00000000000 --- a/lib/template/jsresourcelocator.php +++ /dev/null @@ -1,43 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Template; - -class JSResourceLocator extends ResourceLocator { - public function doFind( $script ) { - $theme_dir = 'themes/'.$this->theme.'/'; - if (strpos($script, '3rdparty') === 0 - && $this->appendIfExist($this->thirdpartyroot, $script.'.js') - || $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.$this->form_factor.'.js') - || $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js') - || $this->appendIfExist($this->serverroot, $theme_dir.$script.$this->form_factor.'.js') - || $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js') - || $this->appendIfExist($this->serverroot, $script.$this->form_factor.'.js') - || $this->appendIfExist($this->serverroot, $script.'.js') - || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.$this->form_factor.'.js') - || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js') - || $this->appendIfExist($this->serverroot, 'core/'.$script.$this->form_factor.'.js') - || $this->appendIfExist($this->serverroot, 'core/'.$script.'.js') - ) { - return; - } - $app = substr($script, 0, strpos($script, '/')); - $script = substr($script, strpos($script, '/')+1); - $app_path = \OC_App::getAppPath($app); - $app_url = \OC_App::getAppWebPath($app); - if ($this->appendIfExist($app_path, $script.$this->form_factor.'.js', $app_url) - || $this->appendIfExist($app_path, $script.'.js', $app_url) - ) { - return; - } - throw new \Exception('js file not found: script:'.$script); - } - - public function doFindTheme( $script ) { - } -} diff --git a/lib/template/resourcelocator.php b/lib/template/resourcelocator.php deleted file mode 100644 index 9f83673664d..00000000000 --- a/lib/template/resourcelocator.php +++ /dev/null @@ -1,70 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Template; - -abstract class ResourceLocator { - protected $theme; - protected $form_factor; - - protected $mapping; - protected $serverroot; - protected $thirdpartyroot; - protected $webroot; - - protected $resources = array(); - - public function __construct( $theme, $form_factor, $core_map, $party_map ) { - $this->theme = $theme; - $this->form_factor = $form_factor; - $this->mapping = $core_map + $party_map; - $this->serverroot = key($core_map); - $this->thirdpartyroot = key($party_map); - $this->webroot = $this->mapping[$this->serverroot]; - } - - abstract public function doFind( $resource ); - abstract public function doFindTheme( $resource ); - - public function find( $resources ) { - try { - foreach($resources as $resource) { - $this->doFind($resource); - } - if (!empty($this->theme)) { - foreach($resources as $resource) { - $this->doFindTheme($resource); - } - } - } catch (\Exception $e) { - throw new \Exception($e->getMessage().' formfactor:'.$this->form_factor - .' serverroot:'.$this->serverroot); - } - } - - /* - * @brief append the $file resource if exist at $root - * @param $root path to check - * @param $file the filename - * @param $web base for path, default map $root to $webroot - */ - protected function appendIfExist($root, $file, $webroot = null) { - if (is_file($root.'/'.$file)) { - if (!$webroot) { - $webroot = $this->mapping[$root]; - } - $this->resources[] = array($root, $webroot, $file); - return true; - } - return false; - } - - public function getResources() { - return $this->resources; - } -} diff --git a/lib/template/templatefilelocator.php b/lib/template/templatefilelocator.php deleted file mode 100644 index d5a484b1a14..00000000000 --- a/lib/template/templatefilelocator.php +++ /dev/null @@ -1,44 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Template; - -class TemplateFileLocator { - protected $form_factor; - protected $dirs; - private $path; - - public function __construct( $form_factor, $dirs ) { - $this->form_factor = $form_factor; - $this->dirs = $dirs; - } - - public function find( $template ) { - if ($template === '') { - throw new \InvalidArgumentException('Empty template name'); - } - - foreach($this->dirs as $dir) { - $file = $dir.$template.$this->form_factor.'.php'; - if (is_file($file)) { - $this->path = $dir; - return $file; - } - $file = $dir.$template.'.php'; - if (is_file($file)) { - $this->path = $dir; - return $file; - } - } - throw new \Exception('template file not found: template:'.$template.' formfactor:'.$this->form_factor); - } - - public function getPath() { - return $this->path; - } -} diff --git a/lib/templatelayout.php b/lib/templatelayout.php deleted file mode 100644 index 625f3424a04..00000000000 --- a/lib/templatelayout.php +++ /dev/null @@ -1,114 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_TemplateLayout extends OC_Template { - public function __construct( $renderas ) { - // Decide which page we show - - if( $renderas == 'user' ) { - parent::__construct( 'core', 'layout.user' ); - if(in_array(OC_APP::getCurrentApp(), array('settings','admin', 'help'))!==false) { - $this->assign('bodyid', 'body-settings'); - }else{ - $this->assign('bodyid', 'body-user'); - } - - // Update notification - if(OC_Config::getValue('updatechecker', true) === true) { - $data=OC_Updater::check(); - if(isset($data['version']) && $data['version'] != '' and $data['version'] !== Array() && OC_User::isAdminUser(OC_User::getUser())) { - $this->assign('updateAvailable', true); - $this->assign('updateVersion', $data['versionstring']); - $this->assign('updateLink', $data['web']); - } else { - $this->assign('updateAvailable', false); // No update available or not an admin user - } - } else { - $this->assign('updateAvailable', false); // Update check is disabled - } - - // Add navigation entry - $this->assign( 'application', '', false ); - $navigation = OC_App::getNavigation(); - $this->assign( 'navigation', $navigation); - $this->assign( 'settingsnavigation', OC_App::getSettingsNavigation()); - foreach($navigation as $entry) { - if ($entry['active']) { - $this->assign( 'application', $entry['name'] ); - break; - } - } - $user_displayname = OC_User::getDisplayName(); - $this->assign( 'user_displayname', $user_displayname ); - $this->assign( 'user_uid', OC_User::getUser() ); - $this->assign('enableAvatars', \OC_Config::getValue('enable_avatars', true)); - } else if ($renderas == 'guest' || $renderas == 'error') { - parent::__construct('core', 'layout.guest'); - } else { - parent::__construct('core', 'layout.base'); - } - $versionParameter = '?v=' . md5(implode(OC_Util::getVersion())); - // Add the js files - $jsfiles = self::findJavascriptFiles(OC_Util::$scripts); - $this->assign('jsfiles', array(), false); - if (OC_Config::getValue('installed', false) && $renderas!='error') { - $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config') . $versionParameter); - } - if (!empty(OC_Util::$coreScripts)) { - $this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false) . $versionParameter); - } - foreach($jsfiles as $info) { - $root = $info[0]; - $web = $info[1]; - $file = $info[2]; - $this->append( 'jsfiles', $web.'/'.$file . $versionParameter); - } - - // Add the css files - $cssfiles = self::findStylesheetFiles(OC_Util::$styles); - $this->assign('cssfiles', array()); - if (!empty(OC_Util::$coreStyles)) { - $this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false) . $versionParameter); - } - foreach($cssfiles as $info) { - $root = $info[0]; - $web = $info[1]; - $file = $info[2]; - - $this->append( 'cssfiles', $web.'/'.$file . $versionParameter); - } - } - - static public function findStylesheetFiles($styles) { - // Read the selected theme from the config file - $theme = OC_Util::getTheme(); - - // Read the detected formfactor and use the right file name. - $fext = self::getFormFactorExtension(); - - $locator = new \OC\Template\CSSResourceLocator( $theme, $fext, - array( OC::$SERVERROOT => OC::$WEBROOT ), - array( OC::$THIRDPARTYROOT => OC::$THIRDPARTYWEBROOT )); - $locator->find($styles); - return $locator->getResources(); - } - - static public function findJavascriptFiles($scripts) { - // Read the selected theme from the config file - $theme = OC_Util::getTheme(); - - // Read the detected formfactor and use the right file name. - $fext = self::getFormFactorExtension(); - - $locator = new \OC\Template\JSResourceLocator( $theme, $fext, - array( OC::$SERVERROOT => OC::$WEBROOT ), - array( OC::$THIRDPARTYROOT => OC::$THIRDPARTYWEBROOT )); - $locator->find($scripts); - return $locator->getResources(); - } -} diff --git a/lib/updater.php b/lib/updater.php deleted file mode 100644 index df7332a96a9..00000000000 --- a/lib/updater.php +++ /dev/null @@ -1,159 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC; -use OC\Hooks\BasicEmitter; - -/** - * Class that handles autoupdating of ownCloud - * - * Hooks provided in scope \OC\Updater - * - maintenanceStart() - * - maintenanceEnd() - * - dbUpgrade() - * - filecacheStart() - * - filecacheProgress(int $percentage) - * - filecacheDone() - * - failure(string $message) - */ -class Updater extends BasicEmitter { - - /** - * @var \OC\Log $log - */ - private $log; - - /** - * @param \OC\Log $log - */ - public function __construct($log = null) { - $this->log = $log; - } - - /** - * Check if a new version is available - * @param string $updateUrl the url to check, i.e. 'http://apps.owncloud.com/updater.php' - * @return array | bool - */ - public function check($updaterUrl) { - - // Look up the cache - it is invalidated all 30 minutes - if ((\OC_Appconfig::getValue('core', 'lastupdatedat') + 1800) > time()) { - return json_decode(\OC_Appconfig::getValue('core', 'lastupdateResult'), true); - } - - \OC_Appconfig::setValue('core', 'lastupdatedat', time()); - - if (\OC_Appconfig::getValue('core', 'installedat', '') == '') { - \OC_Appconfig::setValue('core', 'installedat', microtime(true)); - } - - $version = \OC_Util::getVersion(); - $version['installed'] = \OC_Appconfig::getValue('core', 'installedat'); - $version['updated'] = \OC_Appconfig::getValue('core', 'lastupdatedat'); - $version['updatechannel'] = 'stable'; - $version['edition'] = \OC_Util::getEditionString(); - $versionString = implode('x', $version); - - //fetch xml data from updater - $url = $updaterUrl . '?version=' . $versionString; - - // set a sensible timeout of 10 sec to stay responsive even if the update server is down. - $ctx = stream_context_create( - array( - 'http' => array( - 'timeout' => 10 - ) - ) - ); - $xml = @file_get_contents($url, 0, $ctx); - if ($xml == false) { - return array(); - } - $data = @simplexml_load_string($xml); - - $tmp = array(); - $tmp['version'] = $data->version; - $tmp['versionstring'] = $data->versionstring; - $tmp['url'] = $data->url; - $tmp['web'] = $data->web; - - // Cache the result - \OC_Appconfig::setValue('core', 'lastupdateResult', json_encode($data)); - - return $tmp; - } - - /** - * runs the update actions in maintenance mode, does not upgrade the source files - */ - public function upgrade() { - \OC_DB::enableCaching(false); - \OC_Config::setValue('maintenance', true); - $installedVersion = \OC_Config::getValue('version', '0.0.0'); - $currentVersion = implode('.', \OC_Util::getVersion()); - if ($this->log) { - $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core')); - } - $this->emit('\OC\Updater', 'maintenanceStart'); - try { - \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); - $this->emit('\OC\Updater', 'dbUpgrade'); - - // do a file cache upgrade for users with files - // this can take loooooooooooooooooooooooong - $this->upgradeFileCache(); - } catch (\Exception $exception) { - $this->emit('\OC\Updater', 'failure', array($exception->getMessage())); - } - \OC_Config::setValue('version', implode('.', \OC_Util::getVersion())); - \OC_App::checkAppsRequirements(); - // load all apps to also upgrade enabled apps - \OC_App::loadApps(); - \OC_Config::setValue('maintenance', false); - $this->emit('\OC\Updater', 'maintenanceEnd'); - } - - private function upgradeFileCache() { - try { - $query = \OC_DB::prepare(' - SELECT DISTINCT `user` - FROM `*PREFIX*fscache` - '); - $result = $query->execute(); - } catch (\Exception $e) { - return; - } - $users = $result->fetchAll(); - if (count($users) == 0) { - return; - } - $step = 100 / count($users); - $percentCompleted = 0; - $lastPercentCompletedOutput = 0; - $startInfoShown = false; - foreach ($users as $userRow) { - $user = $userRow['user']; - \OC\Files\Filesystem::initMountPoints($user); - \OC\Files\Cache\Upgrade::doSilentUpgrade($user); - if (!$startInfoShown) { - //We show it only now, because otherwise Info about upgraded apps - //will appear between this and progress info - $this->emit('\OC\Updater', 'filecacheStart'); - $startInfoShown = true; - } - $percentCompleted += $step; - $out = floor($percentCompleted); - if ($out != $lastPercentCompletedOutput) { - $this->emit('\OC\Updater', 'filecacheProgress', array($out)); - $lastPercentCompletedOutput = $out; - } - } - $this->emit('\OC\Updater', 'filecacheDone'); - } -} diff --git a/lib/user.php b/lib/user.php deleted file mode 100644 index 15e807088b4..00000000000 --- a/lib/user.php +++ /dev/null @@ -1,500 +0,0 @@ -. - * - */ - -/** - * This class provides wrapper methods for user management. Multiple backends are - * supported. User management operations are delegated to the configured backend for - * execution. - * - * Hooks provided: - * pre_createUser(&run, uid, password) - * post_createUser(uid, password) - * pre_deleteUser(&run, uid) - * post_deleteUser(uid) - * pre_setPassword(&run, uid, password, recoveryPassword) - * post_setPassword(uid, password, recoveryPassword) - * pre_login(&run, uid, password) - * post_login(uid) - * logout() - */ -class OC_User { - public static function getUserSession() { - return OC::$server->getUserSession(); - } - - /** - * @return \OC\User\Manager - */ - public static function getManager() { - return OC::$server->getUserManager(); - } - - private static $_backends = array(); - - private static $_usedBackends = array(); - - private static $_setupedBackends = array(); - - /** - * @brief registers backend - * @param string $backend name of the backend - * @deprecated Add classes by calling useBackend with a class instance instead - * @return bool - * - * Makes a list of backends that can be used by other modules - */ - public static function registerBackend($backend) { - self::$_backends[] = $backend; - return true; - } - - /** - * @brief gets available backends - * @deprecated - * @returns array of backends - * - * Returns the names of all backends. - */ - public static function getBackends() { - return self::$_backends; - } - - /** - * @brief gets used backends - * @deprecated - * @returns array of backends - * - * Returns the names of all used backends. - */ - public static function getUsedBackends() { - return array_keys(self::$_usedBackends); - } - - /** - * @brief Adds the backend to the list of used backends - * @param string | OC_User_Backend $backend default: database The backend to use for user management - * @return bool - * - * Set the User Authentication Module - */ - public static function useBackend($backend = 'database') { - if ($backend instanceof OC_User_Interface) { - self::$_usedBackends[get_class($backend)] = $backend; - self::getManager()->registerBackend($backend); - } else { - // You'll never know what happens - if (null === $backend OR !is_string($backend)) { - $backend = 'database'; - } - - // Load backend - switch ($backend) { - case 'database': - case 'mysql': - case 'sqlite': - OC_Log::write('core', 'Adding user backend ' . $backend . '.', OC_Log::DEBUG); - self::$_usedBackends[$backend] = new OC_User_Database(); - self::getManager()->registerBackend(self::$_usedBackends[$backend]); - break; - default: - OC_Log::write('core', 'Adding default user backend ' . $backend . '.', OC_Log::DEBUG); - $className = 'OC_USER_' . strToUpper($backend); - self::$_usedBackends[$backend] = new $className(); - self::getManager()->registerBackend(self::$_usedBackends[$backend]); - break; - } - } - return true; - } - - /** - * remove all used backends - */ - public static function clearBackends() { - self::$_usedBackends = array(); - self::getManager()->clearBackends(); - } - - /** - * setup the configured backends in config.php - */ - public static function setupBackends() { - OC_App::loadApps(array('prelogin')); - $backends = OC_Config::getValue('user_backends', array()); - foreach ($backends as $i => $config) { - $class = $config['class']; - $arguments = $config['arguments']; - if (class_exists($class)) { - if (array_search($i, self::$_setupedBackends) === false) { - // make a reflection object - $reflectionObj = new ReflectionClass($class); - - // use Reflection to create a new instance, using the $args - $backend = $reflectionObj->newInstanceArgs($arguments); - self::useBackend($backend); - self::$_setupedBackends[] = $i; - } else { - OC_Log::write('core', 'User backend ' . $class . ' already initialized.', OC_Log::DEBUG); - } - } else { - OC_Log::write('core', 'User backend ' . $class . ' not found.', OC_Log::ERROR); - } - } - } - - /** - * @brief Create a new user - * @param string $uid The username of the user to create - * @param string $password The password of the new user - * @throws Exception - * @return bool true/false - * - * Creates a new user. Basic checking of username is done in OC_User - * itself, not in its subclasses. - * - * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-" - */ - public static function createUser($uid, $password) { - return self::getManager()->createUser($uid, $password); - } - - /** - * @brief delete a user - * @param string $uid The username of the user to delete - * @return bool - * - * Deletes a user - */ - public static function deleteUser($uid) { - $user = self::getManager()->get($uid); - if ($user) { - $user->delete(); - - // We have to delete the user from all groups - foreach (OC_Group::getUserGroups($uid) as $i) { - OC_Group::removeFromGroup($uid, $i); - } - // Delete the user's keys in preferences - OC_Preferences::deleteUser($uid); - - // Delete user files in /data/ - OC_Helper::rmdirr(OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid . '/'); - } - } - - /** - * @brief Try to login a user - * @param $uid The username of the user to log in - * @param $password The password of the user - * @return bool - * - * Log in a user and regenerate a new session - if the password is ok - */ - public static function login($uid, $password) { - return self::getUserSession()->login($uid, $password); - } - - /** - * @brief Sets user id for session and triggers emit - */ - public static function setUserId($uid) { - OC::$session->set('user_id', $uid); - } - - /** - * @brief Sets user display name for session - */ - public static function setDisplayName($uid, $displayName = null) { - if (is_null($displayName)) { - $displayName = $uid; - } - $user = self::getManager()->get($uid); - if ($user) { - return $user->setDisplayName($displayName); - } else { - return false; - } - } - - /** - * @brief Logs the current user out and kills all the session data - * - * Logout, destroys session - */ - public static function logout() { - self::getUserSession()->logout(); - } - - /** - * @brief Check if the user is logged in - * @returns bool - * - * Checks if the user is logged in - */ - public static function isLoggedIn() { - if (\OC::$session->get('user_id')) { - OC_App::loadApps(array('authentication')); - self::setupBackends(); - return self::userExists(\OC::$session->get('user_id')); - } - return false; - } - - /** - * @brief Check if the user is an admin user - * @param string $uid uid of the admin - * @return bool - */ - public static function isAdminUser($uid) { - if (OC_Group::inGroup($uid, 'admin')) { - return true; - } - return false; - } - - - /** - * @brief get the user id of the user currently logged in. - * @return string uid or false - */ - public static function getUser() { - $uid = OC::$session ? OC::$session->get('user_id') : null; - if (!is_null($uid)) { - return $uid; - } else { - return false; - } - } - - /** - * @brief get the display name of the user currently logged in. - * @param string $uid - * @return string uid or false - */ - public static function getDisplayName($uid = null) { - if ($uid) { - $user = self::getManager()->get($uid); - if ($user) { - return $user->getDisplayName(); - } else { - return $uid; - } - } else { - $user = self::getUserSession()->getUser(); - if ($user) { - return $user->getDisplayName(); - } else { - return false; - } - } - } - - /** - * @brief Autogenerate a password - * @return string - * - * generates a password - */ - public static function generatePassword() { - return OC_Util::generateRandomBytes(30); - } - - /** - * @brief Set password - * @param string $uid The username - * @param string $password The new password - * @param string $recoveryPassword for the encryption app to reset encryption keys - * @return bool - * - * Change the password of a user - */ - public static function setPassword($uid, $password, $recoveryPassword = null) { - $user = self::getManager()->get($uid); - if ($user) { - return $user->setPassword($password, $recoveryPassword); - } else { - return false; - } - } - - /** - * @brief Check whether user can change his password - * @param string $uid The username - * @return bool - * - * Check whether a specified user can change his password - */ - public static function canUserChangePassword($uid) { - $user = self::getManager()->get($uid); - if ($user) { - return $user->canChangePassword(); - } else { - return false; - } - } - - /** - * @brief Check whether user can change his display name - * @param string $uid The username - * @return bool - * - * Check whether a specified user can change his display name - */ - public static function canUserChangeDisplayName($uid) { - $user = self::getManager()->get($uid); - if ($user) { - return $user->canChangeDisplayName(); - } else { - return false; - } - } - - /** - * @brief Check if the password is correct - * @param string $uid The username - * @param string $password The password - * @return mixed user id a string on success, false otherwise - * - * Check if the password is correct without logging in the user - * returns the user id or false - */ - public static function checkPassword($uid, $password) { - $manager = self::getManager(); - $username = $manager->checkPassword($uid, $password); - if ($username !== false) { - return $username->getUID(); - } - return false; - } - - /** - * @param string $uid The username - * @return string - * - * returns the path to the users home directory - */ - public static function getHome($uid) { - $user = self::getManager()->get($uid); - if ($user) { - return $user->getHome(); - } else { - return OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid; - } - } - - /** - * @brief Get a list of all users - * @returns array with all uids - * - * Get a list of all users. - */ - public static function getUsers($search = '', $limit = null, $offset = null) { - $users = self::getManager()->search($search, $limit, $offset); - $uids = array(); - foreach ($users as $user) { - $uids[] = $user->getUID(); - } - return $uids; - } - - /** - * @brief Get a list of all users display name - * @param string $search - * @param int $limit - * @param int $offset - * @return array associative array with all display names (value) and corresponding uids (key) - * - * Get a list of all display names and user ids. - */ - public static function getDisplayNames($search = '', $limit = null, $offset = null) { - $displayNames = array(); - $users = self::getManager()->searchDisplayName($search, $limit, $offset); - foreach ($users as $user) { - $displayNames[$user->getUID()] = $user->getDisplayName(); - } - return $displayNames; - } - - /** - * @brief check if a user exists - * @param string $uid the username - * @return boolean - */ - public static function userExists($uid) { - return self::getManager()->userExists($uid); - } - - /** - * disables a user - * - * @param string $uid the user to disable - */ - public static function disableUser($uid) { - $user = self::getManager()->get($uid); - if ($user) { - $user->setEnabled(false); - } - } - - /** - * enable a user - * - * @param string $uid - */ - public static function enableUser($uid) { - $user = self::getManager()->get($uid); - if ($user) { - $user->setEnabled(true); - } - } - - /** - * checks if a user is enabled - * - * @param string $uid - * @return bool - */ - public static function isEnabled($uid) { - $user = self::getManager()->get($uid); - if ($user) { - return $user->isEnabled(); - } else { - return false; - } - } - - /** - * @brief Set cookie value to use in next page load - * @param string $username username to be set - * @param string $token - */ - public static function setMagicInCookie($username, $token) { - self::getUserSession()->setMagicInCookie($username, $token); - } - - /** - * @brief Remove cookie for "remember username" - */ - public static function unsetMagicInCookie() { - self::getUserSession()->unsetMagicInCookie(); - } -} diff --git a/lib/user/backend.php b/lib/user/backend.php deleted file mode 100644 index e9be08e429c..00000000000 --- a/lib/user/backend.php +++ /dev/null @@ -1,159 +0,0 @@ -. - * - */ - -/** - * error code for functions not provided by the user backend - */ -define('OC_USER_BACKEND_NOT_IMPLEMENTED', -501); - -/** - * actions that user backends can define - */ -define('OC_USER_BACKEND_CREATE_USER', 0x000001); -define('OC_USER_BACKEND_SET_PASSWORD', 0x000010); -define('OC_USER_BACKEND_CHECK_PASSWORD', 0x000100); -define('OC_USER_BACKEND_GET_HOME', 0x001000); -define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x010000); -define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x100000); - - -/** - * Abstract base class for user management. Provides methods for querying backend - * capabilities. - * - * Subclass this for your own backends, and see OC_User_Example for descriptions - */ -abstract class OC_User_Backend implements OC_User_Interface { - - protected $possibleActions = array( - OC_USER_BACKEND_CREATE_USER => 'createUser', - OC_USER_BACKEND_SET_PASSWORD => 'setPassword', - OC_USER_BACKEND_CHECK_PASSWORD => 'checkPassword', - OC_USER_BACKEND_GET_HOME => 'getHome', - OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName', - OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName', - ); - - /** - * @brief Get all supported actions - * @return int bitwise-or'ed actions - * - * Returns the supported actions as int to be - * compared with OC_USER_BACKEND_CREATE_USER etc. - */ - public function getSupportedActions() { - $actions = 0; - foreach($this->possibleActions AS $action => $methodName) { - if(method_exists($this, $methodName)) { - $actions |= $action; - } - } - - return $actions; - } - - /** - * @brief Check if backend implements actions - * @param int $actions bitwise-or'ed actions - * @return boolean - * - * Returns the supported actions as int to be - * compared with OC_USER_BACKEND_CREATE_USER etc. - */ - public function implementsActions($actions) { - return (bool)($this->getSupportedActions() & $actions); - } - - /** - * @brief delete a user - * @param string $uid The username of the user to delete - * @return bool - * - * Deletes a user - */ - public function deleteUser( $uid ) { - return false; - } - - /** - * @brief Get a list of all users - * @returns array with all uids - * - * Get a list of all users. - */ - public function getUsers($search = '', $limit = null, $offset = null) { - return array(); - } - - /** - * @brief check if a user exists - * @param string $uid the username - * @return boolean - */ - public function userExists($uid) { - return false; - } - - /** - * @brief get the user's home directory - * @param string $uid the username - * @return boolean - */ - public function getHome($uid) { - return false; - } - - /** - * @brief get display name of the user - * @param string $uid user ID of the user - * @return string display name - */ - public function getDisplayName($uid) { - return $uid; - } - - /** - * @brief Get a list of all display names - * @returns array with all displayNames (value) and the corresponding uids (key) - * - * Get a list of all display names and user ids. - */ - public function getDisplayNames($search = '', $limit = null, $offset = null) { - $displayNames = array(); - $users = $this->getUsers($search, $limit, $offset); - foreach ( $users as $user) { - $displayNames[$user] = $user; - } - return $displayNames; - } - - /** - * @brief Check if a user list is available or not - * @return boolean if users can be listed or not - */ - public function hasUserListings() { - return false; - } -} diff --git a/lib/user/database.php b/lib/user/database.php deleted file mode 100644 index 9f00a022d9f..00000000000 --- a/lib/user/database.php +++ /dev/null @@ -1,269 +0,0 @@ -. - * - */ -/* - * - * The following SQL statement is just a help for developers and will not be - * executed! - * - * CREATE TABLE `users` ( - * `uid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, - * `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - * PRIMARY KEY (`uid`) - * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - * - */ - -require_once 'phpass/PasswordHash.php'; - -/** - * Class for user management in a SQL Database (e.g. MySQL, SQLite) - */ -class OC_User_Database extends OC_User_Backend { - /** - * @var PasswordHash - */ - static private $hasher=null; - - private function getHasher() { - if(!self::$hasher) { - //we don't want to use DES based crypt(), since it doesn't return a hash with a recognisable prefix - $forcePortable=(CRYPT_BLOWFISH!=1); - self::$hasher=new PasswordHash(8, $forcePortable); - } - return self::$hasher; - - } - - /** - * @brief Create a new user - * @param $uid The username of the user to create - * @param $password The password of the new user - * @returns true/false - * - * Creates a new user. Basic checking of username is done in OC_User - * itself, not in its subclasses. - */ - public function createUser( $uid, $password ) { - if( $this->userExists($uid) ) { - return false; - }else{ - $hasher=$this->getHasher(); - $hash = $hasher->HashPassword($password.OC_Config::getValue('passwordsalt', '')); - $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )' ); - $result = $query->execute( array( $uid, $hash)); - - return $result ? true : false; - } - } - - /** - * @brief delete a user - * @param $uid The username of the user to delete - * @returns true/false - * - * Deletes a user - */ - public function deleteUser( $uid ) { - // Delete user-group-relation - $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*users` WHERE `uid` = ?' ); - $query->execute( array( $uid )); - return true; - } - - /** - * @brief Set password - * @param $uid The username - * @param $password The new password - * @returns true/false - * - * Change the password of a user - */ - public function setPassword( $uid, $password ) { - if( $this->userExists($uid) ) { - $hasher=$this->getHasher(); - $hash = $hasher->HashPassword($password.OC_Config::getValue('passwordsalt', '')); - $query = OC_DB::prepare( 'UPDATE `*PREFIX*users` SET `password` = ? WHERE `uid` = ?' ); - $query->execute( array( $hash, $uid )); - - return true; - }else{ - return false; - } - } - - /** - * @brief Set display name - * @param $uid The username - * @param $displayName The new display name - * @returns true/false - * - * Change the display name of a user - */ - public function setDisplayName( $uid, $displayName ) { - if( $this->userExists($uid) ) { - $query = OC_DB::prepare( 'UPDATE `*PREFIX*users` SET `displayname` = ? WHERE `uid` = ?' ); - $query->execute( array( $displayName, $uid )); - return true; - }else{ - return false; - } - } - - /** - * @brief get display name of the user - * @param $uid user ID of the user - * @return display name - */ - public function getDisplayName($uid) { - if( $this->userExists($uid) ) { - $query = OC_DB::prepare( 'SELECT `displayname` FROM `*PREFIX*users` WHERE `uid` = ?' ); - $result = $query->execute( array( $uid ))->fetchAll(); - $displayName = trim($result[0]['displayname'], ' '); - if ( !empty($displayName) ) { - return $displayName; - } else { - return $uid; - } - } - } - - /** - * @brief Get a list of all display names - * @returns array with all displayNames (value) and the correspondig uids (key) - * - * Get a list of all display names and user ids. - */ - public function getDisplayNames($search = '', $limit = null, $offset = null) { - $displayNames = array(); - $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`' - .' WHERE LOWER(`displayname`) LIKE LOWER(?)', $limit, $offset); - $result = $query->execute(array($search.'%')); - $users = array(); - while ($row = $result->fetchRow()) { - $displayNames[$row['uid']] = $row['displayname']; - } - - // let's see if we can also find some users who don't have a display name yet - $query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`' - .' WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset); - $result = $query->execute(array($search.'%')); - while ($row = $result->fetchRow()) { - $displayName = trim($row['displayname'], ' '); - if ( empty($displayName) ) { - $displayNames[$row['uid']] = $row['uid']; - } - } - - - return $displayNames; - } - - /** - * @brief Check if the password is correct - * @param $uid The username - * @param $password The password - * @returns string - * - * Check if the password is correct without logging in the user - * returns the user id or false - */ - public function checkPassword( $uid, $password ) { - $query = OC_DB::prepare( 'SELECT `uid`, `password` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' ); - $result = $query->execute( array( $uid)); - - $row=$result->fetchRow(); - if($row) { - $storedHash=$row['password']; - if ($storedHash[0]=='$') {//the new phpass based hashing - $hasher=$this->getHasher(); - if($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''), $storedHash)) { - return $row['uid']; - }else{ - return false; - } - }else{//old sha1 based hashing - if(sha1($password)==$storedHash) { - //upgrade to new hashing - $this->setPassword($row['uid'], $password); - return $row['uid']; - }else{ - return false; - } - } - }else{ - return false; - } - } - - /** - * @brief Get a list of all users - * @returns array with all uids - * - * Get a list of all users. - */ - public function getUsers($search = '', $limit = null, $offset = null) { - $query = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*users` WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset); - $result = $query->execute(array($search.'%')); - $users = array(); - while ($row = $result->fetchRow()) { - $users[] = $row['uid']; - } - return $users; - } - - /** - * @brief check if a user exists - * @param string $uid the username - * @return boolean - */ - public function userExists($uid) { - $query = OC_DB::prepare( 'SELECT COUNT(*) FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' ); - $result = $query->execute( array( $uid )); - if (OC_DB::isError($result)) { - OC_Log::write('core', OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - return $result->fetchOne() > 0; - } - - /** - * @brief get the user's home directory - * @param string $uid the username - * @return boolean - */ - public function getHome($uid) { - if($this->userExists($uid)) { - return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid; - }else{ - return false; - } - } - - /** - * @return bool - */ - public function hasUserListings() { - return true; - } - -} diff --git a/lib/user/dummy.php b/lib/user/dummy.php deleted file mode 100644 index b5b7a6c3c7a..00000000000 --- a/lib/user/dummy.php +++ /dev/null @@ -1,126 +0,0 @@ -. - * - */ - -/** - * dummy user backend, does not keep state, only for testing use - */ -class OC_User_Dummy extends OC_User_Backend { - private $users = array(); - - /** - * @brief Create a new user - * @param string $uid The username of the user to create - * @param string $password The password of the new user - * @return bool - * - * Creates a new user. Basic checking of username is done in OC_User - * itself, not in its subclasses. - */ - public function createUser($uid, $password) { - if (isset($this->users[$uid])) { - return false; - } else { - $this->users[$uid] = $password; - return true; - } - } - - /** - * @brief delete a user - * @param string $uid The username of the user to delete - * @return bool - * - * Deletes a user - */ - public function deleteUser($uid) { - if (isset($this->users[$uid])) { - unset($this->users[$uid]); - return true; - } else { - return false; - } - } - - /** - * @brief Set password - * @param string $uid The username - * @param string $password The new password - * @return bool - * - * Change the password of a user - */ - public function setPassword($uid, $password) { - if (isset($this->users[$uid])) { - $this->users[$uid] = $password; - return true; - } else { - return false; - } - } - - /** - * @brief Check if the password is correct - * @param string $uid The username - * @param string $password The password - * @return string - * - * Check if the password is correct without logging in the user - * returns the user id or false - */ - public function checkPassword($uid, $password) { - if (isset($this->users[$uid])) { - return ($this->users[$uid] == $password); - } else { - return false; - } - } - - /** - * @brief Get a list of all users - * @param string $search - * @param int $limit - * @param int $offset - * @return array with all uids - * - * Get a list of all users. - */ - public function getUsers($search = '', $limit = null, $offset = null) { - return array_keys($this->users); - } - - /** - * @brief check if a user exists - * @param string $uid the username - * @return boolean - */ - public function userExists($uid) { - return isset($this->users[$uid]); - } - - /** - * @return bool - */ - public function hasUserListings() { - return true; - } -} diff --git a/lib/user/example.php b/lib/user/example.php deleted file mode 100644 index b2d0dc25410..00000000000 --- a/lib/user/example.php +++ /dev/null @@ -1,70 +0,0 @@ -. - * - */ - -/** - * abstract reference class for user management - * this class should only be used as a reference for method signatures and their descriptions - */ -abstract class OC_User_Example extends OC_User_Backend { - /** - * @brief Create a new user - * @param $uid The username of the user to create - * @param $password The password of the new user - * @returns true/false - * - * Creates a new user. Basic checking of username is done in OC_User - * itself, not in its subclasses. - */ - abstract public function createUser($uid, $password); - - /** - * @brief Set password - * @param $uid The username - * @param $password The new password - * @returns true/false - * - * Change the password of a user - */ - abstract public function setPassword($uid, $password); - - /** - * @brief Check if the password is correct - * @param $uid The username - * @param $password The password - * @returns string - * - * Check if the password is correct without logging in the user - * returns the user id or false - */ - abstract public function checkPassword($uid, $password); - - /** - * @brief get the user's home directory - * @param $uid The username - * @returns string - * - * get the user's home directory - * returns the path or false - */ - abstract public function getHome($uid); -} diff --git a/lib/user/http.php b/lib/user/http.php deleted file mode 100644 index e99afe59ba7..00000000000 --- a/lib/user/http.php +++ /dev/null @@ -1,110 +0,0 @@ -. -* -*/ - -/** - * user backend using http auth requests - */ -class OC_User_HTTP extends OC_User_Backend { - /** - * split http://user@host/path into a user and url part - * @param string path - * @return array - */ - private function parseUrl($url) { - $parts=parse_url($url); - $url=$parts['scheme'].'://'.$parts['host']; - if(isset($parts['port'])) { - $url.=':'.$parts['port']; - } - $url.=$parts['path']; - if(isset($parts['query'])) { - $url.='?'.$parts['query']; - } - return array($parts['user'], $url); - - } - - /** - * check if an url is a valid login - * @param string url - * @return boolean - */ - private function matchUrl($url) { - return ! is_null(parse_url($url, PHP_URL_USER)); - } - - /** - * @brief Check if the password is correct - * @param $uid The username - * @param $password The password - * @returns string - * - * Check if the password is correct without logging in the user - * returns the user id or false - */ - public function checkPassword($uid, $password) { - if(!$this->matchUrl($uid)) { - return false; - } - list($user, $url)=$this->parseUrl($uid); - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$password); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - curl_exec($ch); - - $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); - - curl_close($ch); - - if($status === 200) { - return $uid; - } - - return false; - } - - /** - * @brief check if a user exists - * @param string $uid the username - * @return boolean - */ - public function userExists($uid) { - return $this->matchUrl($uid); - } - - /** - * @brief get the user's home directory - * @param string $uid the username - * @return boolean - */ - public function getHome($uid) { - if($this->userExists($uid)) { - return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid; - }else{ - return false; - } - } -} diff --git a/lib/user/interface.php b/lib/user/interface.php deleted file mode 100644 index c72bdfaf3fd..00000000000 --- a/lib/user/interface.php +++ /dev/null @@ -1,80 +0,0 @@ -. - * - */ - -interface OC_User_Interface { - - /** - * @brief Check if backend implements actions - * @param $actions bitwise-or'ed actions - * @returns boolean - * - * Returns the supported actions as int to be - * compared with OC_USER_BACKEND_CREATE_USER etc. - */ - public function implementsActions($actions); - - /** - * @brief delete a user - * @param $uid The username of the user to delete - * @returns true/false - * - * Deletes a user - */ - public function deleteUser($uid); - - /** - * @brief Get a list of all users - * @returns array with all uids - * - * Get a list of all users. - */ - public function getUsers($search = '', $limit = null, $offset = null); - - /** - * @brief check if a user exists - * @param string $uid the username - * @return boolean - */ - public function userExists($uid); - - /** - * @brief get display name of the user - * @param $uid user ID of the user - * @return display name - */ - public function getDisplayName($uid); - - /** - * @brief Get a list of all display names - * @returns array with all displayNames (value) and the corresponding uids (key) - * - * Get a list of all display names and user ids. - */ - public function getDisplayNames($search = '', $limit = null, $offset = null); - - /** - * @brief Check if a user list is available or not - * @return boolean if users can be listed or not - */ - public function hasUserListings(); -} diff --git a/lib/user/manager.php b/lib/user/manager.php deleted file mode 100644 index 13286bc28a4..00000000000 --- a/lib/user/manager.php +++ /dev/null @@ -1,250 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\User; - -use OC\Hooks\PublicEmitter; - -/** - * Class Manager - * - * Hooks available in scope \OC\User: - * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) - * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) - * - preDelete(\OC\User\User $user) - * - postDelete(\OC\User\User $user) - * - preCreateUser(string $uid, string $password) - * - postCreateUser(\OC\User\User $user, string $password) - * - * @package OC\User - */ -class Manager extends PublicEmitter { - /** - * @var \OC_User_Backend[] $backends - */ - private $backends = array(); - - /** - * @var \OC\User\User[] $cachedUsers - */ - private $cachedUsers = array(); - - public function __construct() { - $cachedUsers = $this->cachedUsers; - $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) { - $i = array_search($user, $cachedUsers); - if ($i !== false) { - unset($cachedUsers[$i]); - } - }); - } - - /** - * register a user backend - * - * @param \OC_User_Backend $backend - */ - public function registerBackend($backend) { - $this->backends[] = $backend; - } - - /** - * remove a user backend - * - * @param \OC_User_Backend $backend - */ - public function removeBackend($backend) { - $this->cachedUsers = array(); - if (($i = array_search($backend, $this->backends)) !== false) { - unset($this->backends[$i]); - } - } - - /** - * remove all user backends - */ - public function clearBackends() { - $this->cachedUsers = array(); - $this->backends = array(); - } - - /** - * get a user by user id - * - * @param string $uid - * @return \OC\User\User - */ - public function get($uid) { - if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends - return $this->cachedUsers[$uid]; - } - foreach ($this->backends as $backend) { - if ($backend->userExists($uid)) { - return $this->getUserObject($uid, $backend); - } - } - return null; - } - - /** - * get or construct the user object - * - * @param string $uid - * @param \OC_User_Backend $backend - * @return \OC\User\User - */ - protected function getUserObject($uid, $backend) { - if (isset($this->cachedUsers[$uid])) { - return $this->cachedUsers[$uid]; - } - $this->cachedUsers[$uid] = new User($uid, $backend, $this); - return $this->cachedUsers[$uid]; - } - - /** - * check if a user exists - * - * @param string $uid - * @return bool - */ - public function userExists($uid) { - $user = $this->get($uid); - return ($user !== null); - } - - /** - * Check if the password is valid for the user - * - * @param $loginname - * @param $password - * @return mixed the User object on success, false otherwise - */ - public function checkPassword($loginname, $password) { - foreach ($this->backends as $backend) { - if($backend->implementsActions(\OC_USER_BACKEND_CHECK_PASSWORD)) { - $uid = $backend->checkPassword($loginname, $password); - if ($uid !== false) { - return $this->getUserObject($uid, $backend); - } - } - } - return false; - } - - /** - * search by user id - * - * @param string $pattern - * @param int $limit - * @param int $offset - * @return \OC\User\User[] - */ - public function search($pattern, $limit = null, $offset = null) { - $users = array(); - foreach ($this->backends as $backend) { - $backendUsers = $backend->getUsers($pattern, $limit, $offset); - if (is_array($backendUsers)) { - foreach ($backendUsers as $uid) { - $users[] = $this->getUserObject($uid, $backend); - if (!is_null($limit)) { - $limit--; - } - if (!is_null($offset) and $offset > 0) { - $offset--; - } - - } - } - } - - usort($users, function ($a, $b) { - /** - * @var \OC\User\User $a - * @var \OC\User\User $b - */ - return strcmp($a->getUID(), $b->getUID()); - }); - return $users; - } - - /** - * search by displayName - * - * @param string $pattern - * @param int $limit - * @param int $offset - * @return \OC\User\User[] - */ - public function searchDisplayName($pattern, $limit = null, $offset = null) { - $users = array(); - foreach ($this->backends as $backend) { - $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset); - if (is_array($backendUsers)) { - foreach ($backendUsers as $uid => $displayName) { - $users[] = $this->getUserObject($uid, $backend); - if (!is_null($limit)) { - $limit--; - } - if (!is_null($offset) and $offset > 0) { - $offset--; - } - - } - } - } - - usort($users, function ($a, $b) { - /** - * @var \OC\User\User $a - * @var \OC\User\User $b - */ - return strcmp($a->getDisplayName(), $b->getDisplayName()); - }); - return $users; - } - - /** - * @param string $uid - * @param string $password - * @throws \Exception - * @return bool | \OC\User\User the created user of false - */ - public function createUser($uid, $password) { - // Check the name for bad characters - // Allowed are: "a-z", "A-Z", "0-9" and "_.@-" - if (preg_match('/[^a-zA-Z0-9 _\.@\-]/', $uid)) { - throw new \Exception('Only the following characters are allowed in a username:' - . ' "a-z", "A-Z", "0-9", and "_.@-"'); - } - // No empty username - if (trim($uid) == '') { - throw new \Exception('A valid username must be provided'); - } - // No empty password - if (trim($password) == '') { - throw new \Exception('A valid password must be provided'); - } - - // Check if user already exists - if ($this->userExists($uid)) { - throw new \Exception('The username is already being used'); - } - - $this->emit('\OC\User', 'preCreateUser', array($uid, $password)); - foreach ($this->backends as $backend) { - if ($backend->implementsActions(\OC_USER_BACKEND_CREATE_USER)) { - $backend->createUser($uid, $password); - $user = $this->getUserObject($uid, $backend); - $this->emit('\OC\User', 'postCreateUser', array($user, $password)); - return $user; - } - } - return false; - } -} diff --git a/lib/user/session.php b/lib/user/session.php deleted file mode 100644 index 525c65ab8a1..00000000000 --- a/lib/user/session.php +++ /dev/null @@ -1,174 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\User; - -use OC\Hooks\Emitter; - -/** - * Class Session - * - * Hooks available in scope \OC\User: - * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) - * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) - * - preDelete(\OC\User\User $user) - * - postDelete(\OC\User\User $user) - * - preCreateUser(string $uid, string $password) - * - postCreateUser(\OC\User\User $user) - * - preLogin(string $user, string $password) - * - postLogin(\OC\User\User $user) - * - logout() - * - * @package OC\User - */ -class Session implements Emitter, \OCP\IUserSession { - /** - * @var \OC\User\Manager $manager - */ - private $manager; - - /** - * @var \OC\Session\Session $session - */ - private $session; - - /** - * @var \OC\User\User $activeUser - */ - protected $activeUser; - - /** - * @param \OC\User\Manager $manager - * @param \OC\Session\Session $session - */ - public function __construct($manager, $session) { - $this->manager = $manager; - $this->session = $session; - } - - /** - * @param string $scope - * @param string $method - * @param callable $callback - */ - public function listen($scope, $method, $callback) { - $this->manager->listen($scope, $method, $callback); - } - - /** - * @param string $scope optional - * @param string $method optional - * @param callable $callback optional - */ - public function removeListener($scope = null, $method = null, $callback = null) { - $this->manager->removeListener($scope, $method, $callback); - } - - /** - * get the manager object - * - * @return \OC\User\Manager - */ - public function getManager() { - return $this->manager; - } - - /** - * set the currently active user - * - * @param \OC\User\User $user - */ - public function setUser($user) { - if (is_null($user)) { - $this->session->remove('user_id'); - } else { - $this->session->set('user_id', $user->getUID()); - } - $this->activeUser = $user; - } - - /** - * get the current active user - * - * @return \OC\User\User - */ - public function getUser() { - if ($this->activeUser) { - return $this->activeUser; - } else { - $uid = $this->session->get('user_id'); - if ($uid) { - $this->activeUser = $this->manager->get($uid); - return $this->activeUser; - } else { - return null; - } - } - } - - /** - * try to login with the provided credentials - * - * @param string $uid - * @param string $password - * @return bool - */ - public function login($uid, $password) { - $this->manager->emit('\OC\User', 'preLogin', array($uid, $password)); - $user = $this->manager->checkPassword($uid, $password); - if($user !== false) { - if (!is_null($user)) { - if ($user->isEnabled()) { - $this->setUser($user); - $this->manager->emit('\OC\User', 'postLogin', array($user, $password)); - return true; - } else { - return false; - } - } - } else { - return false; - } - } - - /** - * logout the user from the session - */ - public function logout() { - $this->manager->emit('\OC\User', 'logout'); - $this->setUser(null); - $this->unsetMagicInCookie(); - } - - /** - * Set cookie value to use in next page load - * - * @param string $username username to be set - * @param string $token - */ - public function setMagicInCookie($username, $token) { - $secure_cookie = \OC_Config::getValue("forcessl", false); //TODO: DI for cookies and OC_Config - $expires = time() + \OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); - setcookie("oc_username", $username, $expires, \OC::$WEBROOT, '', $secure_cookie); - setcookie("oc_token", $token, $expires, \OC::$WEBROOT, '', $secure_cookie, true); - setcookie("oc_remember_login", true, $expires, \OC::$WEBROOT, '', $secure_cookie); - } - - /** - * Remove cookie for "remember username" - */ - public function unsetMagicInCookie() { - unset($_COOKIE["oc_username"]); //TODO: DI - unset($_COOKIE["oc_token"]); - unset($_COOKIE["oc_remember_login"]); - setcookie('oc_username', '', time()-3600, \OC::$WEBROOT); - setcookie('oc_token', '', time()-3600, \OC::$WEBROOT); - setcookie('oc_remember_login', '', time()-3600, \OC::$WEBROOT); - } -} diff --git a/lib/user/user.php b/lib/user/user.php deleted file mode 100644 index e5f842944f1..00000000000 --- a/lib/user/user.php +++ /dev/null @@ -1,179 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\User; - -use OC\Hooks\Emitter; - -class User { - /** - * @var string $uid - */ - private $uid; - - /** - * @var string $displayName - */ - private $displayName; - - /** - * @var \OC_User_Backend $backend - */ - private $backend; - - /** - * @var bool $enabled - */ - private $enabled; - - /** - * @var Emitter | Manager $emitter - */ - private $emitter; - - /** - * @param string $uid - * @param \OC_User_Backend $backend - * @param Emitter $emitter - */ - public function __construct($uid, $backend, $emitter = null) { - $this->uid = $uid; - if ($backend and $backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) { - $this->displayName = $backend->getDisplayName($uid); - } else { - $this->displayName = $uid; - } - $this->backend = $backend; - $this->emitter = $emitter; - $enabled = \OC_Preferences::getValue($uid, 'core', 'enabled', 'true'); //TODO: DI for OC_Preferences - $this->enabled = ($enabled === 'true'); - } - - /** - * get the user id - * - * @return string - */ - public function getUID() { - return $this->uid; - } - - /** - * get the displayname for the user, if no specific displayname is set it will fallback to the user id - * - * @return string - */ - public function getDisplayName() { - return $this->displayName; - } - - /** - * set the displayname for the user - * - * @param string $displayName - * @return bool - */ - public function setDisplayName($displayName) { - if ($this->canChangeDisplayName()) { - $this->displayName = $displayName; - $result = $this->backend->setDisplayName($this->uid, $displayName); - return $result !== false; - } else { - return false; - } - } - - /** - * Delete the user - * - * @return bool - */ - public function delete() { - if ($this->emitter) { - $this->emitter->emit('\OC\User', 'preDelete', array($this)); - } - $result = $this->backend->deleteUser($this->uid); - if ($this->emitter) { - $this->emitter->emit('\OC\User', 'postDelete', array($this)); - } - return !($result === false); - } - - /** - * Set the password of the user - * - * @param string $password - * @param string $recoveryPassword for the encryption app to reset encryption keys - * @return bool - */ - public function setPassword($password, $recoveryPassword) { - if ($this->emitter) { - $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword)); - } - if ($this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD)) { - $result = $this->backend->setPassword($this->uid, $password); - if ($this->emitter) { - $this->emitter->emit('\OC\User', 'postSetPassword', array($this, $password, $recoveryPassword)); - } - return !($result === false); - } else { - return false; - } - } - - /** - * get the users home folder to mount - * - * @return string - */ - public function getHome() { - if ($this->backend->implementsActions(\OC_USER_BACKEND_GET_HOME) and $home = $this->backend->getHome($this->uid)) { - return $home; - } - return \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $this->uid; //TODO switch to Config object once implemented - } - - /** - * check if the backend supports changing passwords - * - * @return bool - */ - public function canChangePassword() { - return $this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD); - } - - /** - * check if the backend supports changing display names - * - * @return bool - */ - public function canChangeDisplayName() { - return $this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME); - } - - /** - * check if the user is enabled - * - * @return bool - */ - public function isEnabled() { - return $this->enabled; - } - - /** - * set the enabled status for the user - * - * @param bool $enabled - */ - public function setEnabled($enabled) { - $this->enabled = $enabled; - $enabled = ($enabled) ? 'true' : 'false'; - \OC_Preferences::setValue($this->uid, 'core', 'enabled', $enabled); - } -} diff --git a/lib/util.php b/lib/util.php deleted file mode 100755 index 6be56d07c9a..00000000000 --- a/lib/util.php +++ /dev/null @@ -1,1019 +0,0 @@ -$configDataDirectory), '/'); - self::$rootMounted = true; - } - - //if we aren't logged in, there is no use to set up the filesystem - if( $user != "" ) { - $quota = self::getUserQuota($user); - if ($quota !== \OC\Files\SPACE_UNLIMITED) { - \OC\Files\Filesystem::addStorageWrapper(function($mountPoint, $storage) use ($quota, $user) { - if ($mountPoint === '/' . $user . '/'){ - return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota)); - } else { - return $storage; - } - }); - } - $userDir = '/'.$user.'/files'; - $userRoot = OC_User::getHome($user); - $userDirectory = $userRoot . '/files'; - if( !is_dir( $userDirectory )) { - mkdir( $userDirectory, 0755, true ); - } - //jail the user into his "home" directory - \OC\Files\Filesystem::init($user, $userDir); - - $fileOperationProxy = new OC_FileProxy_FileOperations(); - OC_FileProxy::register($fileOperationProxy); - - OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir)); - } - return true; - } - - public static function getUserQuota($user){ - $userQuota = OC_Preferences::getValue($user, 'files', 'quota', 'default'); - if($userQuota === 'default') { - $userQuota = OC_AppConfig::getValue('files', 'default_quota', 'none'); - } - if($userQuota === 'none') { - return \OC\Files\SPACE_UNLIMITED; - }else{ - return OC_Helper::computerFileSize($userQuota); - } - } - - /** - * @return void - */ - public static function tearDownFS() { - \OC\Files\Filesystem::tearDown(); - self::$fsSetup=false; - self::$rootMounted=false; - } - - /** - * @brief get the current installed version of ownCloud - * @return array - */ - public static function getVersion() { - // hint: We only can count up. Reset minor/patchlevel when - // updating major/minor version number. - return array(5, 80, 07); - } - - /** - * @brief get the current installed version string of ownCloud - * @return string - */ - public static function getVersionString() { - return '6.0 pre alpha'; - } - - /** - * @description get the current installed edition of ownCloud. There is the community - * edition that just returns an empty string and the enterprise edition - * that returns "Enterprise". - * @return string - */ - public static function getEditionString() { - return ''; - } - - /** - * @brief add a javascript file - * - * @param string $application - * @param filename $file - * @return void - */ - public static function addScript( $application, $file = null ) { - if ( is_null( $file )) { - $file = $application; - $application = ""; - } - if ( !empty( $application )) { - self::$scripts[] = "$application/js/$file"; - } else { - self::$scripts[] = "js/$file"; - } - } - - /** - * @brief add a css file - * - * @param string $application - * @param filename $file - * @return void - */ - public static function addStyle( $application, $file = null ) { - if ( is_null( $file )) { - $file = $application; - $application = ""; - } - if ( !empty( $application )) { - self::$styles[] = "$application/css/$file"; - } else { - self::$styles[] = "css/$file"; - } - } - - /** - * @brief Add a custom element to the header - * @param string $tag tag name of the element - * @param array $attributes array of attributes for the element - * @param string $text the text content for the element - * @return void - */ - public static function addHeader( $tag, $attributes, $text='') { - self::$headers[] = array( - 'tag'=>$tag, - 'attributes'=>$attributes, - 'text'=>$text - ); - } - - /** - * @brief formats a timestamp in the "right" way - * - * @param int $timestamp - * @param bool $dateOnly option to omit time from the result - * @return string timestamp - * @description adjust to clients timezone if we know it - */ - public static function formatDate( $timestamp, $dateOnly=false) { - if(\OC::$session->exists('timezone')) { - $systemTimeZone = intval(date('O')); - $systemTimeZone = (round($systemTimeZone/100, 0)*60) + ($systemTimeZone%100); - $clientTimeZone = \OC::$session->get('timezone')*60; - $offset = $clientTimeZone - $systemTimeZone; - $timestamp = $timestamp + $offset*60; - } - $l = OC_L10N::get('lib'); - return $l->l($dateOnly ? 'date' : 'datetime', $timestamp); - } - - /** - * @brief check if the current server configuration is suitable for ownCloud - * @return array arrays with error messages and hints - */ - public static function checkServer() { - // Assume that if checkServer() succeeded before in this session, then all is fine. - if(\OC::$session->exists('checkServer_suceeded') && \OC::$session->get('checkServer_suceeded')) { - return array(); - } - - $errors = array(); - - $defaults = new \OC_Defaults(); - - $webServerRestart = false; - //check for database drivers - if(!(is_callable('sqlite_open') or class_exists('SQLite3')) - and !is_callable('mysql_connect') - and !is_callable('pg_connect') - and !is_callable('oci_connect')) { - $errors[] = array( - 'error'=>'No database drivers (sqlite, mysql, or postgresql) installed.', - 'hint'=>'' //TODO: sane hint - ); - $webServerRestart = true; - } - - //common hint for all file permissions error messages - $permissionsHint = 'Permissions can usually be fixed by ' - .'giving the webserver write access to the root directory.'; - - // Check if config folder is writable. - if(!is_writable(OC::$SERVERROOT."/config/") or !is_readable(OC::$SERVERROOT."/config/")) { - $errors[] = array( - 'error' => "Can't write into config directory", - 'hint' => 'This can usually be fixed by ' - .'giving the webserver write access to the config directory.' - ); - } - - // Check if there is a writable install folder. - if(OC_Config::getValue('appstoreenabled', true)) { - if( OC_App::getInstallPath() === null - || !is_writable(OC_App::getInstallPath()) - || !is_readable(OC_App::getInstallPath()) ) { - $errors[] = array( - 'error' => "Can't write into apps directory", - 'hint' => 'This can usually be fixed by ' - .'giving the webserver write access to the apps directory ' - .'or disabling the appstore in the config file.' - ); - } - } - $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - // Create root dir. - if(!is_dir($CONFIG_DATADIRECTORY)) { - $success=@mkdir($CONFIG_DATADIRECTORY); - if ($success) { - $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); - } else { - $errors[] = array( - 'error' => "Can't create data directory (".$CONFIG_DATADIRECTORY.")", - 'hint' => 'This can usually be fixed by ' - .'giving the webserver write access to the root directory.' - ); - } - } else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) { - $errors[] = array( - 'error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud', - 'hint'=>$permissionsHint - ); - } else { - $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY)); - } - - $moduleHint = "Please ask your server administrator to install the module."; - // check if all required php modules are present - if(!class_exists('ZipArchive')) { - $errors[] = array( - 'error'=>'PHP module zip not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(!class_exists('DOMDocument')) { - $errors[] = array( - 'error' => 'PHP module dom not installed.', - 'hint' => $moduleHint - ); - $webServerRestart =true; - } - if(!function_exists('xml_parser_create')) { - $errors[] = array( - 'error' => 'PHP module libxml not installed.', - 'hint' => $moduleHint - ); - $webServerRestart = true; - } - if(!function_exists('mb_detect_encoding')) { - $errors[] = array( - 'error'=>'PHP module mb multibyte not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(!function_exists('ctype_digit')) { - $errors[] = array( - 'error'=>'PHP module ctype is not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(!function_exists('json_encode')) { - $errors[] = array( - 'error'=>'PHP module JSON is not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(!extension_loaded('gd') || !function_exists('gd_info')) { - $errors[] = array( - 'error'=>'PHP module GD is not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(!function_exists('gzencode')) { - $errors[] = array( - 'error'=>'PHP module zlib is not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(!function_exists('iconv')) { - $errors[] = array( - 'error'=>'PHP module iconv is not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(!function_exists('simplexml_load_string')) { - $errors[] = array( - 'error'=>'PHP module SimpleXML is not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if(floatval(phpversion()) < 5.3) { - $errors[] = array( - 'error'=>'PHP 5.3 is required.', - 'hint'=>'Please ask your server administrator to update PHP to version 5.3 or higher.' - .' PHP 5.2 is no longer supported by ownCloud and the PHP community.' - ); - $webServerRestart = true; - } - if(!defined('PDO::ATTR_DRIVER_NAME')) { - $errors[] = array( - 'error'=>'PHP PDO module is not installed.', - 'hint'=>$moduleHint - ); - $webServerRestart = true; - } - if (((strtolower(@ini_get('safe_mode')) == 'on') - || (strtolower(@ini_get('safe_mode')) == 'yes') - || (strtolower(@ini_get('safe_mode')) == 'true') - || (ini_get("safe_mode") == 1 ))) { - $errors[] = array( - 'error'=>'PHP Safe Mode is enabled. ownCloud requires that it is disabled to work properly.', - 'hint'=>'PHP Safe Mode is a deprecated and mostly useless setting that should be disabled. ' - .'Please ask your server administrator to disable it in php.ini or in your webserver config.' - ); - $webServerRestart = true; - } - if (get_magic_quotes_gpc() == 1 ) { - $errors[] = array( - 'error'=>'Magic Quotes is enabled. ownCloud requires that it is disabled to work properly.', - 'hint'=>'Magic Quotes is a deprecated and mostly useless setting that should be disabled. ' - .'Please ask your server administrator to disable it in php.ini or in your webserver config.' - ); - $webServerRestart = true; - } - - if($webServerRestart) { - $errors[] = array( - 'error'=>'PHP modules have been installed, but they are still listed as missing?', - 'hint'=>'Please ask your server administrator to restart the web server.' - ); - } - - // Cache the result of this function - \OC::$session->set('checkServer_suceeded', count($errors) == 0); - - return $errors; - } - - /** - * @brief check if there are still some encrypted files stored - * @return boolean - */ - public static function encryptedFiles() { - //check if encryption was enabled in the past - $encryptedFiles = false; - if (OC_App::isEnabled('files_encryption') === false) { - $view = new OC\Files\View('/' . OCP\User::getUser()); - $keyfilePath = '/files_encryption/keyfiles'; - if ($view->is_dir($keyfilePath)) { - $dircontent = $view->getDirectoryContent($keyfilePath); - if (!empty($dircontent)) { - $encryptedFiles = true; - } - } - } - - return $encryptedFiles; - } - - /** - * @brief Check for correct file permissions of data directory - * @paran string $dataDirectory - * @return array arrays with error messages and hints - */ - public static function checkDataDirectoryPermissions($dataDirectory) { - $errors = array(); - if (self::runningOnWindows()) { - //TODO: permissions checks for windows hosts - } else { - $permissionsModHint = 'Please change the permissions to 0770 so that the directory' - .' cannot be listed by other users.'; - $perms = substr(decoct(@fileperms($dataDirectory)), -3); - if (substr($perms, -1) != '0') { - OC_Helper::chmodr($dataDirectory, 0770); - clearstatcache(); - $perms = substr(decoct(@fileperms($dataDirectory)), -3); - if (substr($perms, 2, 1) != '0') { - $errors[] = array( - 'error' => 'Data directory ('.$dataDirectory.') is readable for other users', - 'hint' => $permissionsModHint - ); - } - } - } - return $errors; - } - - /** - * @return void - */ - public static function displayLoginPage($errors = array()) { - $parameters = array(); - foreach( $errors as $key => $value ) { - $parameters[$value] = true; - } - if (!empty($_POST['user'])) { - $parameters["username"] = $_POST['user']; - $parameters['user_autofocus'] = false; - } else { - $parameters["username"] = ''; - $parameters['user_autofocus'] = true; - } - if (isset($_REQUEST['redirect_url'])) { - $redirectUrl = $_REQUEST['redirect_url']; - $parameters['redirect_url'] = urlencode($redirectUrl); - } - - $parameters['alt_login'] = OC_App::getAlternativeLogIns(); - OC_Template::printGuestPage("", "login", $parameters); - } - - - /** - * @brief Check if the app is enabled, redirects to home if not - * @return void - */ - public static function checkAppEnabled($app) { - if( !OC_App::isEnabled($app)) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); - exit(); - } - } - - /** - * Check if the user is logged in, redirects to home if not. With - * redirect URL parameter to the request URI. - * @return void - */ - public static function checkLoggedIn() { - // Check if we are a user - if( !OC_User::isLoggedIn()) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', - array('redirectUrl' => OC_Request::requestUri()) - )); - exit(); - } - } - - /** - * @brief Check if the user is a admin, redirects to home if not - * @return void - */ - public static function checkAdminUser() { - if( !OC_User::isAdminUser(OC_User::getUser())) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); - exit(); - } - } - - /** - * @brief Check if the user is a subadmin, redirects to home if not - * @return array $groups where the current user is subadmin - */ - public static function checkSubAdminUser() { - if(!OC_SubAdmin::isSubAdmin(OC_User::getUser())) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); - exit(); - } - return true; - } - - /** - * @brief Redirect to the user default page - * @return void - */ - public static function redirectToDefaultPage() { - if(isset($_REQUEST['redirect_url'])) { - $location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url'])); - } - else if (isset(OC::$REQUESTEDAPP) && !empty(OC::$REQUESTEDAPP)) { - $location = OC_Helper::linkToAbsolute( OC::$REQUESTEDAPP, 'index.php' ); - } else { - $defaultPage = OC_Appconfig::getValue('core', 'defaultpage'); - if ($defaultPage) { - $location = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/'.$defaultPage); - } else { - $location = OC_Helper::linkToAbsolute( 'files', 'index.php' ); - } - } - OC_Log::write('core', 'redirectToDefaultPage: '.$location, OC_Log::DEBUG); - header( 'Location: '.$location ); - exit(); - } - - /** - * @brief get an id unique for this instance - * @return string - */ - public static function getInstanceId() { - $id = OC_Config::getValue('instanceid', null); - if(is_null($id)) { - // We need to guarantee at least one letter in instanceid so it can be used as the session_name - $id = 'oc' . self::generateRandomBytes(10); - OC_Config::setValue('instanceid', $id); - } - return $id; - } - - /** - * @brief Static lifespan (in seconds) when a request token expires. - * @see OC_Util::callRegister() - * @see OC_Util::isCallRegistered() - * @description - * Also required for the client side to compute the point in time when to - * request a fresh token. The client will do so when nearly 97% of the - * time span coded here has expired. - */ - public static $callLifespan = 3600; // 3600 secs = 1 hour - - /** - * @brief Register an get/post call. Important to prevent CSRF attacks. - * @todo Write howto: CSRF protection guide - * @return $token Generated token. - * @description - * Creates a 'request token' (random) and stores it inside the session. - * Ever subsequent (ajax) request must use such a valid token to succeed, - * otherwise the request will be denied as a protection against CSRF. - * The tokens expire after a fixed lifespan. - * @see OC_Util::$callLifespan - * @see OC_Util::isCallRegistered() - */ - public static function callRegister() { - // Check if a token exists - if(!\OC::$session->exists('requesttoken')) { - // No valid token found, generate a new one. - $requestToken = self::generateRandomBytes(20); - \OC::$session->set('requesttoken', $requestToken); - } else { - // Valid token already exists, send it - $requestToken = \OC::$session->get('requesttoken'); - } - return($requestToken); - } - - /** - * @brief Check an ajax get/post call if the request token is valid. - * @return boolean False if request token is not set or is invalid. - * @see OC_Util::$callLifespan - * @see OC_Util::callRegister() - */ - public static function isCallRegistered() { - if(!\OC::$session->exists('requesttoken')) { - return false; - } - - if(isset($_GET['requesttoken'])) { - $token = $_GET['requesttoken']; - } elseif(isset($_POST['requesttoken'])) { - $token = $_POST['requesttoken']; - } elseif(isset($_SERVER['HTTP_REQUESTTOKEN'])) { - $token = $_SERVER['HTTP_REQUESTTOKEN']; - } else { - //no token found. - return false; - } - - // Check if the token is valid - if($token !== \OC::$session->get('requesttoken')) { - // Not valid - return false; - } else { - // Valid token - return true; - } - } - - /** - * @brief Check an ajax get/post call if the request token is valid. exit if not. - * @todo Write howto - * @return void - */ - public static function callCheck() { - if(!OC_Util::isCallRegistered()) { - exit(); - } - } - - /** - * @brief Public function to sanitize HTML - * - * This function is used to sanitize HTML and should be applied on any - * string or array of strings before displaying it on a web page. - * - * @param string|array of strings - * @return array with sanitized strings or a single sanitized string, depends on the input parameter. - */ - public static function sanitizeHTML( &$value ) { - if (is_array($value)) { - array_walk_recursive($value, 'OC_Util::sanitizeHTML'); - } else { - //Specify encoding for PHP<5.4 - $value = htmlentities((string)$value, ENT_QUOTES, 'UTF-8'); - } - return $value; - } - - /** - * @brief Public function to encode url parameters - * - * This function is used to encode path to file before output. - * Encoding is done according to RFC 3986 with one exception: - * Character '/' is preserved as is. - * - * @param string $component part of URI to encode - * @return string - */ - public static function encodePath($component) { - $encoded = rawurlencode($component); - $encoded = str_replace('%2F', '/', $encoded); - return $encoded; - } - - /** - * @brief Check if the htaccess file is working - * @return bool - * @description Check if the htaccess file is working by creating a test - * file in the data directory and trying to access via http - */ - public static function isHtAccessWorking() { - // testdata - $fileName = '/htaccesstest.txt'; - $testContent = 'testcontent'; - - // creating a test file - $testFile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$fileName; - - if(file_exists($testFile)) {// already running this test, possible recursive call - return false; - } - - $fp = @fopen($testFile, 'w'); - @fwrite($fp, $testContent); - @fclose($fp); - - // accessing the file via http - $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$fileName); - $fp = @fopen($url, 'r'); - $content=@fread($fp, 2048); - @fclose($fp); - - // cleanup - @unlink($testFile); - - // does it work ? - if($content==$testContent) { - return false; - } else { - return true; - } - } - - /** - * @brief test if webDAV is working properly - * @return bool - * @description - * The basic assumption is that if the server returns 401/Not Authenticated for an unauthenticated PROPFIND - * the web server it self is setup properly. - * - * Why not an authenticated PROPFIND and other verbs? - * - We don't have the password available - * - We have no idea about other auth methods implemented (e.g. OAuth with Bearer header) - * - */ - public static function isWebDAVWorking() { - if (!function_exists('curl_init')) { - return true; - } - $settings = array( - 'baseUri' => OC_Helper::linkToRemote('webdav'), - ); - - $client = new \Sabre_DAV_Client($settings); - - // for this self test we don't care if the ssl certificate is self signed and the peer cannot be verified. - $client->setVerifyPeer(false); - - $return = true; - try { - // test PROPFIND - $client->propfind('', array('{DAV:}resourcetype')); - } catch (\Sabre_DAV_Exception_NotAuthenticated $e) { - $return = true; - } catch (\Exception $e) { - OC_Log::write('core', 'isWebDAVWorking: NO - Reason: '.$e->getMessage(). ' ('.get_class($e).')', OC_Log::WARN); - $return = false; - } - - return $return; - } - - /** - * Check if the setlocal call does not work. This can happen if the right - * local packages are not available on the server. - * @return bool - */ - public static function isSetLocaleWorking() { - // setlocale test is pointless on Windows - if (OC_Util::runningOnWindows() ) { - return true; - } - - $result = setlocale(LC_ALL, 'en_US.UTF-8', 'en_US.UTF8'); - if($result == false) { - return false; - } - return true; - } - - /** - * @brief Check if the PHP module fileinfo is loaded. - * @return bool - */ - public static function fileInfoLoaded() { - return function_exists('finfo_open'); - } - - /** - * @brief Check if the ownCloud server can connect to the internet - * @return bool - */ - public static function isInternetConnectionWorking() { - // in case there is no internet connection on purpose return false - if (self::isInternetConnectionEnabled() === false) { - return false; - } - - // try to connect to owncloud.org to see if http connections to the internet are possible. - $connected = @fsockopen("www.owncloud.org", 80); - if ($connected) { - fclose($connected); - return true; - } else { - // second try in case one server is down - $connected = @fsockopen("apps.owncloud.com", 80); - if ($connected) { - fclose($connected); - return true; - } else { - return false; - } - } - } - - /** - * @brief Check if the connection to the internet is disabled on purpose - * @return bool - */ - public static function isInternetConnectionEnabled(){ - return \OC_Config::getValue("has_internet_connection", true); - } - - /** - * @brief clear all levels of output buffering - * @return void - */ - public static function obEnd(){ - while (ob_get_level()) { - ob_end_clean(); - } - } - - - /** - * @brief Generates a cryptographic secure pseudo-random string - * @param Int $length of the random string - * @return String - * Please also update secureRNGAvailable if you change something here - */ - public static function generateRandomBytes($length = 30) { - // Try to use openssl_random_pseudo_bytes - if (function_exists('openssl_random_pseudo_bytes')) { - $pseudoByte = bin2hex(openssl_random_pseudo_bytes($length, $strong)); - if($strong == true) { - return substr($pseudoByte, 0, $length); // Truncate it to match the length - } - } - - // Try to use /dev/urandom - if (!self::runningOnWindows()) { - $fp = @file_get_contents('/dev/urandom', false, null, 0, $length); - if ($fp !== false) { - $string = substr(bin2hex($fp), 0, $length); - return $string; - } - } - - // Fallback to mt_rand() - $characters = '0123456789'; - $characters .= 'abcdefghijklmnopqrstuvwxyz'; - $charactersLength = strlen($characters)-1; - $pseudoByte = ""; - - // Select some random characters - for ($i = 0; $i < $length; $i++) { - $pseudoByte .= $characters[mt_rand(0, $charactersLength)]; - } - return $pseudoByte; - } - - /** - * @brief Checks if a secure random number generator is available - * @return bool - */ - public static function secureRNGAvailable() { - // Check openssl_random_pseudo_bytes - if(function_exists('openssl_random_pseudo_bytes')) { - openssl_random_pseudo_bytes(1, $strong); - if($strong == true) { - return true; - } - } - - // Check /dev/urandom - if (!self::runningOnWindows()) { - $fp = @file_get_contents('/dev/urandom', false, null, 0, 1); - if ($fp !== false) { - return true; - } - } - - return false; - } - - /** - * @Brief Get file content via curl. - * @param string $url Url to get content - * @return string of the response or false on error - * This function get the content of a page via curl, if curl is enabled. - * If not, file_get_element is used. - */ - public static function getUrlContent($url){ - if (function_exists('curl_init')) { - $curl = curl_init(); - - curl_setopt($curl, CURLOPT_HEADER, 0); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); - curl_setopt($curl, CURLOPT_URL, $url); - curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($curl, CURLOPT_MAXREDIRS, 10); - - curl_setopt($curl, CURLOPT_USERAGENT, "ownCloud Server Crawler"); - if(OC_Config::getValue('proxy', '') != '') { - curl_setopt($curl, CURLOPT_PROXY, OC_Config::getValue('proxy')); - } - if(OC_Config::getValue('proxyuserpwd', '') != '') { - curl_setopt($curl, CURLOPT_PROXYUSERPWD, OC_Config::getValue('proxyuserpwd')); - } - $data = curl_exec($curl); - curl_close($curl); - - } else { - $contextArray = null; - - if(OC_Config::getValue('proxy', '') != '') { - $contextArray = array( - 'http' => array( - 'timeout' => 10, - 'proxy' => OC_Config::getValue('proxy') - ) - ); - } else { - $contextArray = array( - 'http' => array( - 'timeout' => 10 - ) - ); - } - - $ctx = stream_context_create( - $contextArray - ); - $data = @file_get_contents($url, 0, $ctx); - - } - return $data; - } - - /** - * @return bool - well are we running on windows or not - */ - public static function runningOnWindows() { - return (substr(PHP_OS, 0, 3) === "WIN"); - } - - /** - * Handles the case that there may not be a theme, then check if a "default" - * theme exists and take that one - * @return string the theme - */ - public static function getTheme() { - $theme = OC_Config::getValue("theme", ''); - - if($theme === '') { - if(is_dir(OC::$SERVERROOT . '/themes/default')) { - $theme = 'default'; - } - } - - return $theme; - } - - /** - * @brief Clear the opcode cache if one exists - * This is necessary for writing to the config file - * in case the opcode cache does not re-validate files - * @return void - */ - public static function clearOpcodeCache() { - // APC - if (function_exists('apc_clear_cache')) { - apc_clear_cache(); - } - // Zend Opcache - if (function_exists('accelerator_reset')) { - accelerator_reset(); - } - // XCache - if (function_exists('xcache_clear_cache')) { - xcache_clear_cache(XC_TYPE_VAR, 0); - } - // Opcache (PHP >= 5.5) - if (function_exists('opcache_reset')) { - opcache_reset(); - } - } - - /** - * Normalize a unicode string - * @param string $value a not normalized string - * @return bool|string - */ - public static function normalizeUnicode($value) { - if(class_exists('Patchwork\PHP\Shim\Normalizer')) { - $normalizedValue = \Patchwork\PHP\Shim\Normalizer::normalize($value); - if($normalizedValue === false) { - \OC_Log::write( 'core', 'normalizing failed for "' . $value . '"', \OC_Log::WARN); - } else { - $value = $normalizedValue; - } - } - - return $value; - } - - /** - * @return string - */ - public static function basename($file) { - $file = rtrim($file, '/'); - $t = explode('/', $file); - return array_pop($t); - } -} diff --git a/lib/vobject.php b/lib/vobject.php deleted file mode 100644 index 267176ebc07..00000000000 --- a/lib/vobject.php +++ /dev/null @@ -1,207 +0,0 @@ -. - * - */ - -/** - * This class provides a streamlined interface to the Sabre VObject classes - */ -class OC_VObject{ - /** @var Sabre\VObject\Component */ - protected $vobject; - - /** - * @returns Sabre\VObject\Component - */ - public function getVObject() { - return $this->vobject; - } - - /** - * @brief Parses the VObject - * @param string VObject as string - * @returns Sabre_VObject or null - */ - public static function parse($data) { - try { - Sabre\VObject\Property::$classMap['LAST-MODIFIED'] = 'Sabre\VObject\Property\DateTime'; - $vobject = Sabre\VObject\Reader::read($data); - if ($vobject instanceof Sabre\VObject\Component) { - $vobject = new OC_VObject($vobject); - } - return $vobject; - } catch (Exception $e) { - OC_Log::write('vobject', $e->getMessage(), OC_Log::ERROR); - return null; - } - } - - /** - * @brief Escapes semicolons - * @param string $value - * @return string - */ - public static function escapeSemicolons($value) { - foreach($value as &$i ) { - $i = implode("\\\\;", explode(';', $i)); - } - return implode(';', $value); - } - - /** - * @brief Creates an array out of a multivalue property - * @param string $value - * @return array - */ - public static function unescapeSemicolons($value) { - $array = explode(';', $value); - for($i=0;$ivobject = $vobject_or_name; - } else { - $this->vobject = new Sabre\VObject\Component($vobject_or_name); - } - } - - public function add($item, $itemValue = null) { - if ($item instanceof OC_VObject) { - $item = $item->getVObject(); - } - $this->vobject->add($item, $itemValue); - } - - /** - * @brief Add property to vobject - * @param object $name of property - * @param object $value of property - * @param object $parameters of property - * @returns Sabre_VObject_Property newly created - */ - public function addProperty($name, $value, $parameters=array()) { - if(is_array($value)) { - $value = OC_VObject::escapeSemicolons($value); - } - $property = new Sabre\VObject\Property( $name, $value ); - foreach($parameters as $name => $value) { - $property->parameters[] = new Sabre\VObject\Parameter($name, $value); - } - - $this->vobject->add($property); - return $property; - } - - public function setUID() { - $uid = substr(md5(rand().time()), 0, 10); - $this->vobject->add('UID', $uid); - } - - public function setString($name, $string) { - if ($string != '') { - $string = strtr($string, array("\r\n"=>"\n")); - $this->vobject->__set($name, $string); - }else{ - $this->vobject->__unset($name); - } - } - - /** - * Sets or unsets the Date and Time for a property. - * When $datetime is set to 'now', use the current time - * When $datetime is null, unset the property - * - * @param string property name - * @param DateTime $datetime - * @param int $dateType - * @return void - */ - public function setDateTime($name, $datetime, $dateType=Sabre\VObject\Property\DateTime::LOCALTZ) { - if ($datetime == 'now') { - $datetime = new DateTime(); - } - if ($datetime instanceof DateTime) { - $datetime_element = new Sabre\VObject\Property\DateTime($name); - $datetime_element->setDateTime($datetime, $dateType); - $this->vobject->__set($name, $datetime_element); - }else{ - $this->vobject->__unset($name); - } - } - - public function getAsString($name) { - return $this->vobject->__isset($name) ? - $this->vobject->__get($name)->value : - ''; - } - - public function getAsArray($name) { - $values = array(); - if ($this->vobject->__isset($name)) { - $values = explode(',', $this->getAsString($name)); - $values = array_map('trim', $values); - } - return $values; - } - - public function &__get($name) { - if ($name == 'children') { - return $this->vobject->children; - } - $return = $this->vobject->__get($name); - if ($return instanceof Sabre\VObject\Component) { - $return = new OC_VObject($return); - } - return $return; - } - - public function __set($name, $value) { - return $this->vobject->__set($name, $value); - } - - public function __unset($name) { - return $this->vobject->__unset($name); - } - - public function __isset($name) { - return $this->vobject->__isset($name); - } - - public function __call($function, $arguments) { - return call_user_func_array(array($this->vobject, $function), $arguments); - } -} diff --git a/lib/vobject/compoundproperty.php b/lib/vobject/compoundproperty.php deleted file mode 100644 index 7fe42574bed..00000000000 --- a/lib/vobject/compoundproperty.php +++ /dev/null @@ -1,70 +0,0 @@ -. - * - */ - -namespace OC\VObject; - -/** - * This class overrides \Sabre\VObject\Property::serialize() to not - * double escape commas and semi-colons in compound properties. -*/ -class CompoundProperty extends \Sabre\VObject\Property\Compound { - - /** - * Turns the object back into a serialized blob. - * - * @return string - */ - public function serialize() { - - $str = $this->name; - if ($this->group) { - $str = $this->group . '.' . $this->name; - } - - foreach($this->parameters as $param) { - $str.=';' . $param->serialize(); - } - $src = array( - "\n", - ); - $out = array( - '\n', - ); - $str.=':' . str_replace($src, $out, $this->value); - - $out = ''; - while(strlen($str) > 0) { - if (strlen($str) > 75) { - $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n"; - $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8'); - } else { - $out .= $str . "\r\n"; - $str = ''; - break; - } - } - - return $out; - - } - -} diff --git a/lib/vobject/stringproperty.php b/lib/vobject/stringproperty.php deleted file mode 100644 index a9d63a0a789..00000000000 --- a/lib/vobject/stringproperty.php +++ /dev/null @@ -1,80 +0,0 @@ -. - * - */ - -namespace OC\VObject; - -/** - * This class overrides \Sabre\VObject\Property::serialize() properly - * escape commas and semi-colons in string properties. -*/ -class StringProperty extends \Sabre\VObject\Property { - - /** - * Turns the object back into a serialized blob. - * - * @return string - */ - public function serialize() { - - $str = $this->name; - if ($this->group) { - $str = $this->group . '.' . $this->name; - } - - foreach($this->parameters as $param) { - $str.=';' . $param->serialize(); - } - - $src = array( - '\\', - "\n", - ';', - ',', - ); - $out = array( - '\\\\', - '\n', - '\;', - '\,', - ); - $value = strtr($this->value, array('\,' => ',', '\;' => ';', '\\\\' => '\\')); - $str.=':' . str_replace($src, $out, $value); - - $out = ''; - while(strlen($str) > 0) { - if (strlen($str) > 75) { - $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n"; - $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8'); - } else { - $out .= $str . "\r\n"; - $str = ''; - break; - } - } - - return $out; - - } - -} diff --git a/tests/lib/autoloader.php b/tests/lib/autoloader.php index 0e7d606ccf6..b182dc87477 100644 --- a/tests/lib/autoloader.php +++ b/tests/lib/autoloader.php @@ -19,15 +19,15 @@ class AutoLoader extends \PHPUnit_Framework_TestCase { } public function testLeadingSlashOnClassName() { - $this->assertEquals(array('files/storage/local.php'), $this->loader->findClass('\OC\Files\Storage\Local')); + $this->assertEquals(array('private/files/storage/local.php'), $this->loader->findClass('\OC\Files\Storage\Local')); } public function testNoLeadingSlashOnClassName() { - $this->assertEquals(array('files/storage/local.php'), $this->loader->findClass('OC\Files\Storage\Local')); + $this->assertEquals(array('private/files/storage/local.php'), $this->loader->findClass('OC\Files\Storage\Local')); } public function testLegacyPath() { - $this->assertEquals(array('legacy/files.php', 'files.php'), $this->loader->findClass('OC_Files')); + $this->assertEquals(array('private/legacy/files.php', 'private/files.php'), $this->loader->findClass('OC_Files')); } public function testClassPath() { @@ -54,11 +54,11 @@ class AutoLoader extends \PHPUnit_Framework_TestCase { } public function testLoadCoreNamespace() { - $this->assertEquals(array('foo/bar.php'), $this->loader->findClass('OC\Foo\Bar')); + $this->assertEquals(array('private/foo/bar.php'), $this->loader->findClass('OC\Foo\Bar')); } public function testLoadCore() { - $this->assertEquals(array('legacy/foo/bar.php', 'foo/bar.php'), $this->loader->findClass('OC_Foo_Bar')); + $this->assertEquals(array('private/legacy/foo/bar.php', 'private/foo/bar.php'), $this->loader->findClass('OC_Foo_Bar')); } public function testLoadPublicNamespace() { -- cgit v1.2.3 From 8e0060405dd585a33f58d6a5520532726b3af5d6 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 30 Sep 2013 16:39:03 +0200 Subject: reorganize file in lib --- .../sabre/aborteduploaddetectionplugin.php | 101 ---- .../sabre/aborteduploaddetectionplugin.php | 101 ++++ lib/private/tagmanager.php | 68 +++ lib/private/tags.php | 642 +++++++++++++++++++++ lib/tagmanager.php | 68 --- lib/tags.php | 642 --------------------- 6 files changed, 811 insertions(+), 811 deletions(-) delete mode 100644 lib/connector/sabre/aborteduploaddetectionplugin.php create mode 100644 lib/private/connector/sabre/aborteduploaddetectionplugin.php create mode 100644 lib/private/tagmanager.php create mode 100644 lib/private/tags.php delete mode 100644 lib/tagmanager.php delete mode 100644 lib/tags.php diff --git a/lib/connector/sabre/aborteduploaddetectionplugin.php b/lib/connector/sabre/aborteduploaddetectionplugin.php deleted file mode 100644 index 15dca3a6809..00000000000 --- a/lib/connector/sabre/aborteduploaddetectionplugin.php +++ /dev/null @@ -1,101 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * Class OC_Connector_Sabre_AbortedUploadDetectionPlugin - * - * This plugin will verify if the uploaded data has been stored completely. - * This is done by comparing the content length of the request with the file size on storage. - */ -class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPlugin { - - /** - * Reference to main server object - * - * @var Sabre_DAV_Server - */ - private $server; - - /** - * is kept public to allow overwrite for unit testing - * - * @var \OC\Files\View - */ - public $fileView; - - /** - * This initializes the plugin. - * - * This function is called by Sabre_DAV_Server, after - * addPlugin is called. - * - * This method should set up the requires event subscriptions. - * - * @param Sabre_DAV_Server $server - */ - public function initialize(Sabre_DAV_Server $server) { - - $this->server = $server; - - $server->subscribeEvent('afterCreateFile', array($this, 'verifyContentLength'), 10); - $server->subscribeEvent('afterWriteContent', array($this, 'verifyContentLength'), 10); - } - - /** - * @param $filePath - * @param Sabre_DAV_INode $node - * @throws Sabre_DAV_Exception_BadRequest - */ - public function verifyContentLength($filePath, Sabre_DAV_INode $node = null) { - - // ownCloud chunked upload will be handled in its own plugin - $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked'); - if ($chunkHeader) { - return; - } - - // compare expected and actual size - $expected = $this->getLength(); - if (!$expected) { - return; - } - $actual = $this->getFileView()->filesize($filePath); - if ($actual != $expected) { - $this->getFileView()->unlink($filePath); - throw new Sabre_DAV_Exception_BadRequest('expected filesize ' . $expected . ' got ' . $actual); - } - - } - - /** - * @return string - */ - public function getLength() - { - $req = $this->server->httpRequest; - $length = $req->getHeader('X-Expected-Entity-Length'); - if (!$length) { - $length = $req->getHeader('Content-Length'); - } - - return $length; - } - - /** - * @return \OC\Files\View - */ - public function getFileView() - { - if (is_null($this->fileView)) { - // initialize fileView - $this->fileView = \OC\Files\Filesystem::getView(); - } - - return $this->fileView; - } -} diff --git a/lib/private/connector/sabre/aborteduploaddetectionplugin.php b/lib/private/connector/sabre/aborteduploaddetectionplugin.php new file mode 100644 index 00000000000..15dca3a6809 --- /dev/null +++ b/lib/private/connector/sabre/aborteduploaddetectionplugin.php @@ -0,0 +1,101 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class OC_Connector_Sabre_AbortedUploadDetectionPlugin + * + * This plugin will verify if the uploaded data has been stored completely. + * This is done by comparing the content length of the request with the file size on storage. + */ +class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPlugin { + + /** + * Reference to main server object + * + * @var Sabre_DAV_Server + */ + private $server; + + /** + * is kept public to allow overwrite for unit testing + * + * @var \OC\Files\View + */ + public $fileView; + + /** + * This initializes the plugin. + * + * This function is called by Sabre_DAV_Server, after + * addPlugin is called. + * + * This method should set up the requires event subscriptions. + * + * @param Sabre_DAV_Server $server + */ + public function initialize(Sabre_DAV_Server $server) { + + $this->server = $server; + + $server->subscribeEvent('afterCreateFile', array($this, 'verifyContentLength'), 10); + $server->subscribeEvent('afterWriteContent', array($this, 'verifyContentLength'), 10); + } + + /** + * @param $filePath + * @param Sabre_DAV_INode $node + * @throws Sabre_DAV_Exception_BadRequest + */ + public function verifyContentLength($filePath, Sabre_DAV_INode $node = null) { + + // ownCloud chunked upload will be handled in its own plugin + $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked'); + if ($chunkHeader) { + return; + } + + // compare expected and actual size + $expected = $this->getLength(); + if (!$expected) { + return; + } + $actual = $this->getFileView()->filesize($filePath); + if ($actual != $expected) { + $this->getFileView()->unlink($filePath); + throw new Sabre_DAV_Exception_BadRequest('expected filesize ' . $expected . ' got ' . $actual); + } + + } + + /** + * @return string + */ + public function getLength() + { + $req = $this->server->httpRequest; + $length = $req->getHeader('X-Expected-Entity-Length'); + if (!$length) { + $length = $req->getHeader('Content-Length'); + } + + return $length; + } + + /** + * @return \OC\Files\View + */ + public function getFileView() + { + if (is_null($this->fileView)) { + // initialize fileView + $this->fileView = \OC\Files\Filesystem::getView(); + } + + return $this->fileView; + } +} diff --git a/lib/private/tagmanager.php b/lib/private/tagmanager.php new file mode 100644 index 00000000000..9a371a11253 --- /dev/null +++ b/lib/private/tagmanager.php @@ -0,0 +1,68 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Factory class creating instances of \OCP\ITags + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class TagManager implements \OCP\ITagManager { + + /** + * User + * + * @var string + */ + private $user = null; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user) { + + $this->user = $user; + + } + + /** + * Create a new \OCP\ITags instance and load tags from db. + * + * @see \OCP\ITags + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function load($type, $defaultTags=array()) { + return new Tags($this->user, $type, $defaultTags); + } + +} \ No newline at end of file diff --git a/lib/private/tags.php b/lib/private/tags.php new file mode 100644 index 00000000000..9fdb35a7d6e --- /dev/null +++ b/lib/private/tags.php @@ -0,0 +1,642 @@ + +* @copyright 2012 Bart Visscher bartv@thisnet.nl +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class Tags implements \OCP\ITags { + + /** + * Tags + * + * @var array + */ + private $tags = array(); + + /** + * Used for storing objectid/categoryname pairs while rescanning. + * + * @var array + */ + private static $relations = array(); + + /** + * Type + * + * @var string + */ + private $type = null; + + /** + * User + * + * @var string + */ + private $user = null; + + const TAG_TABLE = '*PREFIX*vcategory'; + const RELATION_TABLE = '*PREFIX*vcategory_to_object'; + + const TAG_FAVORITE = '_$!!$_'; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user, $type, $defaultTags = array()) { + $this->user = $user; + $this->type = $type; + $this->loadTags($defaultTags); + } + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + */ + protected function loadTags($defaultTags=array()) { + $this->tags = array(); + $result = null; + $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $this->tags[$row['id']] = $row['category']; + } + } + + if(count($defaultTags) > 0 && count($this->tags) === 0) { + $this->addMultiple($defaultTags, true); + } + \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), + \OCP\Util::DEBUG); + + } + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty() { + $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ?'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + return ((int)$result->fetchOne() === 0); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @return array + */ + public function getTags() { + if(!count($this->tags)) { + return array(); + } + + $tags = array_values($this->tags); + uasort($tags, 'strnatcasecmp'); + $tagMap = array(); + + foreach($tags as $tag) { + if($tag !== self::TAG_FAVORITE) { + $tagMap[] = array( + 'id' => $this->array_searchi($tag, $this->tags), + 'name' => $tag + ); + } + } + return $tagMap; + + } + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function getIdsForTag($tag) { + $result = null; + if(is_numeric($tag)) { + $tagId = $tag; + } elseif(is_string($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } + + if($tagId === false) { + $l10n = \OC_L10N::get('core'); + throw new \Exception( + $l10n->t('Could not find category "%s"', $tag) + ); + } + + $ids = array(); + $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE + . '` WHERE `categoryid` = ?'; + + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($tagId)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $ids[] = (int)$row['objid']; + } + } + + return $ids; + } + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name) { + return $this->in_arrayi($name, $this->tags); + } + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name) { + $name = trim($name); + + if($this->hasTag($name)) { + \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG); + return false; + } + try { + $result = \OCP\DB::insertIfNotExist( + self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $name, + ) + ); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } elseif((int)$result === 0) { + \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $id = \OCP\DB::insertid(self::TAG_TABLE); + \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); + $this->tags[$id] = $name; + return $id; + } + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to) { + $from = trim($from); + $to = trim($to); + $id = $this->array_searchi($from, $this->tags); + if($id === false) { + \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG); + return false; + } + + $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? ' + . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($to, $this->user, $this->type, $id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $this->tags[$id] = $to; + return true; + } + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMultiple($names, $sync=false, $id = null) { + if(!is_array($names)) { + $names = array($names); + } + $names = array_map('trim', $names); + $newones = array(); + foreach($names as $name) { + if(($this->in_arrayi( + $name, $this->tags) == false) && $name !== '') { + $newones[] = $name; + } + if(!is_null($id) ) { + // Insert $objectid, $categoryid pairs if not exist. + self::$relations[] = array('objid' => $id, 'tag' => $name); + } + } + $this->tags = array_merge($this->tags, $newones); + if($sync === true) { + $this->save(); + } + + return true; + } + + /** + * Save the list of tags and their object relations + */ + protected function save() { + if(is_array($this->tags)) { + foreach($this->tags as $tag) { + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $tag, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + // reload tags to get the proper ids. + $this->loadTags(); + // Loop through temporarily cached objectid/tagname pairs + // and save relations. + $tags = $this->tags; + // For some reason this is needed or array_search(i) will return 0..? + ksort($tags); + foreach(self::$relations as $relation) { + $tagId = $this->array_searchi($relation['tag'], $tags); + \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG); + if($tagId) { + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $relation['objid'], + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } + self::$relations = array(); // reset + } else { + \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! ' + . print_r($this->tags, true), \OCP\Util::ERROR); + } + } + + /** + * Delete tags and tag/object relations for a user. + * + * For hooking up on post_deleteUser + * + * @param array + */ + public static function post_deleteUser($arguments) { + // Find all objectid/tagId pairs. + $result = null; + try { + $stmt = \OCP\DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'); + while( $row = $result->fetchRow()) { + try { + $stmt->execute(array($row['id'])); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); + } + } + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids) { + if(count($ids) === 0) { + // job done ;) + return true; + } + $updates = $ids; + try { + $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; + $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; + $query .= 'AND `type`= ?'; + $updates[] = $this->type; + $stmt = \OCP\DB::prepare($query); + $result = $stmt->execute($updates); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites() { + try { + return $this->getIdsForTag(self::TAG_FAVORITE); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return array(); + } + } + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid) { + if(!$this->hasTag(self::TAG_FAVORITE)) { + $this->add(self::TAG_FAVORITE, true); + } + return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid) { + return $this->unTag($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + if(!$this->hasTag($tag)) { + $this->add($tag, true); + } + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $objid, + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; + $stmt = \OCP\DB::prepare($sql); + $stmt->execute(array($objid, $tagId, $this->type)); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names) { + if(!is_array($names)) { + $names = array($names); + } + + $names = array_map('trim', $names); + + \OCP\Util::writeLog('core', __METHOD__ . ', before: ' + . print_r($this->tags, true), \OCP\Util::DEBUG); + foreach($names as $name) { + $id = null; + + if($this->hasTag($name)) { + $id = $this->array_searchi($name, $this->tags); + unset($this->tags[$id]); + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE ' + . '`uid` = ? AND `type` = ? AND `category` = ?'); + $result = $stmt->execute(array($this->user, $this->type, $name)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); + return false; + } + if(!is_null($id) && $id !== false) { + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'; + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', + __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), + \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + } + return true; + } + + // case-insensitive in_array + private function in_arrayi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return in_array(strtolower($needle), array_map('strtolower', $haystack)); + } + + // case-insensitive array_search + private function array_searchi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return array_search(strtolower($needle), array_map('strtolower', $haystack)); + } +} diff --git a/lib/tagmanager.php b/lib/tagmanager.php deleted file mode 100644 index 9a371a11253..00000000000 --- a/lib/tagmanager.php +++ /dev/null @@ -1,68 +0,0 @@ - -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 library. If not, see . -* -*/ - -/** - * Factory class creating instances of \OCP\ITags - * - * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or - * anything else that is either parsed from a vobject or that the user chooses - * to add. - * Tag names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a tag 'family' for a type, and - * tries to add a tag named 'Family' it will be silently ignored. - */ - -namespace OC; - -class TagManager implements \OCP\ITagManager { - - /** - * User - * - * @var string - */ - private $user = null; - - /** - * Constructor. - * - * @param string $user The user whos data the object will operate on. - */ - public function __construct($user) { - - $this->user = $user; - - } - - /** - * Create a new \OCP\ITags instance and load tags from db. - * - * @see \OCP\ITags - * @param string $type The type identifier e.g. 'contact' or 'event'. - * @param array $defaultTags An array of default tags to be used if none are stored. - * @return \OCP\ITags - */ - public function load($type, $defaultTags=array()) { - return new Tags($this->user, $type, $defaultTags); - } - -} \ No newline at end of file diff --git a/lib/tags.php b/lib/tags.php deleted file mode 100644 index 9fdb35a7d6e..00000000000 --- a/lib/tags.php +++ /dev/null @@ -1,642 +0,0 @@ - -* @copyright 2012 Bart Visscher bartv@thisnet.nl -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 library. If not, see . -* -*/ - -/** - * Class for easily tagging objects by their id - * - * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or - * anything else that is either parsed from a vobject or that the user chooses - * to add. - * Tag names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a tag 'family' for a type, and - * tries to add a tag named 'Family' it will be silently ignored. - */ - -namespace OC; - -class Tags implements \OCP\ITags { - - /** - * Tags - * - * @var array - */ - private $tags = array(); - - /** - * Used for storing objectid/categoryname pairs while rescanning. - * - * @var array - */ - private static $relations = array(); - - /** - * Type - * - * @var string - */ - private $type = null; - - /** - * User - * - * @var string - */ - private $user = null; - - const TAG_TABLE = '*PREFIX*vcategory'; - const RELATION_TABLE = '*PREFIX*vcategory_to_object'; - - const TAG_FAVORITE = '_$!!$_'; - - /** - * Constructor. - * - * @param string $user The user whos data the object will operate on. - */ - public function __construct($user, $type, $defaultTags = array()) { - $this->user = $user; - $this->type = $type; - $this->loadTags($defaultTags); - } - - /** - * Load tags from db. - * - * @param string $type The type identifier e.g. 'contact' or 'event'. - * @param array $defaultTags An array of default tags to be used if none are stored. - */ - protected function loadTags($defaultTags=array()) { - $this->tags = array(); - $result = null; - $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($this->user, $this->type)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $this->tags[$row['id']] = $row['category']; - } - } - - if(count($defaultTags) > 0 && count($this->tags) === 0) { - $this->addMultiple($defaultTags, true); - } - \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), - \OCP\Util::DEBUG); - - } - - /** - * Check if any tags are saved for this type and user. - * - * @return boolean. - */ - public function isEmpty() { - $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'; - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($this->user, $this->type)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - return ((int)$result->fetchOne() === 0); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - } - - /** - * Get the tags for a specific user. - * - * This returns an array with id/name maps: - * [ - * ['id' => 0, 'name' = 'First tag'], - * ['id' => 1, 'name' = 'Second tag'], - * ] - * - * @return array - */ - public function getTags() { - if(!count($this->tags)) { - return array(); - } - - $tags = array_values($this->tags); - uasort($tags, 'strnatcasecmp'); - $tagMap = array(); - - foreach($tags as $tag) { - if($tag !== self::TAG_FAVORITE) { - $tagMap[] = array( - 'id' => $this->array_searchi($tag, $this->tags), - 'name' => $tag - ); - } - } - return $tagMap; - - } - - /** - * Get the a list if items tagged with $tag. - * - * Throws an exception if the tag could not be found. - * - * @param string|integer $tag Tag id or name. - * @return array An array of object ids or false on error. - */ - public function getIdsForTag($tag) { - $result = null; - if(is_numeric($tag)) { - $tagId = $tag; - } elseif(is_string($tag)) { - $tag = trim($tag); - $tagId = $this->array_searchi($tag, $this->tags); - } - - if($tagId === false) { - $l10n = \OC_L10N::get('core'); - throw new \Exception( - $l10n->t('Could not find category "%s"', $tag) - ); - } - - $ids = array(); - $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE - . '` WHERE `categoryid` = ?'; - - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($tagId)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $ids[] = (int)$row['objid']; - } - } - - return $ids; - } - - /** - * Checks whether a tag is already saved. - * - * @param string $name The name to check for. - * @return bool - */ - public function hasTag($name) { - return $this->in_arrayi($name, $this->tags); - } - - /** - * Add a new tag. - * - * @param string $name A string with a name of the tag - * @return int the id of the added tag or false if it already exists. - */ - public function add($name) { - $name = trim($name); - - if($this->hasTag($name)) { - \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG); - return false; - } - try { - $result = \OCP\DB::insertIfNotExist( - self::TAG_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $name, - ) - ); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } elseif((int)$result === 0) { - \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - $id = \OCP\DB::insertid(self::TAG_TABLE); - \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); - $this->tags[$id] = $name; - return $id; - } - - /** - * Rename tag. - * - * @param string $from The name of the existing tag - * @param string $to The new name of the tag. - * @return bool - */ - public function rename($from, $to) { - $from = trim($from); - $to = trim($to); - $id = $this->array_searchi($from, $this->tags); - if($id === false) { - \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG); - return false; - } - - $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? ' - . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($to, $this->user, $this->type, $id)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - $this->tags[$id] = $to; - return true; - } - - /** - * Add a list of new tags. - * - * @param string[] $names A string with a name or an array of strings containing - * the name(s) of the to add. - * @param bool $sync When true, save the tags - * @param int|null $id int Optional object id to add to this|these tag(s) - * @return bool Returns false on error. - */ - public function addMultiple($names, $sync=false, $id = null) { - if(!is_array($names)) { - $names = array($names); - } - $names = array_map('trim', $names); - $newones = array(); - foreach($names as $name) { - if(($this->in_arrayi( - $name, $this->tags) == false) && $name !== '') { - $newones[] = $name; - } - if(!is_null($id) ) { - // Insert $objectid, $categoryid pairs if not exist. - self::$relations[] = array('objid' => $id, 'tag' => $name); - } - } - $this->tags = array_merge($this->tags, $newones); - if($sync === true) { - $this->save(); - } - - return true; - } - - /** - * Save the list of tags and their object relations - */ - protected function save() { - if(is_array($this->tags)) { - foreach($this->tags as $tag) { - try { - \OCP\DB::insertIfNotExist(self::TAG_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $tag, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - } - // reload tags to get the proper ids. - $this->loadTags(); - // Loop through temporarily cached objectid/tagname pairs - // and save relations. - $tags = $this->tags; - // For some reason this is needed or array_search(i) will return 0..? - ksort($tags); - foreach(self::$relations as $relation) { - $tagId = $this->array_searchi($relation['tag'], $tags); - \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG); - if($tagId) { - try { - \OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $relation['objid'], - 'categoryid' => $tagId, - 'type' => $this->type, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - } - } - self::$relations = array(); // reset - } else { - \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! ' - . print_r($this->tags, true), \OCP\Util::ERROR); - } - } - - /** - * Delete tags and tag/object relations for a user. - * - * For hooking up on post_deleteUser - * - * @param array - */ - public static function post_deleteUser($arguments) { - // Find all objectid/tagId pairs. - $result = null; - try { - $stmt = \OCP\DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - - if(!is_null($result)) { - try { - $stmt = \OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'); - while( $row = $result->fetchRow()) { - try { - $stmt->execute(array($row['id'])); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - } - try { - $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), \OCP\Util::ERROR); - } - } - - /** - * Delete tag/object relations from the db - * - * @param array $ids The ids of the objects - * @return boolean Returns false on error. - */ - public function purgeObjects(array $ids) { - if(count($ids) === 0) { - // job done ;) - return true; - } - $updates = $ids; - try { - $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; - $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; - $query .= 'AND `type`= ?'; - $updates[] = $this->type; - $stmt = \OCP\DB::prepare($query); - $result = $stmt->execute($updates); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), - \OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Get favorites for an object type - * - * @return array An array of object ids. - */ - public function getFavorites() { - try { - return $this->getIdsForTag(self::TAG_FAVORITE); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), - \OCP\Util::ERROR); - return array(); - } - } - - /** - * Add an object to favorites - * - * @param int $objid The id of the object - * @return boolean - */ - public function addToFavorites($objid) { - if(!$this->hasTag(self::TAG_FAVORITE)) { - $this->add(self::TAG_FAVORITE, true); - } - return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); - } - - /** - * Remove an object from favorites - * - * @param int $objid The id of the object - * @return boolean - */ - public function removeFromFavorites($objid) { - return $this->unTag($objid, self::TAG_FAVORITE, $this->type); - } - - /** - * Creates a tag/object relation. - * - * @param int $objid The id of the object - * @param int|string $tag The id or name of the tag - * @return boolean Returns false on database error. - */ - public function tagAs($objid, $tag) { - if(is_string($tag) && !is_numeric($tag)) { - $tag = trim($tag); - if(!$this->hasTag($tag)) { - $this->add($tag, true); - } - $tagId = $this->array_searchi($tag, $this->tags); - } else { - $tagId = $tag; - } - try { - \OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $objid, - 'categoryid' => $tagId, - 'type' => $this->type, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Delete single tag/object relation from the db - * - * @param int $objid The id of the object - * @param int|string $tag The id or name of the tag - * @return boolean - */ - public function unTag($objid, $tag) { - if(is_string($tag) && !is_numeric($tag)) { - $tag = trim($tag); - $tagId = $this->array_searchi($tag, $this->tags); - } else { - $tagId = $tag; - } - - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; - $stmt = \OCP\DB::prepare($sql); - $stmt->execute(array($objid, $tagId, $this->type)); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Delete tags from the - * - * @param string[] $names An array of tags to delete - * @return bool Returns false on error - */ - public function delete($names) { - if(!is_array($names)) { - $names = array($names); - } - - $names = array_map('trim', $names); - - \OCP\Util::writeLog('core', __METHOD__ . ', before: ' - . print_r($this->tags, true), \OCP\Util::DEBUG); - foreach($names as $name) { - $id = null; - - if($this->hasTag($name)) { - $id = $this->array_searchi($name, $this->tags); - unset($this->tags[$id]); - } - try { - $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE ' - . '`uid` = ? AND `type` = ? AND `category` = ?'); - $result = $stmt->execute(array($this->user, $this->type, $name)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), \OCP\Util::ERROR); - return false; - } - if(!is_null($id) && $id !== false) { - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'; - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($id)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', - __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), - \OCP\Util::ERROR); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - } - } - return true; - } - - // case-insensitive in_array - private function in_arrayi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return in_array(strtolower($needle), array_map('strtolower', $haystack)); - } - - // case-insensitive array_search - private function array_searchi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return array_search(strtolower($needle), array_map('strtolower', $haystack)); - } -} -- cgit v1.2.3 From b948c1a1b642e2cf99c3e59aff785d82ddec7645 Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Sat, 28 Sep 2013 17:43:14 +0200 Subject: prepare the updater for the new update channels --- lib/updater.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/updater.php b/lib/updater.php index df7332a96a9..9827d8a8c12 100644 --- a/lib/updater.php +++ b/lib/updater.php @@ -56,7 +56,7 @@ class Updater extends BasicEmitter { $version = \OC_Util::getVersion(); $version['installed'] = \OC_Appconfig::getValue('core', 'installedat'); $version['updated'] = \OC_Appconfig::getValue('core', 'lastupdatedat'); - $version['updatechannel'] = 'stable'; + $version['updatechannel'] = \OC_Util::getChannel(); $version['edition'] = \OC_Util::getEditionString(); $versionString = implode('x', $version); -- cgit v1.2.3 From 69dd6af57489395527e94b033e3f0b8d5c73ca12 Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Sat, 28 Sep 2013 02:15:18 +0200 Subject: use === Shoudn't make a difference in this case but just in case Conflicts: lib/ocsclient.php --- lib/ocsclient.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/ocsclient.php b/lib/ocsclient.php index bd0302a2a81..67966fe7cd0 100644 --- a/lib/ocsclient.php +++ b/lib/ocsclient.php @@ -36,7 +36,12 @@ class OC_OCSClient{ * to set it in the config file or it will fallback to the default */ private static function getAppStoreURL() { - $url = OC_Config::getValue('appstoreurl', 'http://api.apps.owncloud.com/v1'); + if(OC_Util::getEditionString()===''){ + $default='http://api.apps.owncloud.com/v1'; + }else{ + $default=''; + } + $url = OC_Config::getValue('appstoreurl', $default); return($url); } -- cgit v1.2.3 From 2cf26ee0b16bebe83a08e4be89681f73208ba9ae Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Fri, 27 Sep 2013 23:41:24 +0200 Subject: put the current version and edition into a seperate file to simplify packaging. introduce update channels and build version for automated channel updates. More about that later Conflicts: lib/ocsclient.php lib/util.php --- lib/util.php | 43 ++++++++++++++++++++++++++++++++++++++----- version.php | 17 +++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 version.php diff --git a/lib/util.php b/lib/util.php index e03667b0794..5bfa7d74228 100755 --- a/lib/util.php +++ b/lib/util.php @@ -96,9 +96,8 @@ class OC_Util { * @return array */ public static function getVersion() { - // hint: We only can count up. Reset minor/patchlevel when - // updating major/minor version number. - return array(5, 80, 05); + OC_Util::loadVersion(); + return $_SESSION['OC_Version']; } /** @@ -106,7 +105,8 @@ class OC_Util { * @return string */ public static function getVersionString() { - return '6.0 pre alpha'; + OC_Util::loadVersion(); + return $_SESSION['OC_VersionString']; } /** @@ -116,7 +116,40 @@ class OC_Util { * @return string */ public static function getEditionString() { - return ''; + OC_Util::loadVersion(); + return $_SESSION['OC_Edition']; + } + + /** + * @description get the update channel of the current installed of ownCloud. + * @return string + */ + public static function getChannel() { + OC_Util::loadVersion(); + return $_SESSION['OC_Channel']; + } + + /** + * @description get the build number of the current installed of ownCloud. + * @return string + */ + public static function getBuild() { + OC_Util::loadVersion(); + return $_SESSION['OC_Build']; + } + + /** + * @description load the version.php into the session as cache + */ + private static function loadVersion() { + if(!isset($_SESSION['OC_Version'])){ + require('version.php'); + $_SESSION['OC_Version']=$OC_Version; + $_SESSION['OC_VersionString']=$OC_VersionString; + $_SESSION['OC_Edition']=$OC_Edition; + $_SESSION['OC_Channel']=$OC_Channel; + $_SESSION['OC_Build']=$OC_Build; + } } /** diff --git a/version.php b/version.php new file mode 100644 index 00000000000..dcdc288959e --- /dev/null +++ b/version.php @@ -0,0 +1,17 @@ + Date: Mon, 30 Sep 2013 20:28:00 +0200 Subject: use public api for session access from server container --- lib/util.php | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/util.php b/lib/util.php index 36969f096fa..ea2eb98d23c 100755 --- a/lib/util.php +++ b/lib/util.php @@ -107,7 +107,7 @@ class OC_Util { */ public static function getVersion() { OC_Util::loadVersion(); - return $_SESSION['OC_Version']; + return \OC::$server->getSession()->get('OC_Version'); } /** @@ -116,7 +116,7 @@ class OC_Util { */ public static function getVersionString() { OC_Util::loadVersion(); - return $_SESSION['OC_VersionString']; + return \OC::$server->getSession()->get('OC_VersionString'); } /** @@ -127,7 +127,7 @@ class OC_Util { */ public static function getEditionString() { OC_Util::loadVersion(); - return $_SESSION['OC_Edition']; + return \OC::$server->getSession()->get('OC_Edition'); } /** @@ -136,7 +136,7 @@ class OC_Util { */ public static function getChannel() { OC_Util::loadVersion(); - return $_SESSION['OC_Channel']; + return \OC::$server->getSession()->get('OC_Channel'); } /** @@ -145,20 +145,26 @@ class OC_Util { */ public static function getBuild() { OC_Util::loadVersion(); - return $_SESSION['OC_Build']; + return \OC::$server->getSession()->get('OC_Build'); } /** * @description load the version.php into the session as cache */ private static function loadVersion() { - if(!isset($_SESSION['OC_Version'])){ - require('version.php'); - $_SESSION['OC_Version']=$OC_Version; - $_SESSION['OC_VersionString']=$OC_VersionString; - $_SESSION['OC_Edition']=$OC_Edition; - $_SESSION['OC_Channel']=$OC_Channel; - $_SESSION['OC_Build']=$OC_Build; + if(!\OC::$server->getSession()->exists('OC_Version')) { + require 'version.php'; + $session = \OC::$server->getSession(); + /** @var $OC_Version string */ + $session->set('OC_Version', $OC_Version); + /** @var $OC_VersionString string */ + $session->set('OC_VersionString', $OC_VersionString); + /** @var $OC_Edition string */ + $session->set('OC_Edition', $OC_Edition); + /** @var $OC_Channel string */ + $session->set('OC_Channel', $OC_Channel); + /** @var $OC_Build string */ + $session->set('OC_Build', $OC_Build); } } -- cgit v1.2.3 From bf0f3bf0da64b8b81405846169b5ee27a4289362 Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Tue, 1 Oct 2013 12:37:19 +0200 Subject: use a 4 digit number --- version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.php b/version.php index dcdc288959e..3a9cac1d38c 100644 --- a/version.php +++ b/version.php @@ -1,7 +1,7 @@ Date: Tue, 1 Oct 2013 14:28:59 +0200 Subject: add explanation --- version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.php b/version.php index 3a9cac1d38c..eb2e9a4a68b 100644 --- a/version.php +++ b/version.php @@ -1,6 +1,6 @@