summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorThomas Müller <thomas.mueller@tmit.eu>2013-09-30 20:21:51 +0200
committerThomas Müller <thomas.mueller@tmit.eu>2013-09-30 20:21:51 +0200
commitbed27b603de1b5eb736d123fd58b774c7f79a4fd (patch)
treee73b8fd5f69821561f5b0be5727e38d5700b7966 /lib
parent2cf26ee0b16bebe83a08e4be89681f73208ba9ae (diff)
parentb58a464b864e70076aa0bde6d70c727b2aa32397 (diff)
downloadnextcloud-server-bed27b603de1b5eb736d123fd58b774c7f79a4fd.tar.gz
nextcloud-server-bed27b603de1b5eb736d123fd58b774c7f79a4fd.zip
Merge branch 'master' into channels
Conflicts: lib/util.php
Diffstat (limited to 'lib')
-rw-r--r--lib/allconfig.php77
-rw-r--r--lib/app.php53
-rw-r--r--lib/appframework/app.php98
-rw-r--r--lib/appframework/controller/controller.php142
-rw-r--r--lib/appframework/core/api.php348
-rw-r--r--lib/appframework/dependencyinjection/dicontainer.php146
-rw-r--r--lib/appframework/http/dispatcher.php100
-rw-r--r--lib/appframework/http/downloadresponse.php50
-rw-r--r--lib/appframework/http/http.php148
-rw-r--r--lib/appframework/http/redirectresponse.php56
-rw-r--r--lib/appframework/http/request.php307
-rw-r--r--lib/appframework/middleware/middleware.php100
-rw-r--r--lib/appframework/middleware/middlewaredispatcher.php159
-rw-r--r--lib/appframework/middleware/security/securityexception.php41
-rw-r--r--lib/appframework/middleware/security/securitymiddleware.php136
-rw-r--r--lib/appframework/routing/routeactionhandler.php42
-rw-r--r--lib/appframework/routing/routeconfig.php186
-rw-r--r--lib/appframework/utility/methodannotationreader.php61
-rw-r--r--lib/appframework/utility/simplecontainer.php44
-rw-r--r--lib/appframework/utility/timefactory.php42
-rw-r--r--lib/archive.php3
-rw-r--r--lib/avatar.php89
-rw-r--r--lib/base.php83
-rw-r--r--lib/cache.php23
-rw-r--r--lib/cache/broker.php12
-rw-r--r--lib/cache/file.php24
-rw-r--r--lib/cache/fileglobal.php29
-rw-r--r--lib/cache/fileglobalgc.php5
-rw-r--r--lib/cache/usercache.php77
-rw-r--r--lib/connector/sabre/aborteduploaddetectionplugin.php101
-rw-r--r--lib/connector/sabre/directory.php23
-rw-r--r--lib/connector/sabre/file.php9
-rw-r--r--lib/connector/sabre/node.php11
-rw-r--r--lib/connector/sabre/objecttree.php52
-rw-r--r--lib/contactsmanager.php145
-rw-r--r--lib/db.php22
-rw-r--r--lib/db/connection.php2
-rw-r--r--lib/db/oracleconnection.php50
-rw-r--r--lib/filechunking.php2
-rw-r--r--lib/files/cache/cache.php4
-rw-r--r--lib/files/cache/scanner.php78
-rw-r--r--lib/files/node/file.php155
-rw-r--r--lib/files/node/folder.php382
-rw-r--r--lib/files/node/node.php245
-rw-r--r--lib/files/node/nonexistingfile.php89
-rw-r--r--lib/files/node/nonexistingfolder.php113
-rw-r--r--lib/files/node/root.php337
-rw-r--r--lib/files/storage/common.php21
-rw-r--r--lib/files/storage/mappedlocal.php18
-rw-r--r--lib/files/storage/storage.php2
-rw-r--r--lib/files/utils/scanner.php6
-rw-r--r--lib/files/view.php114
-rw-r--r--lib/helper.php106
-rw-r--r--lib/image.php306
-rw-r--r--lib/installer.php11
-rw-r--r--lib/l10n/ach.php8
-rw-r--r--lib/l10n/ca.php3
-rw-r--r--lib/l10n/cs_CZ.php17
-rw-r--r--lib/l10n/da.php17
-rw-r--r--lib/l10n/de.php12
-rw-r--r--lib/l10n/de_DE.php13
-rw-r--r--lib/l10n/en_GB.php72
-rw-r--r--lib/l10n/es.php24
-rw-r--r--lib/l10n/es_AR.php22
-rw-r--r--lib/l10n/es_MX.php8
-rw-r--r--lib/l10n/et_EE.php3
-rw-r--r--lib/l10n/fi_FI.php7
-rw-r--r--lib/l10n/fr.php29
-rw-r--r--lib/l10n/gl.php17
-rw-r--r--lib/l10n/hu_HU.php11
-rw-r--r--lib/l10n/it.php17
-rw-r--r--lib/l10n/ja_JP.php17
-rw-r--r--lib/l10n/km.php8
-rw-r--r--lib/l10n/ko.php8
-rw-r--r--lib/l10n/lt_LT.php52
-rw-r--r--lib/l10n/nl.php16
-rw-r--r--lib/l10n/nn_NO.php12
-rw-r--r--lib/l10n/nqo.php8
-rw-r--r--lib/l10n/pa.php16
-rw-r--r--lib/l10n/pl.php29
-rw-r--r--lib/l10n/pt_BR.php11
-rw-r--r--lib/l10n/pt_PT.php10
-rw-r--r--lib/l10n/ro.php8
-rw-r--r--lib/l10n/ru.php17
-rw-r--r--lib/l10n/sk_SK.php14
-rw-r--r--lib/l10n/sq.php8
-rw-r--r--lib/l10n/sr@latin.php8
-rw-r--r--lib/l10n/sv.php14
-rw-r--r--lib/l10n/ug.php1
-rw-r--r--lib/l10n/zh_CN.php7
-rw-r--r--lib/legacy/cache.php10
-rw-r--r--lib/legacy/preferences.php146
-rw-r--r--lib/log/rotate.php35
-rw-r--r--lib/migration/content.php3
-rw-r--r--lib/navigationmanager.php64
-rw-r--r--lib/notsquareexception.php12
-rw-r--r--lib/ocs/activity.php28
-rw-r--r--lib/ocsclient.php49
-rw-r--r--lib/preferences.php153
-rwxr-xr-xlib/preview.php630
-rw-r--r--lib/preview/image.php36
-rw-r--r--lib/preview/movies.php47
-rw-r--r--lib/preview/mp3.php48
-rw-r--r--lib/preview/office-cl.php134
-rw-r--r--lib/preview/office-fallback.php142
-rw-r--r--lib/preview/office.php22
-rw-r--r--lib/preview/pdf.php40
-rw-r--r--lib/preview/provider.php19
-rw-r--r--lib/preview/svg.php46
-rw-r--r--lib/preview/txt.php83
-rw-r--r--lib/preview/unknown.php27
-rwxr-xr-xlib/previewmanager.php38
-rw-r--r--lib/public/app.php16
-rw-r--r--lib/public/appframework/app.php81
-rw-r--r--lib/public/appframework/http/http.php89
-rw-r--r--lib/public/appframework/http/jsonresponse.php74
-rw-r--r--lib/public/appframework/http/response.php169
-rw-r--r--lib/public/appframework/http/templateresponse.php126
-rw-r--r--lib/public/appframework/iapi.php151
-rw-r--r--lib/public/appframework/iappcontainer.php57
-rw-r--r--lib/public/appframework/imiddleware.php88
-rw-r--r--lib/public/contacts.php55
-rw-r--r--lib/public/contacts/imanager.php150
-rw-r--r--lib/public/db.php11
-rw-r--r--lib/public/files/alreadyexistsexception.php11
-rw-r--r--lib/public/files/file.php53
-rw-r--r--lib/public/files/folder.php119
-rw-r--r--lib/public/files/node.php159
-rw-r--r--lib/public/files/notenoughspaceexception.php11
-rw-r--r--lib/public/files/notfoundexception.php11
-rw-r--r--lib/public/files/notpermittedexception.php11
-rw-r--r--lib/public/files/storage.php297
-rw-r--r--lib/public/icache.php55
-rw-r--r--lib/public/iconfig.php65
-rw-r--r--lib/public/icontainer.php64
-rw-r--r--lib/public/idbconnection.php74
-rw-r--r--lib/public/inavigationmanager.php27
-rw-r--r--lib/public/ipreview.php35
-rw-r--r--lib/public/irequest.php96
-rw-r--r--lib/public/iservercontainer.php125
-rw-r--r--lib/public/isession.php56
-rw-r--r--lib/public/itagmanager.php48
-rw-r--r--lib/public/itags.php164
-rw-r--r--lib/public/iusersession.php30
-rw-r--r--lib/public/share.php52
-rw-r--r--lib/public/template.php19
-rw-r--r--lib/public/user.php2
-rw-r--r--lib/search/provider/file.php3
-rw-r--r--lib/search/result.php4
-rw-r--r--lib/server.php255
-rw-r--r--lib/session/session.php2
-rw-r--r--lib/setup.php2
-rw-r--r--lib/setup/mysql.php2
-rw-r--r--lib/setup/oci.php2
-rw-r--r--lib/setup/postgresql.php2
-rw-r--r--lib/tagmanager.php68
-rw-r--r--lib/tags.php642
-rw-r--r--lib/template/functions.php16
-rw-r--r--lib/templatelayout.php5
-rw-r--r--lib/user.php62
-rw-r--r--lib/user/http.php6
-rw-r--r--lib/user/manager.php19
-rw-r--r--lib/user/session.php21
-rw-r--r--lib/user/user.php18
-rwxr-xr-xlib/util.php559
-rw-r--r--lib/vcategories.php821
166 files changed, 10827 insertions, 1774 deletions
diff --git a/lib/allconfig.php b/lib/allconfig.php
new file mode 100644
index 00000000000..72aabf60793
--- /dev/null
+++ b/lib/allconfig.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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/app.php b/lib/app.php
index 8f5dd1d685e..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();
@@ -73,11 +71,11 @@ class OC_App{
if (!defined('DEBUG') || !DEBUG) {
if (is_null($types)
- && empty(OC_Util::$core_scripts)
- && empty(OC_Util::$core_styles)) {
- OC_Util::$core_scripts = OC_Util::$scripts;
+ && empty(OC_Util::$coreScripts)
+ && empty(OC_Util::$coreStyles)) {
+ OC_Util::$coreScripts = OC_Util::$scripts;
OC_Util::$scripts = array();
- OC_Util::$core_styles = OC_Util::$styles;
+ OC_Util::$coreStyles = OC_Util::$styles;
OC_Util::$styles = 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;
}
@@ -667,14 +660,16 @@ class OC_App{
}
$dh = opendir( $apps_dir['path'] );
- while (($file = readdir($dh)) !== false) {
+ if(is_resource($dh)) {
+ while (($file = readdir($dh)) !== false) {
- if ($file[0] != '.' and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php')) {
+ if ($file[0] != '.' and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php')) {
- $apps[] = $file;
+ $apps[] = $file;
- }
+ }
+ }
}
}
@@ -868,10 +863,10 @@ class OC_App{
/**
- * Compares the app version with the owncloud version to see if the app
+ * 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
+ * @param string $appRequired the required version from the xml
* major.minor.bugfix
* @return boolean true if compatible, otherwise false
*/
diff --git a/lib/appframework/app.php b/lib/appframework/app.php
new file mode 100644
index 00000000000..7ff55bb809d
--- /dev/null
+++ b/lib/appframework/app.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..0ea0a38cc09
--- /dev/null
+++ b/lib/appframework/controller/controller.php
@@ -0,0 +1,142 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..39522ee3dd5
--- /dev/null
+++ b/lib/appframework/core/api.php
@@ -0,0 +1,348 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..3755d45fa09
--- /dev/null
+++ b/lib/appframework/dependencyinjection/dicontainer.php
@@ -0,0 +1,146 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..ea57a6860cc
--- /dev/null
+++ b/lib/appframework/http/dispatcher.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..67b9542dba6
--- /dev/null
+++ b/lib/appframework/http/downloadresponse.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..e00dc9cdc4a
--- /dev/null
+++ b/lib/appframework/http/http.php
@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..688447f1618
--- /dev/null
+++ b/lib/appframework/http/redirectresponse.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..34605acdfea
--- /dev/null
+++ b/lib/appframework/http/request.php
@@ -0,0 +1,307 @@
+<?php
+/**
+ * ownCloud - Request
+ *
+ * @author Thomas Tanghus
+ * @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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
new file mode 100644
index 00000000000..b12c03c3eb8
--- /dev/null
+++ b/lib/appframework/middleware/middleware.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..70ab108e6b8
--- /dev/null
+++ b/lib/appframework/middleware/middlewaredispatcher.php
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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; $i<count($this->middlewares); $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 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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..4f1447e1afb
--- /dev/null
+++ b/lib/appframework/middleware/security/securitymiddleware.php
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..7fb56f14eab
--- /dev/null
+++ b/lib/appframework/routing/routeactionhandler.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * ownCloud - App Framework
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller thomas.mueller@tmit.eu
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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 @@
+<?php
+/**
+ * ownCloud - App Framework
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller thomas.mueller@tmit.eu
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
new file mode 100644
index 00000000000..a51ace83a37
--- /dev/null
+++ b/lib/appframework/utility/simplecontainer.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace OC\AppFramework\Utility;
+
+// register 3rdparty autoloaders
+require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php';
+
+/**
+ * Class SimpleContainer
+ *
+ * SimpleContainer is a simple implementation of IContainer on basis of \Pimple
+ */
+class SimpleContainer extends \Pimple implements \OCP\IContainer {
+
+ /**
+ * @param string $name name of the service to query for
+ * @return object registered service for the given $name
+ */
+ public function query($name) {
+ return $this->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
new file mode 100644
index 00000000000..2c3dd6cf5e3
--- /dev/null
+++ b/lib/appframework/utility/timefactory.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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
index 364cd5a74a1..85bfae57295 100644
--- a/lib/archive.php
+++ b/lib/archive.php
@@ -119,7 +119,8 @@ abstract class OC_Archive{
* @return bool
*/
function addRecursive($path, $source) {
- if($dh=opendir($source)) {
+ $dh = opendir($source);
+ if(is_resource($dh)) {
$this->addFolder($path);
while (($file = readdir($dh)) !== false) {
if($file=='.' or $file=='..') {
diff --git a/lib/avatar.php b/lib/avatar.php
new file mode 100644
index 00000000000..f20980c364b
--- /dev/null
+++ b/lib/avatar.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it>
+ * 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/base.php b/lib/base.php
index 2613e88d053..036051119de 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));
@@ -257,20 +262,30 @@ class OC {
OC_Util::addScript("compatibility");
OC_Util::addScript("jquery.ocdialog");
OC_Util::addScript("oc-dialogs");
- OC_Util::addScript("octemplate");
OC_Util::addScript("js");
+ OC_Util::addScript("octemplate");
OC_Util::addScript("eventsource");
OC_Util::addScript("config");
//OC_Util::addScript( "multiselect" );
OC_Util::addScript('search', 'result');
OC_Util::addScript('router');
+ OC_Util::addScript("oc-requesttoken");
+
+ // avatars
+ if (\OC_Config::getValue('enable_avatars', true) === true) {
+ \OC_Util::addScript('placeholder');
+ \OC_Util::addScript('3rdparty', 'md5/md5.min');
+ \OC_Util::addScript('jquery.avatar');
+ \OC_Util::addScript('avatar');
+ }
OC_Util::addStyle("styles");
+ OC_Util::addStyle("apps");
+ OC_Util::addStyle("fixes");
OC_Util::addStyle("multiselect");
OC_Util::addStyle("jquery-ui-1.10.0.custom");
OC_Util::addStyle("jquery-tipsy");
OC_Util::addStyle("jquery.ocdialog");
- OC_Util::addScript("oc-requesttoken");
}
public static function initSession() {
@@ -356,6 +371,7 @@ class OC {
self::$loader->registerPrefix('Doctrine\\Common', 'doctrine/common/lib');
self::$loader->registerPrefix('Doctrine\\DBAL', 'doctrine/dbal/lib');
self::$loader->registerPrefix('Symfony\\Component\\Routing', 'symfony/routing');
+ self::$loader->registerPrefix('Symfony\\Component\\Console', 'symfony/console');
self::$loader->registerPrefix('Sabre\\VObject', '3rdparty');
self::$loader->registerPrefix('Sabre_', '3rdparty');
self::$loader->registerPrefix('Patchwork', '3rdparty');
@@ -415,7 +431,7 @@ class OC {
}
self::initPaths();
- OC_Util::issetlocaleworking();
+ OC_Util::isSetLocaleWorking();
// set debug mode if an xdebug session is active
if (!defined('DEBUG') || !DEBUG) {
@@ -440,6 +456,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();
@@ -490,7 +509,9 @@ class OC {
self::registerCacheHooks();
self::registerFilesystemHooks();
+ self::registerPreviewHooks();
self::registerShareHooks();
+ self::registerLogRotate();
//make sure temporary files are cleaned up
register_shutdown_function(array('OC_Helper', 'cleanTmp'));
@@ -525,7 +546,7 @@ class OC {
}
// write error into log if locale can't be set
- if (OC_Util::issetlocaleworking() == false) {
+ if (OC_Util::isSetLocaleWorking() == false) {
OC_Log::write('core',
'setting locale to en_US.UTF-8/en_US.UTF8 failed. Support is probably not installed on your system',
OC_Log::ERROR);
@@ -544,11 +565,28 @@ 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) {
+
+ }
+ // NOTE: This will be replaced to use OCP
+ $userSession = \OC_User::getUserSession();
+ $userSession->listen('postLogin', '\OC\Cache\File', 'loginListener');
+ }
+ }
+
+ /**
+ * register hooks for the cache
+ */
+ public static function registerLogRotate() {
+ if (OC_Config::getValue('installed', false) && OC_Config::getValue('log_rotate_size', 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\Log\Rotate', OC_Config::getValue("datadirectory", OC::$SERVERROOT.'/data').'/owncloud.log');
} catch (Exception $e) {
}
- OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener');
}
}
@@ -562,6 +600,14 @@ class OC {
}
/**
+ * register hooks for previews
+ */
+ public static function registerPreviewHooks() {
+ OC_Hook::connect('OC_Filesystem', 'post_write', 'OC\Preview', 'post_write');
+ OC_Hook::connect('OC_Filesystem', 'delete', 'OC\Preview', 'post_delete');
+ }
+
+ /**
* register hooks for sharing
*/
public static function registerShareHooks() {
@@ -669,12 +715,15 @@ class OC {
$app = $param['app'];
$file = $param['file'];
$app_path = OC_App::getAppPath($app);
- $file = $app_path . '/' . $file;
- unset($app, $app_path);
- if (file_exists($file)) {
- require_once $file;
- return true;
+ if (OC_App::isEnabled($app) && $app_path !== false) {
+ $file = $app_path . '/' . $file;
+ unset($app, $app_path);
+ if (file_exists($file)) {
+ require_once $file;
+ return true;
+ }
}
+ header('HTTP/1.0 404 Not Found');
return false;
}
@@ -721,6 +770,7 @@ class OC {
|| !isset($_COOKIE["oc_token"])
|| !isset($_COOKIE["oc_username"])
|| !$_COOKIE["oc_remember_login"]
+ || !OC_Util::rememberLoginAllowed()
) {
return false;
}
@@ -738,7 +788,7 @@ class OC {
if (in_array($_COOKIE['oc_token'], $tokens, true)) {
// replace successfully used token with a new one
OC_Preferences::deleteKey($_COOKIE['oc_username'], 'login_token', $_COOKIE['oc_token']);
- $token = OC_Util::generate_random_bytes(32);
+ $token = OC_Util::generateRandomBytes(32);
OC_Preferences::setValue($_COOKIE['oc_username'], 'login_token', $token, time());
OC_User::setMagicInCookie($_COOKIE['oc_username'], $token);
// login
@@ -772,14 +822,15 @@ class OC {
self::$session->set('timezone', $_POST['timezone-offset']);
}
- self::cleanupLoginTokens($_POST['user']);
+ $userid = OC_User::getUser();
+ self::cleanupLoginTokens($userid);
if (!empty($_POST["remember_login"])) {
if (defined("DEBUG") && DEBUG) {
OC_Log::write('core', 'Setting remember login to cookie', OC_Log::DEBUG);
}
- $token = OC_Util::generate_random_bytes(32);
- OC_Preferences::setValue($_POST['user'], 'login_token', $token, time());
- OC_User::setMagicInCookie($_POST["user"], $token);
+ $token = OC_Util::generateRandomBytes(32);
+ OC_Preferences::setValue($userid, 'login_token', $token, time());
+ OC_User::setMagicInCookie($userid, $token);
} else {
OC_User::unsetMagicInCookie();
}
diff --git a/lib/cache.php b/lib/cache.php
index 48b9964ba9d..a311f10a00f 100644
--- a/lib/cache.php
+++ b/lib/cache.php
@@ -6,34 +6,36 @@
* See the COPYING-README file.
*/
-class OC_Cache {
+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) {
- self::$global_cache = new OC_Cache_FileGlobal();
+ self::$global_cache = new Cache\FileGlobal();
}
return self::$global_cache;
}
/**
* get the user cache
- * @return OC_Cache
+ * @return Cache
*/
static public function getUserCache() {
if (!self::$user_cache) {
- self::$user_cache = new OC_Cache_File();
+ self::$user_cache = new Cache\File();
}
return self::$user_cache;
}
@@ -85,7 +87,7 @@ class OC_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='') {
@@ -93,6 +95,11 @@ class OC_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 a161dbfa3bb..9b7e837e1bc 100644
--- a/lib/cache/broker.php
+++ b/lib/cache/broker.php
@@ -6,8 +6,18 @@
* See the COPYING-README file.
*/
-class OC_Cache_Broker {
+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/file.php b/lib/cache/file.php
index 9fee6034a71..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;
}
}
@@ -80,9 +81,11 @@ class OC_Cache_File{
$storage = $this->getStorage();
if($storage and $storage->is_dir('/')) {
$dh=$storage->opendir('/');
- while (($file = readdir($dh)) !== false) {
- if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) {
- $storage->unlink('/'.$file);
+ if(is_resource($dh)) {
+ while (($file = readdir($dh)) !== false) {
+ if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) {
+ $storage->unlink('/'.$file);
+ }
}
}
}
@@ -94,6 +97,9 @@ class OC_Cache_File{
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);
diff --git a/lib/cache/fileglobal.php b/lib/cache/fileglobal.php
index 2fbd8ca3edb..bd049bba4d0 100644
--- a/lib/cache/fileglobal.php
+++ b/lib/cache/fileglobal.php
@@ -6,10 +6,11 @@
* 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().'/';
+ $cache_dir = get_temp_dir().'/owncloud-' . \OC_Util::getInstanceId().'/';
if (!is_dir($cache_dir)) {
mkdir($cache_dir);
}
@@ -69,30 +70,34 @@ class OC_Cache_FileGlobal{
$prefix = $this->fixKey($prefix);
if($cache_dir and is_dir($cache_dir)) {
$dh=opendir($cache_dir);
- while (($file = readdir($dh)) !== false) {
- if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)) {
- unlink($cache_dir.$file);
+ 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);
+ $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);
- while (($file = readdir($dh)) !== false) {
- if($file!='.' and $file!='..') {
- $mtime = filemtime($cache_dir.$file);
- if ($mtime < $now) {
- unlink($cache_dir.$file);
+ 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
index a29c31f9063..399dd5e6f94 100644
--- a/lib/cache/fileglobalgc.php
+++ b/lib/cache/fileglobalgc.php
@@ -1,8 +1,9 @@
<?php
+namespace OC\Cache;
-class OC_Cache_FileGlobalGC extends \OC\BackgroundJob\Job{
+class FileGlobalGC extends \OC\BackgroundJob\Job{
public function run($argument){
- OC_Cache_FileGlobal::gc();
+ FileGlobal::gc();
}
}
diff --git a/lib/cache/usercache.php b/lib/cache/usercache.php
new file mode 100644
index 00000000000..baa8820700b
--- /dev/null
+++ b/lib/cache/usercache.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Cache;
+
+/**
+ * This interface defines method for accessing the file based user cache.
+ */
+class UserCache implements \OCP\ICache {
+
+ /**
+ * @var \OC\Cache\File $userCache
+ */
+ protected $userCache;
+
+ public function __construct() {
+ $this->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/connector/sabre/aborteduploaddetectionplugin.php b/lib/connector/sabre/aborteduploaddetectionplugin.php
new file mode 100644
index 00000000000..15dca3a6809
--- /dev/null
+++ b/lib/connector/sabre/aborteduploaddetectionplugin.php
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
+ * 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/connector/sabre/directory.php b/lib/connector/sabre/directory.php
index 66cd2fcd4e3..382bdf06df1 100644
--- a/lib/connector/sabre/directory.php
+++ b/lib/connector/sabre/directory.php
@@ -74,21 +74,14 @@ 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);
+ $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();
@@ -236,7 +229,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
$storageInfo = OC_Helper::getStorageInfo($this->path);
return array(
$storageInfo['used'],
- $storageInfo['total']
+ $storageInfo['free']
);
}
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();
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 b298813a202..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');
@@ -64,7 +74,25 @@ 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
+ $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);
@@ -88,15 +116,27 @@ class ObjectTree extends \Sabre_DAV_ObjectTree {
} else {
Filesystem::mkdir($destination);
$dh = Filesystem::opendir($source);
- while (($subnode = readdir($dh)) !== false) {
+ if(is_resource($dh)) {
+ while (($subnode = readdir($dh)) !== false) {
- if ($subnode == '.' || $subnode == '..') continue;
- $this->copy($source . '/' . $subnode, $destination . '/' . $subnode);
+ 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/contactsmanager.php b/lib/contactsmanager.php
new file mode 100644
index 00000000000..fc6745b4505
--- /dev/null
+++ b/lib/contactsmanager.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller thomas.mueller@tmit.eu
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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
index ebd012c72f8..1e5d12649df 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -75,6 +75,7 @@ class OC_DB {
// 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':
@@ -86,6 +87,7 @@ class OC_DB {
'driver' => 'pdo_sqlite',
);
$connectionParams['adapter'] = '\OC\DB\AdapterSqlite';
+ $connectionParams['wrapperClass'] = 'OC\DB\Connection';
break;
case 'mysql':
$connectionParams = array(
@@ -98,6 +100,7 @@ class OC_DB {
'driver' => 'pdo_mysql',
);
$connectionParams['adapter'] = '\OC\DB\Adapter';
+ $connectionParams['wrapperClass'] = 'OC\DB\Connection';
break;
case 'pgsql':
$connectionParams = array(
@@ -109,6 +112,7 @@ class OC_DB {
'driver' => 'pdo_pgsql',
);
$connectionParams['adapter'] = '\OC\DB\AdapterPgSql';
+ $connectionParams['wrapperClass'] = 'OC\DB\Connection';
break;
case 'oci':
$connectionParams = array(
@@ -123,6 +127,8 @@ class OC_DB {
$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(
@@ -135,14 +141,14 @@ class OC_DB {
'driver' => 'pdo_sqlsrv',
);
$connectionParams['adapter'] = '\OC\DB\AdapterSQLSrv';
+ $connectionParams['wrapperClass'] = 'OC\DB\Connection';
break;
default:
return false;
}
- $connectionParams['wrapperClass'] = 'OC\DB\Connection';
$connectionParams['tablePrefix'] = OC_Config::getValue('dbtableprefix', 'oc_' );
try {
- self::$connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
+ 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
@@ -330,18 +336,6 @@ class OC_DB {
}
/**
- * @brief Disconnect
- *
- * This is good bye, good bye, yeah!
- */
- public static function disconnect() {
- // Cut connection if required
- if(self::$connection) {
- self::$connection->close();
- }
- }
-
- /**
* @brief saves database schema to xml file
* @param string $file name of file
* @param int $mode
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/db/oracleconnection.php b/lib/db/oracleconnection.php
new file mode 100644
index 00000000000..e2fc4644f47
--- /dev/null
+++ b/lib/db/oracleconnection.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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/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/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 . '`';
diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php
index 87fa7c1365a..96f84609cf2 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,22 +102,48 @@ class Scanner extends BasicEmitter {
}
}
$newData = $data;
- if ($reuseExisting and $cacheData = $this->cache->get($file)) {
- // 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'];
+ $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;
}
- if ($reuseExisting & self::REUSE_ETAG) {
- $data['etag'] = $cacheData['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'] = $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);
}
- // 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;
}
@@ -159,20 +191,22 @@ class Scanner extends BasicEmitter {
$newChildren = array();
if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) {
\OC_DB::beginTransaction();
- 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;
+ 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'];
}
- } else if ($size !== -1) {
- $size += $data['size'];
}
}
}
diff --git a/lib/files/node/file.php b/lib/files/node/file.php
new file mode 100644
index 00000000000..75d5e0166b6
--- /dev/null
+++ b/lib/files/node/file.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * 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
new file mode 100644
index 00000000000..923f53821b2
--- /dev/null
+++ b/lib/files/node/folder.php
@@ -0,0 +1,382 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * 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
new file mode 100644
index 00000000000..063e2424a64
--- /dev/null
+++ b/lib/files/node/node.php
@@ -0,0 +1,245 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * 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
new file mode 100644
index 00000000000..d45076f7fee
--- /dev/null
+++ b/lib/files/node/nonexistingfile.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * 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
new file mode 100644
index 00000000000..0346cbf1e21
--- /dev/null
+++ b/lib/files/node/nonexistingfolder.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * 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
new file mode 100644
index 00000000000..e3d58476e9c
--- /dev/null
+++ b/lib/files/node/root.php
@@ -0,0 +1,337 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * 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
index 01560f34fde..a5b79f0e967 100644
--- a/lib/files/storage/common.php
+++ b/lib/files/storage/common.php
@@ -142,13 +142,15 @@ abstract class Common implements \OC\Files\Storage\Storage {
return false;
} else {
$directoryHandle = $this->opendir($directory);
- 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(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);
+ }
}
}
}
@@ -224,7 +226,8 @@ abstract class Common implements \OC\Files\Storage\Storage {
}
private function addLocalFolder($path, $target) {
- if ($dh = $this->opendir($path)) {
+ $dh = $this->opendir($path);
+ if(is_resource($dh)) {
while (($file = readdir($dh)) !== false) {
if ($file !== '.' and $file !== '..') {
if ($this->is_dir($path . '/' . $file)) {
@@ -242,7 +245,7 @@ abstract class Common implements \OC\Files\Storage\Storage {
protected function searchInDir($query, $dir = '') {
$files = array();
$dh = $this->opendir($dir);
- if ($dh) {
+ if (is_resource($dh)) {
while (($item = readdir($dh)) !== false) {
if ($item == '.' || $item == '..') continue;
if (strstr(strtolower($item), strtolower($query)) !== false) {
diff --git a/lib/files/storage/mappedlocal.php b/lib/files/storage/mappedlocal.php
index fbf1b4ebf96..ba5ac4191c5 100644
--- a/lib/files/storage/mappedlocal.php
+++ b/lib/files/storage/mappedlocal.php
@@ -65,16 +65,18 @@ class MappedLocal extends \OC\Files\Storage\Common{
$logicalPath = $this->mapper->physicalToLogic($physicalPath);
$dh = opendir($physicalPath);
- while (($file = readdir($dh)) !== false) {
- if ($file === '.' or $file === '..') {
- continue;
- }
+ if(is_resource($dh)) {
+ while (($file = readdir($dh)) !== false) {
+ if ($file === '.' or $file === '..') {
+ continue;
+ }
- $logicalFilePath = $this->mapper->physicalToLogic($physicalPath.'/'.$file);
+ $logicalFilePath = $this->mapper->physicalToLogic($physicalPath.'/'.$file);
- $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath);
- $file = $this->stripLeading($file);
- $files[]= $file;
+ $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath);
+ $file = $this->stripLeading($file);
+ $files[]= $file;
+ }
}
\OC\Files\Stream\Dir::register('local-win32'.$path, $files);
diff --git a/lib/files/storage/storage.php b/lib/files/storage/storage.php
index c96caebf4af..b673bb9a32d 100644
--- a/lib/files/storage/storage.php
+++ b/lib/files/storage/storage.php
@@ -13,7 +13,7 @@ namespace OC\Files\Storage;
*
* All paths passed to the storage are relative to the storage and should NOT have a leading slash.
*/
-interface Storage {
+interface Storage extends \OCP\Files\Storage {
/**
* $parameters is a free form array with the configuration options needed to construct the storage
*
diff --git a/lib/files/utils/scanner.php b/lib/files/utils/scanner.php
index f0dc41ffad3..2cad7dd77bd 100644
--- a/lib/files/utils/scanner.php
+++ b/lib/files/utils/scanner.php
@@ -72,6 +72,9 @@ class Scanner extends PublicEmitter {
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();
@@ -81,6 +84,9 @@ class Scanner extends PublicEmitter {
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
index bb737f19ef8..aa08a5f7cc9 100644
--- a/lib/files/view.php
+++ b/lib/files/view.php
@@ -30,7 +30,7 @@ class View {
private $internal_path_cache = array();
private $storage_cache = array();
- public function __construct($root) {
+ public function __construct($root = '') {
$this->fakeRoot = $root;
}
@@ -249,6 +249,7 @@ class View {
$hooks = array('touch');
if (!$this->file_exists($path)) {
+ $hooks[] = 'create';
$hooks[] = 'write';
}
$result = $this->basicOperation('touch', $path, $hooks, $mtime);
@@ -267,18 +268,18 @@ class View {
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
if (\OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data)
and Filesystem::isValidPath($path)
- and !Filesystem::isFileBlacklisted($path)
+ and !Filesystem::isFileBlacklisted($path)
) {
$path = $this->getRelativePath($absolutePath);
$exists = $this->file_exists($path);
$run = true;
- if ($this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path)) {
+ if ($this->shouldEmitHooks($path)) {
if (!$exists) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_create,
array(
- Filesystem::signal_param_path => $path,
+ Filesystem::signal_param_path => $this->getHookPath($path),
Filesystem::signal_param_run => &$run
)
);
@@ -287,7 +288,7 @@ class View {
Filesystem::CLASSNAME,
Filesystem::signal_write,
array(
- Filesystem::signal_param_path => $path,
+ Filesystem::signal_param_path => $this->getHookPath($path),
Filesystem::signal_param_run => &$run
)
);
@@ -300,18 +301,18 @@ class View {
list ($count, $result) = \OC_Helper::streamCopy($data, $target);
fclose($target);
fclose($data);
- if ($this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path) && $result !== false) {
+ if ($this->shouldEmitHooks($path) && $result !== false) {
if (!$exists) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_create,
- array(Filesystem::signal_param_path => $path)
+ array(Filesystem::signal_param_path => $this->getHookPath($path))
);
}
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_write,
- array(Filesystem::signal_param_path => $path)
+ array(Filesystem::signal_param_path => $this->getHookPath($path))
);
}
\OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count);
@@ -332,7 +333,7 @@ class View {
}
public function deleteAll($directory, $empty = false) {
- return $this->basicOperation('deleteAll', $directory, array('delete'), $empty);
+ return $this->rmdir($directory);
}
public function rename($path1, $path2) {
@@ -353,21 +354,21 @@ class View {
return false;
}
$run = true;
- if ($this->fakeRoot == Filesystem::getRoot() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
+ 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 => $path2,
+ Filesystem::signal_param_path => $this->getHookPath($path2),
Filesystem::signal_param_run => &$run
)
);
- } elseif ($this->fakeRoot == Filesystem::getRoot()) {
+ } elseif ($this->shouldEmitHooks()) {
\OC_Hook::emit(
Filesystem::CLASSNAME, Filesystem::signal_rename,
array(
- Filesystem::signal_param_oldpath => $path1,
- Filesystem::signal_param_newpath => $path2,
+ Filesystem::signal_param_oldpath => $this->getHookPath($path1),
+ Filesystem::signal_param_newpath => $this->getHookPath($path2),
Filesystem::signal_param_run => &$run
)
);
@@ -407,22 +408,22 @@ class View {
}
}
}
- if ($this->fakeRoot == Filesystem::getRoot() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
+ 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 => $path2,
+ Filesystem::signal_param_path => $this->getHookPath($path2),
)
);
- } elseif ($this->fakeRoot == Filesystem::getRoot() && $result !== false) {
+ } elseif ($this->shouldEmitHooks() && $result !== false) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_rename,
array(
- Filesystem::signal_param_oldpath => $path1,
- Filesystem::signal_param_newpath => $path2
+ Filesystem::signal_param_oldpath => $this->getHookPath($path1),
+ Filesystem::signal_param_newpath => $this->getHookPath($path2)
)
);
}
@@ -454,13 +455,13 @@ class View {
}
$run = true;
$exists = $this->file_exists($path2);
- if ($this->fakeRoot == Filesystem::getRoot()) {
+ if ($this->shouldEmitHooks()) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_copy,
array(
- Filesystem::signal_param_oldpath => $path1,
- Filesystem::signal_param_newpath => $path2,
+ Filesystem::signal_param_oldpath => $this->getHookPath($path1),
+ Filesystem::signal_param_newpath => $this->getHookPath($path2),
Filesystem::signal_param_run => &$run
)
);
@@ -469,7 +470,7 @@ class View {
Filesystem::CLASSNAME,
Filesystem::signal_create,
array(
- Filesystem::signal_param_path => $path2,
+ Filesystem::signal_param_path => $this->getHookPath($path2),
Filesystem::signal_param_run => &$run
)
);
@@ -479,7 +480,7 @@ class View {
Filesystem::CLASSNAME,
Filesystem::signal_write,
array(
- Filesystem::signal_param_path => $path2,
+ Filesystem::signal_param_path => $this->getHookPath($path2),
Filesystem::signal_param_run => &$run
)
);
@@ -499,9 +500,11 @@ class View {
} else {
if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) {
$result = $this->mkdir($path2);
- while (($file = readdir($dh)) !== false) {
- if (!Filesystem::isIgnoredDir($file)) {
- $result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file);
+ if (is_resource($dh)) {
+ while (($file = readdir($dh)) !== false) {
+ if (!Filesystem::isIgnoredDir($file)) {
+ $result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file);
+ }
}
}
} else {
@@ -510,26 +513,26 @@ class View {
list($count, $result) = \OC_Helper::streamCopy($source, $target);
}
}
- if ($this->fakeRoot == Filesystem::getRoot() && $result !== false) {
+ if ($this->shouldEmitHooks() && $result !== false) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_copy,
array(
- Filesystem::signal_param_oldpath => $path1,
- Filesystem::signal_param_newpath => $path2
+ 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 => $path2)
+ array(Filesystem::signal_param_path => $this->getHookPath($path2))
);
}
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_write,
- array(Filesystem::signal_param_path => $path2)
+ array(Filesystem::signal_param_path => $this->getHookPath($path2))
);
}
return $result;
@@ -620,11 +623,11 @@ class View {
if ($path == null) {
return false;
}
- if (Filesystem::$loaded && $this->fakeRoot == Filesystem::getRoot()) {
+ if ($this->shouldEmitHooks($path)) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_read,
- array(Filesystem::signal_param_path => $path)
+ array(Filesystem::signal_param_path => $this->getHookPath($path))
);
}
list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
@@ -658,7 +661,7 @@ class View {
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam)
and Filesystem::isValidPath($path)
- and !Filesystem::isFileBlacklisted($path)
+ and !Filesystem::isFileBlacklisted($path)
) {
$path = $this->getRelativePath($absolutePath);
if ($path == null) {
@@ -674,7 +677,7 @@ class View {
$result = $storage->$operation($internalPath);
}
$result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result);
- if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot() && $result !== false) {
+ 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);
}
@@ -685,10 +688,35 @@ class View {
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 (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path)) {
+ if ($this->shouldEmitHooks($path)) {
foreach ($hooks as $hook) {
if ($hook != 'read') {
\OC_Hook::emit(
@@ -947,7 +975,7 @@ class View {
/**
* search for files by mimetype
*
- * @param string $query
+ * @param string $mimetype
* @return array
*/
public function searchByMime($mimetype) {
@@ -970,7 +998,7 @@ class View {
$results = $cache->$method($query);
foreach ($results as $result) {
- if (substr($mountPoint . $result['path'], 0, $rootLength) === $this->fakeRoot) {
+ if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
$result['path'] = substr($mountPoint . $result['path'], $rootLength);
$files[] = $result;
}
@@ -984,9 +1012,11 @@ class View {
$relativeMountPoint = substr($mountPoint, $rootLength);
$results = $cache->$method($query);
- foreach ($results as $result) {
- $result['path'] = $relativeMountPoint . $result['path'];
- $files[] = $result;
+ if ($results) {
+ foreach ($results as $result) {
+ $result['path'] = $relativeMountPoint . $result['path'];
+ $files[] = $result;
+ }
}
}
}
diff --git a/lib/helper.php b/lib/helper.php
index dd2476eda5c..66e7acb407a 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -185,7 +185,38 @@ class OC_Helper {
* Returns the path to the image of this file type.
*/
public static function mimetypeIcon($mimetype) {
- $alias = array('application/xml' => 'code/xml');
+ $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];
}
@@ -201,6 +232,14 @@ class OC_Helper {
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')) {
@@ -220,6 +259,21 @@ class OC_Helper {
}
/**
+ * @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
@@ -228,7 +282,6 @@ class OC_Helper {
*/
public static function humanFileSize($bytes) {
if ($bytes < 0) {
- $l = OC_L10N::get('lib');
return "?";
}
if ($bytes < 1024) {
@@ -242,10 +295,17 @@ class OC_Helper {
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";
+ }
- // Wow, heavy duty for owncloud
$bytes = round($bytes / 1024, 1);
- return "$bytes GB";
+ return "$bytes PB";
}
/**
@@ -295,17 +355,19 @@ class OC_Helper {
if (!is_dir($path))
return chmod($path, $filemode);
$dh = opendir($path);
- 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;
+ 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);
}
- closedir($dh);
if (@chmod($path, $filemode))
return true;
else
@@ -603,9 +665,11 @@ class OC_Helper {
// if oc-noclean is empty delete it
$isTmpDirNoCleanEmpty = true;
$tmpDirNoClean = opendir($tmpDirNoCleanName);
- while (false !== ($file = readdir($tmpDirNoClean))) {
- if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
- $isTmpDirNoCleanEmpty = false;
+ if(is_resource($tmpDirNoClean)) {
+ while (false !== ($file = readdir($tmpDirNoClean))) {
+ if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
+ $isTmpDirNoCleanEmpty = false;
+ }
}
}
if ($isTmpDirNoCleanEmpty) {
@@ -648,7 +712,7 @@ class OC_Helper {
$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)"
+ //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];
@@ -659,7 +723,7 @@ class OC_Helper {
}
do {
if ($offset) {
- //Replace the last "(number)" with "(number+1)"
+ //Replace the last "(number)" with "(number+1)"
$newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length);
} else {
$newname = $name . ' (' . $counter . ')';
@@ -858,10 +922,8 @@ class OC_Helper {
} else {
$total = $free; //either unknown or unlimited
}
- if ($total == 0) {
- $total = 1; // prevent division by zero
- }
- if ($total >= 0) {
+ if ($total > 0) {
+ // prevent division by zero or error codes (negative values)
$relative = round(($used / $total) * 10000) / 100;
} else {
$relative = 0;
diff --git a/lib/image.php b/lib/image.php
index 4bc38e20e56..7761a3c7737 100644
--- a/lib/image.php
+++ b/lib/image.php
@@ -25,24 +25,27 @@
*/
class OC_Image {
protected $resource = false; // tmp resource.
- protected $imagetype = IMAGETYPE_PNG; // Default to png if file type isn't evident.
- protected $bit_depth = 24;
- protected $filepath = null;
+ 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) {
+ 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);
+ if (filesize($filePath) > 11) {
+ $imageType = exif_imagetype($filePath);
}
else {
- $imagetype = false;
+ $imageType = false;
}
- return $imagetype ? image_type_to_mime_type($imagetype) : '';
+ return $imageType ? image_type_to_mime_type($imageType) : '';
}
/**
@@ -50,14 +53,19 @@ class OC_Image {
* @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) {
+ 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(!is_null($imageref)) {
- $this->load($imageref);
+
+ if (\OC_Util::fileInfoLoaded()) {
+ $this->fileInfo = new finfo(FILEINFO_MIME_TYPE);
+ }
+
+ if(!is_null($imageRef)) {
+ $this->load($imageRef);
}
}
@@ -74,7 +82,7 @@ class OC_Image {
* @returns int
*/
public function mimeType() {
- return $this->valid() ? image_type_to_mime_type($this->imagetype) : '';
+ return $this->valid() ? $this->mimeType : '';
}
/**
@@ -157,30 +165,30 @@ class OC_Image {
* @returns bool
*/
- public function save($filepath=null) {
- if($filepath === null && $this->filepath === null) {
+ 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;
+ } elseif($filePath === null && $this->filePath !== null) {
+ $filePath = $this->filePath;
}
- return $this->_output($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))) {
+ 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.',
+ __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);
+ } 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;
}
}
@@ -188,30 +196,30 @@ class OC_Image {
return false;
}
- $retval = false;
- switch($this->imagetype) {
+ $retVal = false;
+ switch($this->imageType) {
case IMAGETYPE_GIF:
- $retval = imagegif($this->resource, $filepath);
+ $retVal = imagegif($this->resource, $filePath);
break;
case IMAGETYPE_JPEG:
- $retval = imagejpeg($this->resource, $filepath);
+ $retVal = imagejpeg($this->resource, $filePath);
break;
case IMAGETYPE_PNG:
- $retval = imagepng($this->resource, $filepath);
+ $retVal = imagepng($this->resource, $filePath);
break;
case IMAGETYPE_XBM:
- $retval = imagexbm($this->resource, $filepath);
+ $retVal = imagexbm($this->resource, $filePath);
break;
case IMAGETYPE_WBMP:
- $retval = imagewbmp($this->resource, $filepath);
+ $retVal = imagewbmp($this->resource, $filePath);
break;
case IMAGETYPE_BMP:
- $retval = imagebmp($this->resource, $filepath, $this->bit_depth);
+ $retVal = imagebmp($this->resource, $filePath, $this->bitDepth);
break;
default:
- $retval = imagepng($this->resource, $filepath);
+ $retVal = imagepng($this->resource, $filePath);
}
- return $retval;
+ return $retVal;
}
/**
@@ -233,7 +241,21 @@ class OC_Image {
*/
function data() {
ob_start();
- $res = imagepng($this->resource);
+ 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);
}
@@ -261,11 +283,11 @@ class OC_Image {
OC_Log::write('core', 'OC_Image->fixOrientation() No image loaded.', OC_Log::DEBUG);
return -1;
}
- if(is_null($this->filepath) || !is_readable($this->filepath)) {
+ 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');
+ $exif = @exif_read_data($this->filePath, 'IFD0');
if(!$exif) {
return -1;
}
@@ -351,19 +373,19 @@ class OC_Image {
* @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;
+ 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(in_array(get_resource_type($imageRef), array('file', 'stream'))) {
+ return $this->loadFromFileHandle($imageRef);
}
- } elseif($this->loadFromFile($imageref) !== false) {
+ } elseif($this->loadFromFile($imageRef) !== false) {
return $this->resource;
- } elseif($this->loadFromBase64($imageref) !== false) {
+ } elseif($this->loadFromBase64($imageRef) !== false) {
return $this->resource;
- } elseif($this->loadFromData($imageref) !== false) {
+ } elseif($this->loadFromData($imageRef) !== false) {
return $this->resource;
} else {
OC_Log::write('core', __METHOD__.'(): couldn\'t load anything. Giving up!', OC_Log::DEBUG);
@@ -390,62 +412,62 @@ class OC_Image {
* @param $imageref The path to a local file.
* @returns An image resource or false on error
*/
- public function loadFromFile($imagepath=false) {
+ 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)) {
+ 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);
+ OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: '.$imagePath, OC_Log::DEBUG);
return false;
}
- $itype = exif_imagetype($imagepath);
- switch($itype) {
+ $iType = exif_imagetype($imagePath);
+ switch ($iType) {
case IMAGETYPE_GIF:
if (imagetypes() & IMG_GIF) {
- $this->resource = imagecreatefromgif($imagepath);
+ $this->resource = imagecreatefromgif($imagePath);
} else {
OC_Log::write('core',
- 'OC_Image->loadFromFile, GIF images not supported: '.$imagepath,
+ 'OC_Image->loadFromFile, GIF images not supported: '.$imagePath,
OC_Log::DEBUG);
}
break;
case IMAGETYPE_JPEG:
if (imagetypes() & IMG_JPG) {
- $this->resource = imagecreatefromjpeg($imagepath);
+ $this->resource = imagecreatefromjpeg($imagePath);
} else {
OC_Log::write('core',
- 'OC_Image->loadFromFile, JPG images not supported: '.$imagepath,
+ 'OC_Image->loadFromFile, JPG images not supported: '.$imagePath,
OC_Log::DEBUG);
}
break;
case IMAGETYPE_PNG:
if (imagetypes() & IMG_PNG) {
- $this->resource = imagecreatefrompng($imagepath);
+ $this->resource = imagecreatefrompng($imagePath);
} else {
OC_Log::write('core',
- 'OC_Image->loadFromFile, PNG images not supported: '.$imagepath,
+ 'OC_Image->loadFromFile, PNG images not supported: '.$imagePath,
OC_Log::DEBUG);
}
break;
case IMAGETYPE_XBM:
if (imagetypes() & IMG_XPM) {
- $this->resource = imagecreatefromxbm($imagepath);
+ $this->resource = imagecreatefromxbm($imagePath);
} else {
OC_Log::write('core',
- 'OC_Image->loadFromFile, XBM/XPM images not supported: '.$imagepath,
+ 'OC_Image->loadFromFile, XBM/XPM images not supported: '.$imagePath,
OC_Log::DEBUG);
}
break;
case IMAGETYPE_WBMP:
if (imagetypes() & IMG_WBMP) {
- $this->resource = imagecreatefromwbmp($imagepath);
+ $this->resource = imagecreatefromwbmp($imagePath);
} else {
OC_Log::write('core',
- 'OC_Image->loadFromFile, WBMP images not supported: '.$imagepath,
+ 'OC_Image->loadFromFile, WBMP images not supported: '.$imagePath,
OC_Log::DEBUG);
}
break;
case IMAGETYPE_BMP:
- $this->resource = $this->imagecreatefrombmp($imagepath);
+ $this->resource = $this->imagecreatefrombmp($imagePath);
break;
/*
case IMAGETYPE_TIFF_II: // (intel byte order)
@@ -474,14 +496,15 @@ class OC_Image {
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;
+ $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->filepath = $imagepath;
+ $this->imageType = $iType;
+ $this->mimeType = image_type_to_mime_type($iType);
+ $this->filePath = $imagePath;
}
return $this->resource;
}
@@ -496,6 +519,14 @@ class OC_Image {
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;
@@ -515,6 +546,9 @@ class OC_Image {
$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;
@@ -534,16 +568,16 @@ class OC_Image {
* </p>
* @return resource an image resource identifier on success, <b>FALSE</b> on errors.
*/
- private function imagecreatefrombmp($filename) {
- if (!($fh = fopen($filename, 'rb'))) {
- trigger_error('imagecreatefrombmp: Can not open ' . $filename, E_USER_WARNING);
+ 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);
+ trigger_error('imagecreatefrombmp: ' . $fileName . ' is not a bitmap!', E_USER_WARNING);
return false;
}
// read image header
@@ -554,7 +588,7 @@ class OC_Image {
}
// set bytes and padding
$meta['bytes'] = $meta['bits'] / 8;
- $this->bit_depth = $meta['bits']; //remember the bit depth for the imagebmp call
+ $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;
@@ -590,7 +624,7 @@ class OC_Image {
$p = 0;
$vide = chr(0);
$y = $meta['height'] - 1;
- $error = 'imagecreatefrombmp: ' . $filename . ' has not enough data!';
+ $error = 'imagecreatefrombmp: ' . $fileName . ' has not enough data!';
// loop through the image data beginning with the lower left corner
while ($y >= 0) {
$x = 0;
@@ -653,7 +687,7 @@ class OC_Image {
break;
default:
trigger_error('imagecreatefrombmp: '
- . $filename . ' has ' . $meta['bits'] . ' bits and this is not supported!',
+ . $fileName . ' has ' . $meta['bits'] . ' bits and this is not supported!',
E_USER_WARNING);
return false;
}
@@ -673,24 +707,24 @@ class OC_Image {
* @param $maxsize The maximum size of either the width or height.
* @returns bool
*/
- public function resize($maxsize) {
+ public function resize($maxSize) {
if(!$this->valid()) {
OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR);
return false;
}
- $width_orig=imageSX($this->resource);
- $height_orig=imageSY($this->resource);
- $ratio_orig = $width_orig/$height_orig;
+ $widthOrig=imageSX($this->resource);
+ $heightOrig=imageSY($this->resource);
+ $ratioOrig = $widthOrig/$heightOrig;
- if ($ratio_orig > 1) {
- $new_height = round($maxsize/$ratio_orig);
- $new_width = $maxsize;
+ if ($ratioOrig > 1) {
+ $newHeight = round($maxSize/$ratioOrig);
+ $newWidth = $maxSize;
} else {
- $new_width = round($maxsize*$ratio_orig);
- $new_height = $maxsize;
+ $newWidth = round($maxSize*$ratioOrig);
+ $newHeight = $maxSize;
}
- $this->preciseResize(round($new_width), round($new_height));
+ $this->preciseResize(round($newWidth), round($newHeight));
return true;
}
@@ -699,8 +733,8 @@ class OC_Image {
OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR);
return false;
}
- $width_orig=imageSX($this->resource);
- $height_orig=imageSY($this->resource);
+ $widthOrig=imageSX($this->resource);
+ $heightOrig=imageSY($this->resource);
$process = imagecreatetruecolor($width, $height);
if ($process == false) {
@@ -710,13 +744,13 @@ class OC_Image {
}
// preserve transparency
- if($this->imagetype == IMAGETYPE_GIF or $this->imagetype == IMAGETYPE_PNG) {
+ 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, $width_orig, $height_orig);
+ 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);
@@ -737,19 +771,19 @@ class OC_Image {
OC_Log::write('core', 'OC_Image->centerCrop, No image loaded', OC_Log::ERROR);
return false;
}
- $width_orig=imageSX($this->resource);
- $height_orig=imageSY($this->resource);
- if($width_orig === $height_orig and $size==0) {
+ $widthOrig=imageSX($this->resource);
+ $heightOrig=imageSY($this->resource);
+ if($widthOrig === $heightOrig and $size==0) {
return true;
}
- $ratio_orig = $width_orig/$height_orig;
- $width = $height = min($width_orig, $height_orig);
+ $ratioOrig = $widthOrig/$heightOrig;
+ $width = $height = min($widthOrig, $heightOrig);
- if ($ratio_orig > 1) {
- $x = ($width_orig/2) - ($width/2);
+ if ($ratioOrig > 1) {
+ $x = ($widthOrig/2) - ($width/2);
$y = 0;
} else {
- $y = ($height_orig/2) - ($height/2);
+ $y = ($heightOrig/2) - ($height/2);
$x = 0;
}
if($size>0) {
@@ -767,7 +801,7 @@ class OC_Image {
}
// preserve transparency
- if($this->imagetype == IMAGETYPE_GIF or $this->imagetype == IMAGETYPE_PNG) {
+ if($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
imagealphablending($process, false);
imagesavealpha($process, true);
@@ -827,9 +861,9 @@ class OC_Image {
OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR);
return false;
}
- $width_orig=imageSX($this->resource);
- $height_orig=imageSY($this->resource);
- $ratio = $width_orig/$height_orig;
+ $widthOrig=imageSX($this->resource);
+ $heightOrig=imageSY($this->resource);
+ $ratio = $widthOrig/$heightOrig;
$newWidth = min($maxWidth, $ratio*$maxHeight);
$newHeight = min($maxHeight, $maxWidth/$ratio);
@@ -863,7 +897,7 @@ if ( ! function_exists( 'imagebmp') ) {
* @param int $compression [optional]
* @return bool <b>TRUE</b> on success or <b>FALSE</b> on failure.
*/
- function imagebmp($im, $filename='', $bit=24, $compression=0) {
+ function imagebmp($im, $fileName='', $bit=24, $compression=0) {
if (!in_array($bit, array(1, 4, 8, 16, 24, 32))) {
$bit = 24;
}
@@ -874,14 +908,14 @@ if ( ! function_exists( 'imagebmp') ) {
imagetruecolortopalette($im, true, $bits);
$width = imagesx($im);
$height = imagesy($im);
- $colors_num = imagecolorstotal($im);
- $rgb_quad = '';
+ $colorsNum = imagecolorstotal($im);
+ $rgbQuad = '';
if ($bit <= 8) {
- for ($i = 0; $i < $colors_num; $i++) {
+ for ($i = 0; $i < $colorsNum; $i++) {
$colors = imagecolorsforindex($im, $i);
- $rgb_quad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
+ $rgbQuad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
}
- $bmp_data = '';
+ $bmpData = '';
if ($compression == 0 || $bit < 8) {
$compression = 0;
$extra = '';
@@ -899,35 +933,35 @@ if ( ! function_exists( 'imagebmp') ) {
$bin |= $index << $k;
$i++;
}
- $bmp_data .= chr($bin);
+ $bmpData .= chr($bin);
}
- $bmp_data .= $extra;
+ $bmpData .= $extra;
}
}
// RLE8
else if ($compression == 1 && $bit == 8) {
for ($j = $height - 1; $j >= 0; $j--) {
- $last_index = "\0";
- $same_num = 0;
+ $lastIndex = "\0";
+ $sameNum = 0;
for ($i = 0; $i <= $width; $i++) {
$index = imagecolorat($im, $i, $j);
- if ($index !== $last_index || $same_num > 255) {
- if ($same_num != 0) {
- $bmp_data .= chr($same_num) . chr($last_index);
+ if ($index !== $lastIndex || $sameNum > 255) {
+ if ($sameNum != 0) {
+ $bmpData .= chr($same_num) . chr($lastIndex);
}
- $last_index = $index;
- $same_num = 1;
+ $lastIndex = $index;
+ $sameNum = 1;
}
else {
- $same_num++;
+ $sameNum++;
}
}
- $bmp_data .= "\0\0";
+ $bmpData .= "\0\0";
}
- $bmp_data .= "\0\1";
+ $bmpData .= "\0\1";
}
- $size_quad = strlen($rgb_quad);
- $size_data = strlen($bmp_data);
+ $sizeQuad = strlen($rgbQuad);
+ $sizeData = strlen($bmpData);
}
else {
$extra = '';
@@ -935,7 +969,7 @@ if ( ! function_exists( 'imagebmp') ) {
if ($padding % 4 != 0) {
$extra = str_repeat("\0", $padding);
}
- $bmp_data = '';
+ $bmpData = '';
for ($j = $height - 1; $j >= 0; $j--) {
for ($i = 0; $i < $width; $i++) {
$index = imagecolorat($im, $i, $j);
@@ -945,27 +979,27 @@ if ( ! function_exists( 'imagebmp') ) {
$bin |= ($colors['red'] >> 3) << 10;
$bin |= ($colors['green'] >> 3) << 5;
$bin |= $colors['blue'] >> 3;
- $bmp_data .= pack("v", $bin);
+ $bmpData .= pack("v", $bin);
}
else {
- $bmp_data .= pack("c*", $colors['blue'], $colors['green'], $colors['red']);
+ $bmpData .= pack("c*", $colors['blue'], $colors['green'], $colors['red']);
}
}
- $bmp_data .= $extra;
+ $bmpData .= $extra;
}
- $size_quad = 0;
- $size_data = strlen($bmp_data);
- $colors_num = 0;
- }
- $file_header = 'BM' . pack('V3', 54 + $size_quad + $size_data, 0, 54 + $size_quad);
- $info_header = pack('V3v2V*', 0x28, $width, $height, 1, $bit, $compression, $size_data, 0, 0, $colors_num, 0);
- if ($filename != '') {
- $fp = fopen($filename, 'wb');
- fwrite($fp, $file_header . $info_header . $rgb_quad . $bmp_data);
+ $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 $file_header . $info_header. $rgb_quad . $bmp_data;
+ echo $fileHeader . $infoHeader. $rgbQuad . $bmpData;
return true;
}
}
@@ -977,8 +1011,8 @@ if ( ! function_exists( 'exif_imagetype' ) ) {
* @param string $filename
* @return string|boolean
*/
- function exif_imagetype ( $filename ) {
- if ( ( $info = getimagesize( $filename ) ) !== false ) {
+ function exif_imagetype ( $fileName ) {
+ if ( ( $info = getimagesize( $fileName ) ) !== false ) {
return $info[2];
}
return false;
diff --git a/lib/installer.php b/lib/installer.php
index b9684eaeea0..e082c7eeee9 100644
--- a/lib/installer.php
+++ b/lib/installer.php
@@ -107,10 +107,12 @@ class OC_Installer{
if(!is_file($extractDir.'/appinfo/info.xml')) {
//try to find it in a subdir
$dh=opendir($extractDir);
- 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_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;
+ }
}
}
}
@@ -426,6 +428,7 @@ class OC_Installer{
'OC_API::',
'OC_App::',
'OC_AppConfig::',
+ 'OC_Avatar',
'OC_BackgroundJob::',
'OC_Config::',
'OC_DB::',
diff --git a/lib/l10n/ach.php b/lib/l10n/ach.php
new file mode 100644
index 00000000000..406ff5f5a26
--- /dev/null
+++ b/lib/l10n/ach.php
@@ -0,0 +1,8 @@
+<?php
+$TRANSLATIONS = array(
+"_%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/ca.php b/lib/l10n/ca.php
index 166455e652c..a8769224705 100644
--- a/lib/l10n/ca.php
+++ b/lib/l10n/ca.php
@@ -8,6 +8,9 @@ $TRANSLATIONS = array(
"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.",
diff --git a/lib/l10n/cs_CZ.php b/lib/l10n/cs_CZ.php
index 1a80fc78bb6..ed31ae79529 100644
--- a/lib/l10n/cs_CZ.php
+++ b/lib/l10n/cs_CZ.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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.",
@@ -13,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Aplikace nemůže být nainstalována, protože obsahuje značku\n<shipped>\n\ntrue\n</shipped>\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.",
diff --git a/lib/l10n/da.php b/lib/l10n/da.php
index 78859b08745..05a43f42ed9 100644
--- a/lib/l10n/da.php
+++ b/lib/l10n/da.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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.",
@@ -13,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Appen kan ikke installeres, da den indeholder taget\n<shipped>\n\ntrue\n</shipped>\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.",
diff --git a/lib/l10n/de.php b/lib/l10n/de.php
index 8670e1175c6..87e7a67b47b 100644
--- a/lib/l10n/de.php
+++ b/lib/l10n/de.php
@@ -1,13 +1,16 @@
<?php
$TRANSLATIONS = array(
"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "Applikation \"%s\" kann nicht installiert werden, da sie mit dieser ownCloud Version nicht kompatibel ist.",
-"No app name specified" => "Es wurde kein App-Name angegeben",
+"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.",
@@ -16,12 +19,15 @@ $TRANSLATIONS = array(
"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" => "href wurde nicht angegeben um die Applikation per http zu installieren",
+"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 Archive konnte bei der Installation der Applikation nicht geöffnet werden",
+"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Die Applikation konnte nicht installiert werden, da diese das <shipped>true</shipped> 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",
diff --git a/lib/l10n/de_DE.php b/lib/l10n/de_DE.php
index eafd76b7ee9..09be0eea22d 100644
--- a/lib/l10n/de_DE.php
+++ b/lib/l10n/de_DE.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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.",
@@ -13,8 +18,16 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Die Applikation konnte nicht installiert werden, da diese das <shipped>true</shipped> 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",
diff --git a/lib/l10n/en_GB.php b/lib/l10n/en_GB.php
new file mode 100644
index 00000000000..d02f553eda8
--- /dev/null
+++ b/lib/l10n/en_GB.php
@@ -0,0 +1,72 @@
+<?php
+$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "App can't be installed because it contains the <shipped>true</shipped> 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 <a href='%s'>installation guides</a>." => "Please double check the <a href='%s'>installation guides</a>.",
+"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/es.php b/lib/l10n/es.php
index 14bbf6f6a13..047d5d955bb 100644
--- a/lib/l10n/es.php
+++ b/lib/l10n/es.php
@@ -1,5 +1,7 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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",
@@ -13,6 +15,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "La aplicación no se puede instalar porque contiene la etiqueta\n<shipped>\ntrue\n</shipped>\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.",
@@ -21,7 +35,7 @@ $TRANSLATIONS = array(
"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 no se puede utilizar puntos en 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",
@@ -40,13 +54,13 @@ $TRANSLATIONS = array(
"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 <a href='%s'>installation guides</a>." => "Por favor, vuelva a comprobar las <a href='%s'>guías de instalación</a>.",
"seconds ago" => "hace segundos",
-"_%n minute ago_::_%n minutes ago_" => array("",""),
-"_%n hour ago_::_%n hours ago_" => array("",""),
+"_%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("",""),
+"_%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("",""),
+"_%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:",
diff --git a/lib/l10n/es_AR.php b/lib/l10n/es_AR.php
index 26f1e4ecd5e..f637eb403ed 100644
--- a/lib/l10n/es_AR.php
+++ b/lib/l10n/es_AR.php
@@ -1,5 +1,7 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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",
@@ -13,6 +15,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "La app no se puede instalar porque contiene la etiqueta <shipped>true</shipped> 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.",
@@ -40,13 +54,13 @@ $TRANSLATIONS = array(
"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 <a href='%s'>installation guides</a>." => "Por favor, comprobá nuevamente la <a href='%s'>guía de instalación</a>.",
"seconds ago" => "segundos atrás",
-"_%n minute ago_::_%n minutes ago_" => array("",""),
-"_%n hour ago_::_%n hours ago_" => array("",""),
+"_%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("",""),
+"_%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("",""),
+"_%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:",
diff --git a/lib/l10n/es_MX.php b/lib/l10n/es_MX.php
new file mode 100644
index 00000000000..15f78e0bce6
--- /dev/null
+++ b/lib/l10n/es_MX.php
@@ -0,0 +1,8 @@
+<?php
+$TRANSLATIONS = array(
+"_%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/et_EE.php b/lib/l10n/et_EE.php
index 8e3aa55c4ed..85dfaeb52d5 100644
--- a/lib/l10n/et_EE.php
+++ b/lib/l10n/et_EE.php
@@ -8,6 +8,9 @@ $TRANSLATIONS = array(
"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.",
diff --git a/lib/l10n/fi_FI.php b/lib/l10n/fi_FI.php
index 2e69df43ad2..1d2bdab749c 100644
--- a/lib/l10n/fi_FI.php
+++ b/lib/l10n/fi_FI.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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.",
@@ -15,6 +20,8 @@ $TRANSLATIONS = array(
"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",
diff --git a/lib/l10n/fr.php b/lib/l10n/fr.php
index cfcca28d5f8..ab3d618849e 100644
--- a/lib/l10n/fr.php
+++ b/lib/l10n/fr.php
@@ -1,15 +1,35 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "L'application ne peut être installée car elle contient la balise <shipped>true</shipped> 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.",
@@ -37,15 +57,16 @@ $TRANSLATIONS = array(
"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 <a href='%s'>installation guides</a>." => "Veuillez vous référer au <a href='%s'>guide d'installation</a>.",
"seconds ago" => "il y a quelques secondes",
-"_%n minute ago_::_%n minutes ago_" => array("",""),
-"_%n hour ago_::_%n hours ago_" => array("",""),
+"_%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("",""),
+"_%n day go_::_%n days ago_" => array("","il y a %n jours"),
"last month" => "le mois dernier",
-"_%n month ago_::_%n months ago_" => array("",""),
+"_%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
index 4d92e89ebba..406272d690f 100644
--- a/lib/l10n/gl.php
+++ b/lib/l10n/gl.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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.",
@@ -13,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Non é posíbel instalar o aplicativo por conter a etiqueta\n<shipped>\n\ntrue\n</shipped>\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.",
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 @@
<?php
$TRANSLATIONS = array(
+"No app name specified" => "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 <a href='%s'>installation guides</a>." => "Kérjük tüzetesen tanulmányozza át a <a href='%s'>telepítési útmutatót</a>.",
+"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/it.php b/lib/l10n/it.php
index 983152a14ca..b00789bc86f 100644
--- a/lib/l10n/it.php
+++ b/lib/l10n/it.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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.",
@@ -13,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "L'applicazione non può essere installata poiché contiene il tag <shipped>true<shipped> 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.",
diff --git a/lib/l10n/ja_JP.php b/lib/l10n/ja_JP.php
index 902170524b9..b9e6a0e6924 100644
--- a/lib/l10n/ja_JP.php
+++ b/lib/l10n/ja_JP.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => " \"%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ダウンロードは無効です。",
@@ -13,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "非shippedアプリには許可されない<shipped>true</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" => "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." => "トークンが無効になりました。ページを再読込してください。",
diff --git a/lib/l10n/km.php b/lib/l10n/km.php
new file mode 100644
index 00000000000..e7b09649a24
--- /dev/null
+++ b/lib/l10n/km.php
@@ -0,0 +1,8 @@
+<?php
+$TRANSLATIONS = array(
+"_%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/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 <a href='%s'>installation guides</a>." => "<a href='%s'>설치 가이드</a>를 다시 한 번 확인하십시오.",
+"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/lt_LT.php b/lib/l10n/lt_LT.php
index 242b0a23106..db8d96c1018 100644
--- a/lib/l10n/lt_LT.php
+++ b/lib/l10n/lt_LT.php
@@ -1,30 +1,72 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Programa negali būti įdiegta, nes turi <shipped>true</shipped> ž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 <a href='%s'>installation guides</a>." => "Prašome pažiūrėkite dar kartą <a href='%s'>diegimo instrukcijas</a>.",
"seconds ago" => "prieš sekundę",
-"_%n minute ago_::_%n minutes ago_" => array("",""," prieš %n minučių"),
-"_%n hour ago_::_%n hours ago_" => array("","","prieš %n valandų"),
+"_%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("","",""),
+"_%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ėnesių"),
+"_%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"
+"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/nl.php b/lib/l10n/nl.php
index e546c1f3179..20374f1f0f8 100644
--- a/lib/l10n/nl.php
+++ b/lib/l10n/nl.php
@@ -1,5 +1,6 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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",
@@ -7,6 +8,9 @@ $TRANSLATIONS = array(
"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.",
@@ -14,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "De app kan niet worden geïnstallerd omdat het de <shipped>true</shipped> 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.",
diff --git a/lib/l10n/nn_NO.php b/lib/l10n/nn_NO.php
index 28b4f7b7d94..e8bf8dfdef4 100644
--- a/lib/l10n/nn_NO.php
+++ b/lib/l10n/nn_NO.php
@@ -5,20 +5,22 @@ $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",
"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 <a href='%s'>installation guides</a>." => "Ver vennleg og dobbeltsjekk <a href='%s'>installasjonsrettleiinga</a>.",
+"Please double check the <a href='%s'>installation guides</a>." => "Ver venleg og dobbeltsjekk <a href='%s'>installasjonsrettleiinga</a>.",
"seconds ago" => "sekund sidan",
-"_%n minute ago_::_%n minutes ago_" => array("",""),
-"_%n hour ago_::_%n hours ago_" => array("",""),
+"_%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 day go_::_%n days ago_" => array("","%n dagar sidan"),
"last month" => "førre månad",
-"_%n month ago_::_%n months ago_" => array("",""),
+"_%n month ago_::_%n months ago_" => array("","%n månadar sidan"),
"last year" => "i fjor",
"years ago" => "år sidan"
);
diff --git a/lib/l10n/nqo.php b/lib/l10n/nqo.php
new file mode 100644
index 00000000000..e7b09649a24
--- /dev/null
+++ b/lib/l10n/nqo.php
@@ -0,0 +1,8 @@
+<?php
+$TRANSLATIONS = array(
+"_%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/pa.php b/lib/l10n/pa.php
new file mode 100644
index 00000000000..069fea6e710
--- /dev/null
+++ b/lib/l10n/pa.php
@@ -0,0 +1,16 @@
+<?php
+$TRANSLATIONS = array(
+"Settings" => "ਸੈਟਿੰਗ",
+"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
index 984043aa0be..270559b4e50 100644
--- a/lib/l10n/pl.php
+++ b/lib/l10n/pl.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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.",
@@ -13,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Aplikacja nie może być zainstalowana ponieważ true tag nie jest <shipped>true</shipped> , 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ę.",
@@ -39,17 +56,17 @@ $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 <a href='%s'>installation guides</a>." => "Sprawdź ponownie <a href='%s'>przewodniki instalacji</a>.",
+"Could not find category \"%s\"" => "Nie można odnaleźć kategorii \"%s\"",
"seconds ago" => "sekund temu",
-"_%n minute ago_::_%n minutes ago_" => array("","",""),
-"_%n hour ago_::_%n hours ago_" => array("","",""),
+"_%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 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 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/lib/l10n/pt_BR.php b/lib/l10n/pt_BR.php
index a2379ca4883..7a580799701 100644
--- a/lib/l10n/pt_BR.php
+++ b/lib/l10n/pt_BR.php
@@ -8,6 +8,9 @@ $TRANSLATIONS = array(
"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.",
@@ -54,13 +57,13 @@ $TRANSLATIONS = array(
"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 <a href='%s'>installation guides</a>." => "Por favor, confira os <a href='%s'>guias de instalação</a>.",
"seconds ago" => "segundos atrás",
-"_%n minute ago_::_%n minutes ago_" => array("",""),
-"_%n hour ago_::_%n hours ago_" => array("",""),
+"_%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("",""),
+"_%n day go_::_%n days ago_" => array("","ha %n dias"),
"last month" => "último mês",
-"_%n month ago_::_%n months ago_" => array("",""),
+"_%n month ago_::_%n months ago_" => array("","ha %n meses"),
"last year" => "último ano",
"years ago" => "anos atrás",
"Caused by:" => "Causados ​​por:",
diff --git a/lib/l10n/pt_PT.php b/lib/l10n/pt_PT.php
index c8a2f78cbf5..6e2bcba7b10 100644
--- a/lib/l10n/pt_PT.php
+++ b/lib/l10n/pt_PT.php
@@ -6,6 +6,8 @@ $TRANSLATIONS = array(
"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.",
@@ -40,13 +42,13 @@ $TRANSLATIONS = array(
"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 <a href='%s'>installation guides</a>." => "Por favor verifique <a href='%s'>installation guides</a>.",
"seconds ago" => "Minutos atrás",
-"_%n minute ago_::_%n minutes ago_" => array("",""),
-"_%n hour ago_::_%n hours ago_" => array("",""),
+"_%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 day go_::_%n days ago_" => array("","%n dias atrás"),
"last month" => "ultímo mês",
-"_%n month ago_::_%n months ago_" => array("",""),
+"_%n month ago_::_%n months ago_" => array("","%n meses atrás"),
"last year" => "ano passado",
"years ago" => "anos atrás",
"Caused by:" => "Causado por:",
diff --git a/lib/l10n/ro.php b/lib/l10n/ro.php
index b338b349239..76dafcd03e0 100644
--- a/lib/l10n/ro.php
+++ b/lib/l10n/ro.php
@@ -5,6 +5,8 @@ $TRANSLATIONS = array(
"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.",
@@ -19,11 +21,11 @@ $TRANSLATIONS = array(
"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 <a href='%s'>installation guides</a>." => "Vă rugăm să verificați <a href='%s'>ghiduri de instalare</a>.",
"seconds ago" => "secunde în urmă",
-"_%n minute ago_::_%n minutes ago_" => array("","",""),
-"_%n hour ago_::_%n hours ago_" => array("","",""),
+"_%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("","",""),
+"_%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",
diff --git a/lib/l10n/ru.php b/lib/l10n/ru.php
index c3b6a077b72..501065f8b5f 100644
--- a/lib/l10n/ru.php
+++ b/lib/l10n/ru.php
@@ -1,11 +1,16 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "Приложение \"%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-скачивание отключено.",
@@ -13,6 +18,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Приложение невозможно установить. Оно содержит параметр <shipped>true</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" => "Приложение невозможно установить. Версия в 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." => "Токен просрочен. Перезагрузите страницу.",
diff --git a/lib/l10n/sk_SK.php b/lib/l10n/sk_SK.php
index 4101af247c2..13487b039d6 100644
--- a/lib/l10n/sk_SK.php
+++ b/lib/l10n/sk_SK.php
@@ -1,5 +1,7 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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",
@@ -13,6 +15,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Aplikácia nemôže byť inštalovaná pretože obsahuje <shipped>pravý</shipped> š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.",
diff --git a/lib/l10n/sq.php b/lib/l10n/sq.php
index c2447b7ea23..edaa1df2b86 100644
--- a/lib/l10n/sq.php
+++ b/lib/l10n/sq.php
@@ -36,13 +36,13 @@ $TRANSLATIONS = array(
"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 <a href='%s'>installation guides</a>." => "Ju lutemi kontrolloni mirë <a href='%s'>shoqëruesin e instalimit</a>.",
"seconds ago" => "sekonda më parë",
-"_%n minute ago_::_%n minutes ago_" => array("",""),
-"_%n hour ago_::_%n hours ago_" => array("",""),
+"_%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 day go_::_%n days ago_" => array("","%n ditë më parë"),
"last month" => "muajin e shkuar",
-"_%n month ago_::_%n months ago_" => array("",""),
+"_%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"
diff --git a/lib/l10n/sr@latin.php b/lib/l10n/sr@latin.php
index 5ba51bc0ba7..d8fa9289221 100644
--- a/lib/l10n/sr@latin.php
+++ b/lib/l10n/sr@latin.php
@@ -8,9 +8,15 @@ $TRANSLATIONS = array(
"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("","",""),
-"_%n month ago_::_%n months 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/sv.php b/lib/l10n/sv.php
index dd54e6ca5d3..e7c3420a85b 100644
--- a/lib/l10n/sv.php
+++ b/lib/l10n/sv.php
@@ -1,5 +1,7 @@
<?php
$TRANSLATIONS = array(
+"App \"%s\" can't be installed because it is not compatible with this version of ownCloud." => "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",
@@ -13,6 +15,18 @@ $TRANSLATIONS = array(
"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 <shipped>true</shipped> tag which is not allowed for non shipped apps" => "Appen kan inte installeras eftersom att den innehåller etiketten <shipped>true</shipped> 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.",
diff --git a/lib/l10n/ug.php b/lib/l10n/ug.php
index 731ad904d7e..e2cf38ecc8c 100644
--- a/lib/l10n/ug.php
+++ b/lib/l10n/ug.php
@@ -8,6 +8,7 @@ $TRANSLATIONS = array(
"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" => "بۈگۈن",
diff --git a/lib/l10n/zh_CN.php b/lib/l10n/zh_CN.php
index 03bd48de74b..2c34356ea10 100644
--- a/lib/l10n/zh_CN.php
+++ b/lib/l10n/zh_CN.php
@@ -10,6 +10,7 @@ $TRANSLATIONS = array(
"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 过期,请刷新页面。",
@@ -38,12 +39,12 @@ $TRANSLATIONS = array(
"Please double check the <a href='%s'>installation guides</a>." => "请认真检查<a href='%s'>安装指南</a>.",
"seconds ago" => "秒前",
"_%n minute ago_::_%n minutes ago_" => array("%n 分钟前"),
-"_%n hour ago_::_%n hours ago_" => array(""),
+"_%n hour ago_::_%n hours ago_" => array("%n 小时前"),
"today" => "今天",
"yesterday" => "昨天",
-"_%n day go_::_%n days ago_" => array(""),
+"_%n day go_::_%n days ago_" => array("%n 天前"),
"last month" => "上月",
-"_%n month ago_::_%n months ago_" => array(""),
+"_%n month ago_::_%n months ago_" => array("%n 月前"),
"last year" => "去年",
"years ago" => "年前",
"Could not find category \"%s\"" => "无法找到分类 \"%s\""
diff --git a/lib/legacy/cache.php b/lib/legacy/cache.php
new file mode 100644
index 00000000000..f915eb516b1
--- /dev/null
+++ b/lib/legacy/cache.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+class OC_Cache extends \OC\Cache {
+} \ No newline at end of file
diff --git a/lib/legacy/preferences.php b/lib/legacy/preferences.php
new file mode 100644
index 00000000000..a663db7598b
--- /dev/null
+++ b/lib/legacy/preferences.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Frank Karlitschek
+ * @author Jakob Sack
+ * @copyright 2012 Frank Karlitschek frank@owncloud.org
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * 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/log/rotate.php b/lib/log/rotate.php
new file mode 100644
index 00000000000..bf23ad588b3
--- /dev/null
+++ b/lib/log/rotate.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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/migration/content.php b/lib/migration/content.php
index 2d8268a1d74..4413d722731 100644
--- a/lib/migration/content.php
+++ b/lib/migration/content.php
@@ -191,7 +191,8 @@ class OC_Migration_Content{
if( !file_exists( $dir ) ) {
return false;
}
- if ($dirhandle = opendir($dir)) {
+ $dirhandle = opendir($dir);
+ if(is_resource($dirhandle)) {
while (false !== ( $file = readdir($dirhandle))) {
if (( $file != '.' ) && ( $file != '..' )) {
diff --git a/lib/navigationmanager.php b/lib/navigationmanager.php
new file mode 100644
index 00000000000..1f657b9ad80
--- /dev/null
+++ b/lib/navigationmanager.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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
new file mode 100644
index 00000000000..03dba8fb25f
--- /dev/null
+++ b/lib/notsquareexception.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it>
+ * 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/activity.php b/lib/ocs/activity.php
deleted file mode 100644
index c30e21018d3..00000000000
--- a/lib/ocs/activity.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Frank Karlitschek
-* @copyright 2012 Frank Karlitschek frank@owncloud.org
-*
-* 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 <http://www.gnu.org/licenses/>.
-*
-*/
-
-class OC_OCS_Activity {
-
- public static function activityGet($parameters){
- // TODO
- }
-}
diff --git a/lib/ocsclient.php b/lib/ocsclient.php
index 67966fe7cd0..e35556d92b8 100644
--- a/lib/ocsclient.php
+++ b/lib/ocsclient.php
@@ -45,16 +45,6 @@ class OC_OCSClient{
return($url);
}
- /**
- * @brief Get the url of the OCS KB server.
- * @returns string of the KB server
- * This function returns the url of the OCS knowledge base server. It´s
- * possible to set it in the config file or it will fallback to the default
- */
- private static function getKBURL() {
- $url = OC_Config::getValue('knowledgebaseurl', 'http://api.apps.owncloud.com/v1');
- return($url);
- }
/**
* @brief Get the content of an OCS url call.
@@ -219,44 +209,5 @@ class OC_OCSClient{
}
- /**
- * @brief Get all the knowledgebase entries from the OCS server
- * @returns array with q and a data
- *
- * This function returns a list of all the knowledgebase entries from the OCS server
- */
- public static function getKnownledgebaseEntries($page, $pagesize, $search='') {
- $kbe = array('totalitems' => 0);
- if(OC_Config::getValue('knowledgebaseenabled', true)) {
- $p = (int) $page;
- $s = (int) $pagesize;
- $searchcmd = '';
- if ($search) {
- $searchcmd = '&search='.urlencode($search);
- }
- $url = OC_OCSClient::getKBURL().'/knowledgebase/data?type=150&page='. $p .'&pagesize='. $s . $searchcmd;
- $xml = OC_OCSClient::getOCSresponse($url);
- $data = @simplexml_load_string($xml);
- if($data===false) {
- OC_Log::write('core', 'Unable to parse knowledgebase content', OC_Log::FATAL);
- return null;
- }
- $tmp = $data->data->content;
- for($i = 0; $i < count($tmp); $i++) {
- $kbe[] = array(
- 'id' => $tmp[$i]->id,
- 'name' => $tmp[$i]->name,
- 'description' => $tmp[$i]->description,
- 'answer' => $tmp[$i]->answer,
- 'preview1' => $tmp[$i]->smallpreviewpic1,
- 'detailpage' => $tmp[$i]->detailpage
- );
- }
- $kbe['totalitems'] = $data->meta->totalitems;
- }
- return $kbe;
- }
-
-
}
diff --git a/lib/preferences.php b/lib/preferences.php
index 11ca760830e..359d9a83589 100644
--- a/lib/preferences.php
+++ b/lib/preferences.php
@@ -34,10 +34,21 @@
*
*/
+namespace OC;
+
+use \OC\DB\Connection;
+
+
/**
* This class provides an easy way for storing user preferences.
*/
-class OC_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
@@ -45,14 +56,13 @@ class OC_Preferences{
* This function returns a list of all users that have at least one entry
* in the preferences table.
*/
- public static function getUsers() {
- // No need for more comments
- $query = OC_DB::prepare( 'SELECT DISTINCT( `userid` ) FROM `*PREFIX*preferences`' );
- $result = $query->execute();
+ public function getUsers() {
+ $query = 'SELECT DISTINCT `userid` FROM `*PREFIX*preferences`';
+ $result = $this->conn->executeQuery( $query );
$users = array();
- while( $row = $result->fetchRow()) {
- $users[] = $row["userid"];
+ while( $userid = $result->fetchColumn()) {
+ $users[] = $userid;
}
return $users;
@@ -66,14 +76,13 @@ class OC_Preferences{
* 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 ) {
- // No need for more comments
- $query = OC_DB::prepare( 'SELECT DISTINCT( `appid` ) FROM `*PREFIX*preferences` WHERE `userid` = ?' );
- $result = $query->execute( array( $user ));
+ public function getApps( $user ) {
+ $query = 'SELECT DISTINCT `appid` FROM `*PREFIX*preferences` WHERE `userid` = ?';
+ $result = $this->conn->executeQuery( $query, array( $user ) );
$apps = array();
- while( $row = $result->fetchRow()) {
- $apps[] = $row["appid"];
+ while( $appid = $result->fetchColumn()) {
+ $apps[] = $appid;
}
return $apps;
@@ -88,14 +97,13 @@ class OC_Preferences{
* 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 ) {
- // No need for more comments
- $query = OC_DB::prepare( 'SELECT `configkey` FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ?' );
- $result = $query->execute( array( $user, $app ));
+ 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( $row = $result->fetchRow()) {
- $keys[] = $row["configkey"];
+ while( $key = $result->fetchColumn()) {
+ $keys[] = $key;
}
return $keys;
@@ -112,16 +120,14 @@ class OC_Preferences{
* 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 ) {
+ public function getValue( $user, $app, $key, $default = null ) {
// Try to fetch the value, return default if not exists.
- $query = OC_DB::prepare( 'SELECT `configvalue` FROM `*PREFIX*preferences`'
- .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?' );
- $result = $query->execute( array( $user, $app, $key ));
-
- $row = $result->fetchRow();
+ $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{
+ } else {
return $default;
}
}
@@ -132,29 +138,36 @@ class OC_Preferences{
* @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 ) {
+ public function setValue( $user, $app, $key, $value ) {
// Check if the key does exist
- $query = OC_DB::prepare( 'SELECT `configvalue` FROM `*PREFIX*preferences`'
- .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?' );
- $values=$query->execute(array($user, $app, $key))->fetchAll();
- $exists=(count($values)>0);
+ $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 ) {
- $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*preferences`'
- .' ( `userid`, `appid`, `configkey`, `configvalue` ) VALUES( ?, ?, ?, ? )' );
- $query->execute( array( $user, $app, $key, $value ));
+ $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);
}
- else{
- $query = OC_DB::prepare( 'UPDATE `*PREFIX*preferences` SET `configvalue` = ?'
- .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?' );
- $query->execute( array( $value, $user, $app, $key ));
- }
- return true;
}
/**
@@ -162,62 +175,58 @@ class OC_Preferences{
* @param string $user user
* @param string $app app
* @param string $key key
- * @return bool
*
* Deletes a key.
*/
- public static function deleteKey( $user, $app, $key ) {
- // No need for more comments
- $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*preferences`'
- .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?' );
- $query->execute( array( $user, $app, $key ));
-
- return true;
+ 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
- * @return bool
*
- * Removes all keys in appconfig belonging to the app and the user.
+ * Removes all keys in preferences belonging to the app and the user.
*/
- public static function deleteApp( $user, $app ) {
- // No need for more comments
- $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ?' );
- $query->execute( array( $user, $app ));
-
- return true;
+ 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
- * @return bool
*
- * Removes all keys in appconfig belonging to the user.
+ * Removes all keys in preferences belonging to the user.
*/
- public static function deleteUser( $user ) {
- // No need for more comments
- $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*preferences` WHERE `userid` = ?' );
- $query->execute( array( $user ));
-
- return true;
+ public function deleteUser( $user ) {
+ $where = array(
+ 'userid' => $user,
+ );
+ $this->conn->delete('*PREFIX*preferences', $where);
}
/**
* @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 ) {
- // No need for more comments
- $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*preferences` WHERE `appid` = ?' );
- $query->execute( array( $app ));
-
- return true;
+ 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
new file mode 100755
index 00000000000..266f7795f12
--- /dev/null
+++ b/lib/preview.php
@@ -0,0 +1,630 @@
+<?php
+/**
+ * Copyright (c) 2013 Frank Karlitschek frank@owncloud.org
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ *
+ * Thumbnails:
+ * structure of filename:
+ * /data/user/thumbnails/pathhash/x-y.png
+ *
+ */
+namespace OC;
+
+require_once 'preview/image.php';
+require_once 'preview/movies.php';
+require_once 'preview/mp3.php';
+require_once 'preview/pdf.php';
+require_once 'preview/svg.php';
+require_once 'preview/txt.php';
+require_once 'preview/unknown.php';
+require_once 'preview/office.php';
+
+class Preview {
+ //the thumbnail folder
+ const THUMBNAILS_FOLDER = 'thumbnails';
+
+ //config
+ private $maxScaleFactor;
+ private $configMaxX;
+ private $configMaxY;
+
+ //fileview object
+ private $fileView = null;
+ private $userView = null;
+
+ //vars
+ private $file;
+ private $maxX;
+ private $maxY;
+ private $scalingup;
+
+ //preview images object
+ /**
+ * @var \OC_Image
+ */
+ private $preview;
+
+ //preview providers
+ static private $providers = array();
+ static private $registeredProviders = array();
+
+ /**
+ * @brief check if thumbnail or bigger version of thumbnail of file is cached
+ * @param string $user userid - if no user is given, OC_User::getUser will be used
+ * @param string $root path of root
+ * @param string $file The path to the file where you want a thumbnail from
+ * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image
+ * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image
+ * @param bool $scalingUp Disable/Enable upscaling of previews
+ * @return mixed (bool / string)
+ * false if thumbnail does not exist
+ * path to thumbnail if thumbnail exists
+ */
+ public function __construct($user='', $root='/', $file='', $maxX=1, $maxY=1, $scalingUp=true) {
+ //set config
+ $this->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
new file mode 100644
index 00000000000..9aec967282d
--- /dev/null
+++ b/lib/preview/image.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright (c) 2013 Frank Karlitschek frank@owncloud.org
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+class Image extends Provider {
+
+ public function getMimeType() {
+ return '/image\/.*/';
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ //get fileinfo
+ $fileInfo = $fileview->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
new file mode 100644
index 00000000000..c318137ff0e
--- /dev/null
+++ b/lib/preview/movies.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright (c) 2013 Frank Karlitschek frank@owncloud.org
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+$isShellExecEnabled = !in_array('shell_exec', explode(', ', ini_get('disable_functions')));
+$whichAVCONV = shell_exec('which avconv');
+$isAVCONVAvailable = !empty($whichAVCONV);
+
+if($isShellExecEnabled && $isAVCONVAvailable) {
+
+ class Movie extends Provider {
+
+ public function getMimeType() {
+ return '/video\/.*/';
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ $absPath = \OC_Helper::tmpFile();
+ $tmpPath = \OC_Helper::tmpFile();
+
+ $handle = $fileview->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
new file mode 100644
index 00000000000..1eed566315c
--- /dev/null
+++ b/lib/preview/mp3.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+class MP3 extends Provider {
+
+ public function getMimeType() {
+ return '/audio\/mpeg/';
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ require_once('getid3/getid3.php');
+
+ $getID3 = new \getID3();
+
+ $tmpPath = $fileview->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
new file mode 100644
index 00000000000..112909d6523
--- /dev/null
+++ b/lib/preview/office-cl.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+//we need imagick to convert
+class Office extends Provider {
+
+ private $cmd;
+
+ public function getMimeType() {
+ return null;
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ $this->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
new file mode 100644
index 00000000000..e69ab0ab8cb
--- /dev/null
+++ b/lib/preview/office-fallback.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+/* //There is no (good) php-only solution for converting 2003 word documents to pdfs / pngs ...
+class DOC extends Provider {
+
+ public function getMimeType() {
+ return '/application\/msword/';
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ require_once('');
+ }
+
+}
+
+\OC\Preview::registerProvider('OC\Preview\DOC');
+*/
+
+class DOCX extends Provider {
+
+ public function getMimeType() {
+ return '/application\/vnd.openxmlformats-officedocument.wordprocessingml.document/';
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ require_once('phpdocx/classes/TransformDoc.inc');
+
+ $tmpDoc = $fileview->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
new file mode 100644
index 00000000000..5287bbd6ac1
--- /dev/null
+++ b/lib/preview/office.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+//both, libreoffice backend and php fallback, need imagick
+if (extension_loaded('imagick')) {
+ $isShellExecEnabled = !in_array('shell_exec', explode(', ', ini_get('disable_functions')));
+ $whichLibreOffice = shell_exec('which libreoffice');
+ $isLibreOfficeAvailable = !empty($whichLibreOffice);
+ $whichOpenOffice = shell_exec('which libreoffice');
+ $isOpenOfficeAvailable = !empty($whichOpenOffice);
+ //let's see if there is libreoffice or openoffice on this machine
+ if($isShellExecEnabled && ($isLibreOfficeAvailable || $isOpenOfficeAvailable || is_string(\OC_Config::getValue('preview_libreoffice_path', null)))) {
+ require_once('office-cl.php');
+ }else{
+ //in case there isn't, use our fallback
+ require_once('office-fallback.php');
+ }
+} \ No newline at end of file
diff --git a/lib/preview/pdf.php b/lib/preview/pdf.php
new file mode 100644
index 00000000000..cc974b68818
--- /dev/null
+++ b/lib/preview/pdf.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+if (extension_loaded('imagick')) {
+
+ class PDF extends Provider {
+
+ public function getMimeType() {
+ return '/application\/pdf/';
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ $tmpPath = $fileview->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
new file mode 100644
index 00000000000..e4a730bafc8
--- /dev/null
+++ b/lib/preview/provider.php
@@ -0,0 +1,19 @@
+<?php
+namespace OC\Preview;
+
+abstract class Provider {
+ private $options;
+
+ public function __construct($options) {
+ $this->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
new file mode 100644
index 00000000000..b49e51720fa
--- /dev/null
+++ b/lib/preview/svg.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+if (extension_loaded('imagick')) {
+
+ class SVG extends Provider {
+
+ public function getMimeType() {
+ return '/image\/svg\+xml/';
+ }
+
+ public function getThumbnail($path,$maxX,$maxY,$scalingup,$fileview) {
+ try{
+ $svg = new \Imagick();
+ $svg->setBackgroundColor(new \ImagickPixel('transparent'));
+
+ $content = stream_get_contents($fileview->fopen($path, 'r'));
+ if(substr($content, 0, 5) !== '<?xml') {
+ $content = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . $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
new file mode 100644
index 00000000000..77e728eb364
--- /dev/null
+++ b/lib/preview/txt.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+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);
+
+ //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
new file mode 100644
index 00000000000..9e6cd68d401
--- /dev/null
+++ b/lib/preview/unknown.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Copyright (c) 2013 Frank Karlitschek frank@owncloud.org
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OC\Preview;
+
+class Unknown extends Provider {
+
+ public function getMimeType() {
+ return '/.*/';
+ }
+
+ public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
+ $mimetype = $fileview->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
new file mode 100755
index 00000000000..ac9a866a75b
--- /dev/null
+++ b/lib/previewmanager.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Müller thomas.mueller@tmit.eu
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ *
+ */
+namespace OC;
+
+use OCP\image;
+use OCP\IPreview;
+
+class PreviewManager implements IPreview {
+ /**
+ * @brief return a preview of a file
+ * @param string $file The path to the file where you want a thumbnail from
+ * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image
+ * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image
+ * @param boolean $scaleUp Scale smaller images up to the thumbnail size or not. Might look ugly
+ * @return \OCP\Image
+ */
+ function createPreview($file, $maxX = 100, $maxY = 75, $scaleUp = false)
+ {
+ $preview = new \OC\Preview('', '/', $file, $maxX, $maxY, $scaleUp);
+ return $preview->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/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 );
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 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller deepdiver@owncloud.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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/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 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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();
+ }
+
+}
diff --git a/lib/public/appframework/iapi.php b/lib/public/appframework/iapi.php
new file mode 100644
index 00000000000..fa6af5f5965
--- /dev/null
+++ b/lib/public/appframework/iapi.php
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCP\AppFramework;
+
+
+/**
+ * A few very basic and frequently used API functions are combined in here
+ */
+interface IApi {
+
+
+ /**
+ * Gets the userid of the current user
+ * @return string the user id of the current user
+ */
+ function getUserId();
+
+
+ /**
+ * 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);
+
+ /**
+ * Returns the translation object
+ * @return \OC_L10N the translation object
+ *
+ * FIXME: returns private object / should be retrieved from teh ServerContainer
+ */
+ function getTrans();
+
+
+ /**
+ * 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..7d3b4b3bac7
--- /dev/null
+++ b/lib/public/appframework/iappcontainer.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller deepdiver@owncloud.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\AppFramework;
+
+use OCP\AppFramework\IApi;
+use OCP\IContainer;
+
+/**
+ * Class IAppContainer
+ * @package OCP\AppFramework
+ *
+ * This container interface provides short cuts for app developers to access predefined app service.
+ */
+interface IAppContainer extends IContainer{
+
+ /**
+ * used to return the appname of the set application
+ * @return string the name of your application
+ */
+ function getAppName();
+
+ /**
+ * @return IApi
+ */
+ function getCoreApi();
+
+ /**
+ * @return \OCP\IServerContainer
+ */
+ function getServer();
+
+ /**
+ * @param IMiddleWare $middleWare
+ * @return boolean
+ */
+ function registerMiddleWare(IMiddleWare $middleWare);
+}
diff --git a/lib/public/appframework/imiddleware.php b/lib/public/appframework/imiddleware.php
new file mode 100644
index 00000000000..1e76d3bbe49
--- /dev/null
+++ b/lib/public/appframework/imiddleware.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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 IMiddleWare {
+
+
+ /**
+ * 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);
+}
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/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 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller thomas.mueller@tmit.eu
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * 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/db.php b/lib/public/db.php
index 932e79d9ef1..9512cca2d19 100644
--- a/lib/public/db.php
+++ b/lib/public/db.php
@@ -102,4 +102,15 @@ class DB {
public static function isError($result) {
return(\OC_DB::isError($result));
}
+
+ /**
+ * returns the error code and message as a string for logging
+ * works with DoctrineException
+ * @param mixed $error
+ * @return string
+ */
+ public static function getErrorMessage($error) {
+ return(\OC_DB::getErrorMessage($error));
+ }
+
}
diff --git a/lib/public/files/alreadyexistsexception.php b/lib/public/files/alreadyexistsexception.php
new file mode 100644
index 00000000000..32947c7a5c3
--- /dev/null
+++ b/lib/public/files/alreadyexistsexception.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+class AlreadyExistsException extends \Exception {}
diff --git a/lib/public/files/file.php b/lib/public/files/file.php
new file mode 100644
index 00000000000..916b2edd6c4
--- /dev/null
+++ b/lib/public/files/file.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+interface File extends Node {
+ /**
+ * Get the content of the file as string
+ *
+ * @return string
+ * @throws \OCP\Files\NotPermittedException
+ */
+ public function getContent();
+
+ /**
+ * Write to the file from string data
+ *
+ * @param string $data
+ * @throws \OCP\Files\NotPermittedException
+ */
+ public function putContent($data);
+
+ /**
+ * Get the mimetype of the file
+ *
+ * @return string
+ */
+ public function getMimeType();
+
+ /**
+ * Open the file as stream, resulting resource can be operated as stream like the result from php's own fopen
+ *
+ * @param string $mode
+ * @return resource
+ * @throws \OCP\Files\NotPermittedException
+ */
+ public function fopen($mode);
+
+ /**
+ * Compute the hash of the file
+ * Type of hash is set with $type and can be anything supported by php's hash_file
+ *
+ * @param string $type
+ * @param bool $raw
+ * @return string
+ */
+ public function hash($type, $raw = false);
+}
diff --git a/lib/public/files/folder.php b/lib/public/files/folder.php
new file mode 100644
index 00000000000..da7f20fd366
--- /dev/null
+++ b/lib/public/files/folder.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+interface Folder extends Node {
+ /**
+ * Get the full path of an item in the folder within owncloud's filesystem
+ *
+ * @param string $path relative path of an item in the folder
+ * @return string
+ * @throws \OCP\Files\NotPermittedException
+ */
+ public function getFullPath($path);
+
+ /**
+ * Get the path of an item in the folder relative to the folder
+ *
+ * @param string $path absolute path of an item in the folder
+ * @throws \OCP\Files\NotFoundException
+ * @return string
+ */
+ public function getRelativePath($path);
+
+ /**
+ * check if a node is a (grand-)child of the folder
+ *
+ * @param \OCP\Files\Node $node
+ * @return bool
+ */
+ public function isSubNode($node);
+
+ /**
+ * get the content of this directory
+ *
+ * @throws \OCP\Files\NotFoundException
+ * @return \OCP\Files\Node[]
+ */
+ public function getDirectoryListing();
+
+ /**
+ * Get the node at $path
+ *
+ * @param string $path relative path of the file or folder
+ * @return \OCP\Files\Node
+ * @throws \OCP\Files\NotFoundException
+ */
+ public function get($path);
+
+ /**
+ * Check if a file or folder exists in the folder
+ *
+ * @param string $path relative path of the file or folder
+ * @return bool
+ */
+ public function nodeExists($path);
+
+ /**
+ * Create a new folder
+ *
+ * @param string $path relative path of the new folder
+ * @return \OCP\Files\Folder
+ * @throws \OCP\Files\NotPermittedException
+ */
+ public function newFolder($path);
+
+ /**
+ * Create a new file
+ *
+ * @param string $path relative path of the new file
+ * @return \OCP\Files\File
+ * @throws \OCP\Files\NotPermittedException
+ */
+ public function newFile($path);
+
+ /**
+ * search for files with the name matching $query
+ *
+ * @param string $query
+ * @return \OCP\Files\Node[]
+ */
+ public function search($query);
+
+ /**
+ * search for files by mimetype
+ * $mimetype can either be a full mimetype (image/png) or a wildcard mimetype (image)
+ *
+ * @param string $mimetype
+ * @return \OCP\Files\Node[]
+ */
+ public function searchByMime($mimetype);
+
+ /**
+ * get a file or folder inside the folder by it's internal id
+ *
+ * @param int $id
+ * @return \OCP\Files\Node[]
+ */
+ public function getById($id);
+
+ /**
+ * Get the amount of free space inside the folder
+ *
+ * @return int
+ */
+ public function getFreeSpace();
+
+ /**
+ * Check if new files or folders can be created within the folder
+ *
+ * @return bool
+ */
+ public function isCreatable();
+}
diff --git a/lib/public/files/node.php b/lib/public/files/node.php
new file mode 100644
index 00000000000..b3ddf6de621
--- /dev/null
+++ b/lib/public/files/node.php
@@ -0,0 +1,159 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+interface Node {
+ /**
+ * Move the file or folder to a new location
+ *
+ * @param string $targetPath the absolute target path
+ * @throws \OCP\Files\NotPermittedException
+ * @return \OCP\Files\Node
+ */
+ public function move($targetPath);
+
+ /**
+ * Delete the file or folder
+ */
+ public function delete();
+
+ /**
+ * Cope the file or folder to a new location
+ *
+ * @param string $targetPath the absolute target path
+ * @return \OCP\Files\Node
+ */
+ public function copy($targetPath);
+
+ /**
+ * Change the modified date of the file or folder
+ * If $mtime is omitted the current time will be used
+ *
+ * @param int $mtime (optional) modified date as unix timestamp
+ * @throws \OCP\Files\NotPermittedException
+ */
+ public function touch($mtime = null);
+
+ /**
+ * Get the storage backend the file or folder is stored on
+ *
+ * @return \OCP\Files\Storage
+ * @throws \OCP\Files\NotFoundException
+ */
+ public function getStorage();
+
+ /**
+ * Get the full path of the file or folder
+ *
+ * @return string
+ */
+ public function getPath();
+
+ /**
+ * Get the path of the file or folder relative to the mountpoint of it's storage
+ *
+ * @return string
+ */
+ public function getInternalPath();
+
+ /**
+ * Get the internal file id for the file or folder
+ *
+ * @return int
+ */
+ public function getId();
+
+ /**
+ * Get metadata of the file or folder
+ * The returned array contains the following values:
+ * - mtime
+ * - size
+ *
+ * @return array
+ */
+ public function stat();
+
+ /**
+ * Get the modified date of the file or folder as unix timestamp
+ *
+ * @return int
+ */
+ public function getMTime();
+
+ /**
+ * Get the size of the file or folder in bytes
+ *
+ * @return int
+ */
+ public function getSize();
+
+ /**
+ * Get the Etag of the file or folder
+ * The Etag is an string id used to detect changes to a file or folder,
+ * every time the file or folder is changed the Etag will change to
+ *
+ * @return string
+ */
+ public function getEtag();
+
+
+ /**
+ * Get the permissions of the file or folder as a combination of one or more of the following constants:
+ * - \OCP\PERMISSION_READ
+ * - \OCP\PERMISSION_UPDATE
+ * - \OCP\PERMISSION_CREATE
+ * - \OCP\PERMISSION_DELETE
+ * - \OCP\PERMISSION_SHARE
+ *
+ * @return int
+ */
+ public function getPermissions();
+
+ /**
+ * Check if the file or folder is readable
+ *
+ * @return bool
+ */
+ public function isReadable();
+
+ /**
+ * Check if the file or folder is writable
+ *
+ * @return bool
+ */
+ public function isUpdateable();
+
+ /**
+ * Check if the file or folder is deletable
+ *
+ * @return bool
+ */
+ public function isDeletable();
+
+ /**
+ * Check if the file or folder is shareable
+ *
+ * @return bool
+ */
+ public function isShareable();
+
+ /**
+ * Get the parent folder of the file or folder
+ *
+ * @return Folder
+ */
+ public function getParent();
+
+ /**
+ * Get the filename of the file or folder
+ *
+ * @return string
+ */
+ public function getName();
+}
diff --git a/lib/public/files/notenoughspaceexception.php b/lib/public/files/notenoughspaceexception.php
new file mode 100644
index 00000000000..e51806666ad
--- /dev/null
+++ b/lib/public/files/notenoughspaceexception.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+class NotEnoughSpaceException extends \Exception {}
diff --git a/lib/public/files/notfoundexception.php b/lib/public/files/notfoundexception.php
new file mode 100644
index 00000000000..1ff426a40c6
--- /dev/null
+++ b/lib/public/files/notfoundexception.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+class NotFoundException extends \Exception {}
diff --git a/lib/public/files/notpermittedexception.php b/lib/public/files/notpermittedexception.php
new file mode 100644
index 00000000000..0509de7e829
--- /dev/null
+++ b/lib/public/files/notpermittedexception.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+class NotPermittedException extends \Exception {}
diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php
new file mode 100644
index 00000000000..f32f2073483
--- /dev/null
+++ b/lib/public/files/storage.php
@@ -0,0 +1,297 @@
+<?php
+/**
+ * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+/**
+ * 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 {
+ /**
+ * $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-file.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 the ETag for a file or folder
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getETag($path);
+}
diff --git a/lib/public/icache.php b/lib/public/icache.php
new file mode 100644
index 00000000000..436ee71b2b9
--- /dev/null
+++ b/lib/public/icache.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OCP;
+
+/**
+ * This interface defines method for accessing the file based user cache.
+ */
+interface ICache {
+
+ /**
+ * Get a value from the user cache
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function 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);
+
+ /**
+ * Check if a value is set in the user cache
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function hasKey($key);
+
+ /**
+ * Remove an item from the user cache
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function remove($key);
+
+ /**
+ * clear the user cache of all entries starting with a prefix
+ * @param string $prefix (optional)
+ * @return bool
+ */
+ public function clear($prefix = '');
+}
diff --git a/lib/public/iconfig.php b/lib/public/iconfig.php
new file mode 100644
index 00000000000..850bddf6935
--- /dev/null
+++ b/lib/public/iconfig.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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 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);
+
+ /**
+ * 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);
+
+
+ /**
+ * 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);
+
+ /**
+ * 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);
+
+
+ /**
+ * 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);
+
+ /**
+ * 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);
+}
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 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller deepdiver@owncloud.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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/idbconnection.php b/lib/public/idbconnection.php
new file mode 100644
index 00000000000..c741a0f061a
--- /dev/null
+++ b/lib/public/idbconnection.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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
+ * @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();
+
+ /**
+ * returns the error code and message as a string for logging
+ * @return string
+ */
+ public function getError();
+}
diff --git a/lib/public/inavigationmanager.php b/lib/public/inavigationmanager.php
new file mode 100644
index 00000000000..f89e790c1d0
--- /dev/null
+++ b/lib/public/inavigationmanager.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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);
+}
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 @@
+<?php
+/**
+ * Copyright (c) 2013 Frank Karlitschek frank@owncloud.org
+ * Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+namespace OCP;
+
+/**
+ * This class provides functions to render and show thumbnails and previews of files
+ */
+interface IPreview
+{
+
+ /**
+ * @brief return a preview of a file
+ * @param string $file The path to the file where you want a thumbnail from
+ * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image
+ * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image
+ * @param boolean $scaleUp Scale smaller images up to the thumbnail size or not. Might look ugly
+ * @return \OCP\Image
+ */
+ function createPreview($file, $maxX = 100, $maxY = 75, $scaleUp = false);
+
+
+ /**
+ * @brief returns true if the passed mime type is supported
+ * @param string $mimeType
+ * @return boolean
+ */
+ function isMimeSupported($mimeType = '*');
+
+}
diff --git a/lib/public/irequest.php b/lib/public/irequest.php
new file mode 100644
index 00000000000..9f335b06f2a
--- /dev/null
+++ b/lib/public/irequest.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller deepdiver@owncloud.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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 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..f4045faefef
--- /dev/null
+++ b/lib/public/iservercontainer.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller deepdiver@owncloud.com
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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();
+
+ /**
+ * Returns the preview manager which can create preview images for a given file
+ *
+ * @return \OCP\IPreview
+ */
+ function getPreviewManager();
+
+ /**
+ * Returns the tag manager which can get and set tags for different object types
+ *
+ * @see \OCP\ITagManager::load()
+ * @return \OCP\ITagManager
+ */
+ function getTagManager();
+
+ /**
+ * Returns the root folder of ownCloud's data directory
+ *
+ * @return \OCP\Files\Folder
+ */
+ 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 user session
+ *
+ * @return \OCP\IUserSession
+ */
+ function getUserSession();
+
+ /**
+ * @return \OCP\INavigationManager
+ */
+ function getNavigationManager();
+
+ /**
+ * @return \OCP\IConfig
+ */
+ function getConfig();
+
+ /**
+ * Returns an ICache instance
+ *
+ * @return \OCP\ICache
+ */
+ function getCache();
+
+ /**
+ * Returns the current session
+ *
+ * @return \OCP\ISession
+ */
+ function getSession();
+
+ /**
+ * Returns the current session
+ *
+ * @return \OCP\IDBConnection
+ */
+ function getDatabaseConnection();
+
+}
diff --git a/lib/public/isession.php b/lib/public/isession.php
new file mode 100644
index 00000000000..0a77b0c823b
--- /dev/null
+++ b/lib/public/isession.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
+ * @author Thomas Tanghus
+ * @author Robin Appelman
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+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);
+
+ /**
+ * Remove a $key/$value pair from the session
+ *
+ * @param string $key
+ */
+ public function remove($key);
+
+ /**
+ * Reset and recreate the session
+ */
+ public function clear();
+
+}
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 @@
+<?php
+/**
+* ownCloud
+*
+* @author Thomas Tanghus
+* @copyright 2013 Thomas Tanghus <thomas@tanghus.net>
+*
+* 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 <http://www.gnu.org/licenses/>.
+*
+*/
+
+/**
+ * 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
new file mode 100644
index 00000000000..5b1ebd189da
--- /dev/null
+++ b/lib/public/itags.php
@@ -0,0 +1,164 @@
+<?php
+/**
+* ownCloud
+*
+* @author Thomas Tanghus
+* @copyright 2013 Thomas Tanghus <thomas@tanghus.net>
+*
+* 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 <http://www.gnu.org/licenses/>.
+*
+*/
+
+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 {
+
+ /**
+ * 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 getTags();
+
+ /**
+ * 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);
+
+ /**
+ * 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 addMultiple($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/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 @@
+<?php
+/**
+ * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
+ * 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/public/share.php b/lib/public/share.php
index b38208bc67f..6c5783f1179 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -106,22 +106,22 @@ class Share {
}
return false;
}
-
+
/**
* @brief Prepare a path to be passed to DB as file_target
* @return string Prepared path
*/
public static function prepFileTarget( $path ) {
-
+
// Paths in DB are stored with leading slashes, so add one if necessary
if ( substr( $path, 0, 1 ) !== '/' ) {
-
+
$path = '/' . $path;
-
+
}
-
+
return $path;
-
+
}
/**
@@ -140,8 +140,13 @@ class Share {
$source = -1;
$cache = false;
- $view = new \OC\Files\View('/' . $user . '/files/');
- $meta = $view->getFileInfo(\OC\Files\Filesystem::normalizePath($path));
+ $view = new \OC\Files\View('/' . $user . '/files');
+ if ($view->file_exists($path)) {
+ $meta = $view->getFileInfo($path);
+ } else {
+ // if the file doesn't exists yet we start with the parent folder
+ $meta = $view->getFileInfo(dirname($path));
+ }
if($meta !== false) {
$source = $meta['fileid'];
@@ -251,7 +256,7 @@ class Share {
return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
$parameters, 1, $includeCollections);
}
-
+
/**
* @brief Get the item of item type shared with the current user by source
* @param string Item type
@@ -288,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;
}
/**
@@ -445,6 +461,7 @@ class Share {
$uidOwner, self::FORMAT_NONE, null, 1)) {
// remember old token
$oldToken = $checkExists['token'];
+ $oldPermissions = $checkExists['permissions'];
//delete the old share
self::delete($checkExists['id']);
}
@@ -455,15 +472,18 @@ class Share {
$hasher = new \PasswordHash(8, $forcePortable);
$shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', ''));
} else {
- // reuse the already set password
- $shareWith = $checkExists['share_with'];
+ // reuse the already set password, but only if we change permissions
+ // otherwise the user disabled the password protection
+ if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
+ $shareWith = $checkExists['share_with'];
+ }
}
// Generate token
if (isset($oldToken)) {
$token = $oldToken;
} else {
- $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH);
+ $token = \OC_Util::generateRandomBytes(self::TOKEN_LENGTH);
}
$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
null, $token);
@@ -740,10 +760,10 @@ 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
*/
- 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'])) {
diff --git a/lib/public/template.php b/lib/public/template.php
index ab1089c332d..3b1a4ed4906 100644
--- a/lib/public/template.php
+++ b/lib/public/template.php
@@ -54,6 +54,25 @@ function mimetype_icon( $mimetype ) {
return(\mimetype_icon( $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
+ */
+function preview_icon( $path ) {
+ return(\preview_icon( $path ));
+}
+
+/**
+ * @brief make publicpreview_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
+ */
+function publicPreview_icon ( $path, $token ) {
+ return(\publicPreview_icon( $path, $token ));
+}
/**
* @brief make OC_Helper::humanFileSize available as a simple function
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/search/provider/file.php b/lib/search/provider/file.php
index 4d88c2a87f1..9bd50931517 100644
--- a/lib/search/provider/file.php
+++ b/lib/search/provider/file.php
@@ -10,6 +10,7 @@ class OC_Search_Provider_File extends OC_Search_Provider{
$mime = $fileData['mimetype'];
$name = basename($path);
+ $container = dirname($path);
$text = '';
$skip = false;
if($mime=='httpd/unix-directory') {
@@ -37,7 +38,7 @@ class OC_Search_Provider_File extends OC_Search_Provider{
}
}
if(!$skip) {
- $results[] = new OC_Search_Result($name, $text, $link, $type);
+ $results[] = new OC_Search_Result($name, $text, $link, $type, $container);
}
}
return $results;
diff --git a/lib/search/result.php b/lib/search/result.php
index 08beaea151c..42275c2df11 100644
--- a/lib/search/result.php
+++ b/lib/search/result.php
@@ -7,6 +7,7 @@ class OC_Search_Result{
public $text;
public $link;
public $type;
+ public $container;
/**
* create a new search result
@@ -15,10 +16,11 @@ class OC_Search_Result{
* @param string $link link for the result
* @param string $type the type of result as human readable string ('File', 'Music', etc)
*/
- public function __construct($name, $text, $link, $type) {
+ public function __construct($name, $text, $link, $type, $container) {
$this->name=$name;
$this->text=$text;
$this->link=$link;
$this->type=$type;
+ $this->container=$container;
}
}
diff --git a/lib/server.php b/lib/server.php
new file mode 100644
index 00000000000..cabb15324ec
--- /dev/null
+++ b/lib/server.php
@@ -0,0 +1,255 @@
+<?php
+
+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;
+
+/**
+ * Class Server
+ * @package OC
+ *
+ * TODO: hookup all manager classes
+ */
+class Server extends SimpleContainer implements IServerContainer {
+
+ function __construct() {
+ $this->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/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
*
diff --git a/lib/setup.php b/lib/setup.php
index 05a49890976..6bf3c88370f 100644
--- a/lib/setup.php
+++ b/lib/setup.php
@@ -61,7 +61,7 @@ class OC_Setup {
}
//generate a random salt that is used to salt the local user passwords
- $salt = OC_Util::generate_random_bytes(30);
+ $salt = OC_Util::generateRandomBytes(30);
OC_Config::setValue('passwordsalt', $salt);
//write the config file
diff --git a/lib/setup/mysql.php b/lib/setup/mysql.php
index 0cf04fde5a1..d97b6d2602f 100644
--- a/lib/setup/mysql.php
+++ b/lib/setup/mysql.php
@@ -23,7 +23,7 @@ class MySQL extends AbstractDatabase {
$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::generate_random_bytes(30);
+ $this->dbpassword=\OC_Util::generateRandomBytes(30);
$this->createDBUser($connection);
diff --git a/lib/setup/oci.php b/lib/setup/oci.php
index 86b53de45a4..326d7a00531 100644
--- a/lib/setup/oci.php
+++ b/lib/setup/oci.php
@@ -65,7 +65,7 @@ class OCI extends AbstractDatabase {
//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::generate_random_bytes(30);
+ $this->dbpassword=\OC_Util::generateRandomBytes(30);
//oracle passwords are treated as identifiers:
// must start with aphanumeric char
diff --git a/lib/setup/postgresql.php b/lib/setup/postgresql.php
index 49fcbf0326e..89d328ada19 100644
--- a/lib/setup/postgresql.php
+++ b/lib/setup/postgresql.php
@@ -33,7 +33,7 @@ class PostgreSQL extends AbstractDatabase {
//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::generate_random_bytes(30);
+ $this->dbpassword=\OC_Util::generateRandomBytes(30);
$this->createDBUser($connection);
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 @@
+<?php
+/**
+* ownCloud
+*
+* @author Thomas Tanghus
+* @copyright 2013 Thomas Tanghus <thomas@tanghus.net>
+*
+* 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 <http://www.gnu.org/licenses/>.
+*
+*/
+
+/**
+ * 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
new file mode 100644
index 00000000000..9fdb35a7d6e
--- /dev/null
+++ b/lib/tags.php
@@ -0,0 +1,642 @@
+<?php
+/**
+* ownCloud
+*
+* @author Thomas Tanghus
+* @copyright 2012-2013 Thomas Tanghus <thomas@tanghus.net>
+* @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 <http://www.gnu.org/licenses/>.
+*
+*/
+
+/**
+ * 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 = '_$!<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/template/functions.php b/lib/template/functions.php
index 717e197c1cb..501f8081bff 100644
--- a/lib/template/functions.php
+++ b/lib/template/functions.php
@@ -59,6 +59,22 @@ function mimetype_icon( $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
diff --git a/lib/templatelayout.php b/lib/templatelayout.php
index 0024c9d4960..625f3424a04 100644
--- a/lib/templatelayout.php
+++ b/lib/templatelayout.php
@@ -46,6 +46,7 @@ class OC_TemplateLayout extends OC_Template {
$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 {
@@ -58,7 +59,7 @@ class OC_TemplateLayout extends OC_Template {
if (OC_Config::getValue('installed', false) && $renderas!='error') {
$this->append( 'jsfiles', OC_Helper::linkToRoute('js_config') . $versionParameter);
}
- if (!empty(OC_Util::$core_scripts)) {
+ if (!empty(OC_Util::$coreScripts)) {
$this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false) . $versionParameter);
}
foreach($jsfiles as $info) {
@@ -71,7 +72,7 @@ class OC_TemplateLayout extends OC_Template {
// Add the css files
$cssfiles = self::findStylesheetFiles(OC_Util::$styles);
$this->assign('cssfiles', array());
- if (!empty(OC_Util::$core_styles)) {
+ if (!empty(OC_Util::$coreStyles)) {
$this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false) . $versionParameter);
}
foreach($cssfiles as $info) {
diff --git a/lib/user.php b/lib/user.php
index 93c7c9d4cd5..15e807088b4 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();
@@ -177,6 +138,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'];
@@ -353,7 +315,7 @@ class OC_User {
* generates a password
*/
public static function generatePassword() {
- return OC_Util::generate_random_bytes(30);
+ return OC_Util::generateRandomBytes(30);
}
/**
@@ -410,22 +372,18 @@ 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
*/
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 $username->getUID();
}
+ return false;
}
/**
diff --git a/lib/user/http.php b/lib/user/http.php
index 1e044ed4188..e99afe59ba7 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..13286bc28a4 100644
--- a/lib/user/manager.php
+++ b/lib/user/manager.php
@@ -119,6 +119,25 @@ class Manager extends PublicEmitter {
}
/**
+ * 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
diff --git a/lib/user/session.php b/lib/user/session.php
index 9a6c669e935..525c65ab8a1 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
*/
@@ -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
@@ -106,24 +106,6 @@ class User {
}
/**
- * 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
*
* @param string $password
diff --git a/lib/util.php b/lib/util.php
index 5bfa7d74228..36969f096fa 100755
--- a/lib/util.php
+++ b/lib/util.php
@@ -11,12 +11,18 @@ class OC_Util {
public static $headers=array();
private static $rootMounted=false;
private static $fsSetup=false;
- public static $core_styles=array();
- public static $core_scripts=array();
+ public static $coreStyles=array();
+ public static $coreScripts=array();
- // Can be set up
- public static function setupFS( $user = '' ) {// configure the initial filesystem based on the configuration
- if(self::$fsSetup) {//setting up the filesystem twice can only lead to trouble
+ /**
+ * @brief Can be set up
+ * @param string $user
+ * @return boolean
+ * @description configure the initial filesystem based on the configuration
+ */
+ public static function setupFS( $user = '' ) {
+ //setting up the filesystem twice can only lead to trouble
+ if(self::$fsSetup) {
return false;
}
@@ -37,15 +43,16 @@ class OC_Util {
self::$fsSetup=true;
}
- $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
+ $configDataDirectory = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
//first set up the local "root" storage
\OC\Files\Filesystem::initMounts();
if(!self::$rootMounted) {
- \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir'=>$CONFIG_DATADIRECTORY), '/');
- self::$rootMounted=true;
+ \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir'=>$configDataDirectory), '/');
+ self::$rootMounted = true;
}
- if( $user != "" ) { //if we aren't logged in, there is no use to set up the filesystem
+ //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) {
@@ -56,19 +63,19 @@ class OC_Util {
}
});
}
- $user_dir = '/'.$user.'/files';
- $user_root = OC_User::getHome($user);
- $userdirectory = $user_root . '/files';
- if( !is_dir( $userdirectory )) {
- mkdir( $userdirectory, 0755, true );
+ $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, $user_dir);
+ \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' => $user_dir));
+ OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir));
}
return true;
}
@@ -85,14 +92,17 @@ class OC_Util {
}
}
+ /**
+ * @return void
+ */
public static function tearDownFS() {
\OC\Files\Filesystem::tearDown();
self::$fsSetup=false;
- self::$rootMounted=false;
+ self::$rootMounted=false;
}
/**
- * get the current installed version of ownCloud
+ * @brief get the current installed version of ownCloud
* @return array
*/
public static function getVersion() {
@@ -101,7 +111,7 @@ class OC_Util {
}
/**
- * get the current installed version string of ownCloud
+ * @brief get the current installed version string of ownCloud
* @return string
*/
public static function getVersionString() {
@@ -110,7 +120,7 @@ class OC_Util {
}
/**
- * get the current installed edition of ownCloud. There is the community
+ * @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
@@ -153,103 +163,117 @@ class OC_Util {
}
/**
- * add a javascript file
+ * @brief add a javascript file
*
- * @param appid $application
- * @param filename $file
+ * @param string $application
+ * @param filename $file
+ * @return void
*/
public static function addScript( $application, $file = null ) {
- if( is_null( $file )) {
+ if ( is_null( $file )) {
$file = $application;
$application = "";
}
- if( !empty( $application )) {
+ if ( !empty( $application )) {
self::$scripts[] = "$application/js/$file";
- }else{
+ } else {
self::$scripts[] = "js/$file";
}
}
/**
- * add a css file
+ * @brief add a css file
*
- * @param appid $application
- * @param filename $file
+ * @param string $application
+ * @param filename $file
+ * @return void
*/
public static function addStyle( $application, $file = null ) {
- if( is_null( $file )) {
+ if ( is_null( $file )) {
$file = $application;
$application = "";
}
- if( !empty( $application )) {
+ if ( !empty( $application )) {
self::$styles[] = "$application/css/$file";
- }else{
+ } else {
self::$styles[] = "css/$file";
}
}
/**
* @brief Add a custom element to the header
- * @param string tag tag name of the element
+ * @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);
+ self::$headers[] = array(
+ 'tag'=>$tag,
+ 'attributes'=>$attributes,
+ 'text'=>$text
+ );
}
/**
- * formats a timestamp in the "right" way
+ * @brief formats a timestamp in the "right" way
*
- * @param int timestamp $timestamp
- * @param bool dateOnly option to omit time from the result
+ * @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')) {//adjust to clients timezone if we know it
+ 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;
+ $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');
+ $l = OC_L10N::get('lib');
return $l->l($dateOnly ? 'date' : 'datetime', $timestamp);
}
/**
- * check if the current server configuration is suitable for ownCloud
+ * @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'))
+ if(\OC::$session->exists('checkServer_suceeded') && \OC::$session->get('checkServer_suceeded')) {
return array();
+ }
- $errors=array();
+ $errors = array();
$defaults = new \OC_Defaults();
- $web_server_restart= false;
+ $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
- $web_server_restart= true;
+ $errors[] = array(
+ 'error'=>'No database drivers (sqlite, mysql, or postgresql) installed.',
+ 'hint'=>'' //TODO: sane hint
+ );
+ $webServerRestart = true;
}
- //common hint for all file permissons error messages
+ //common hint for all file permissions error messages
$permissionsHint = 'Permissions can usually be fixed by '
- .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html#set-the-directory-permissions" target="_blank">giving the webserver write access to the root directory</a>.';
+ .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html'
+ .'#set-the-directory-permissions" target="_blank">giving the webserver write access to the root directory</a>.';
// 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 '
- .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html#set-the-directory-permissions" target="_blank">giving the webserver write access to the config directory</a>.'
+ .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html'
+ .'#set-the-directory-permissions" target="_blank">giving the webserver write access to the config directory</a>.'
);
}
@@ -261,7 +285,8 @@ class OC_Util {
$errors[] = array(
'error' => "Can't write into apps directory",
'hint' => 'This can usually be fixed by '
- .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html#set-the-directory-permissions" target="_blank">giving the webserver write access to the apps directory</a> '
+ .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html'
+ .'#set-the-directory-permissions" target="_blank">giving the webserver write access to the apps directory</a> '
.'or disabling the appstore in the config file.'
);
}
@@ -276,94 +301,131 @@ class OC_Util {
$errors[] = array(
'error' => "Can't create data directory (".$CONFIG_DATADIRECTORY.")",
'hint' => 'This can usually be fixed by '
- .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html#set-the-directory-permissions" target="_blank">giving the webserver write access to the root directory</a>.'
+ .'<a href="' . $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html'
+ .'#set-the-directory-permissions" target="_blank">giving the webserver write access to the root directory</a>.'
);
}
} else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
- $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud',
- 'hint'=>$permissionsHint);
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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' => 'Please ask your server administrator to install the module.');
- $web_server_restart =true;
+ $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' => 'Please ask your server administrator to install the module.');
- $web_server_restart =true;
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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.',
+ 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.');
- $web_server_restart=true;
+ .' 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'=>'Please ask your server administrator to install the module.');
- $web_server_restart=true;
+ $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.');
- $web_server_restart=true;
+ $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.');
- $web_server_restart=true;
+ $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($web_server_restart) {
- $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.');
+ 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
@@ -381,39 +443,49 @@ 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;
}
-
+
/**
- * Check for correct file permissions of data directory
- * @return array arrays with error messages and hints
- */
+ * @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 (stristr(PHP_OS, 'WIN')) {
+ 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.';
- $prems = substr(decoct(@fileperms($dataDirectory)), -3);
- if (substr($prems, -1) != '0') {
+ $perms = substr(decoct(@fileperms($dataDirectory)), -3);
+ if (substr($perms, -1) != '0') {
OC_Helper::chmodr($dataDirectory, 0770);
clearstatcache();
- $prems = substr(decoct(@fileperms($dataDirectory)), -3);
- if (substr($prems, 2, 1) != '0') {
- $errors[] = array('error' => 'Data directory ('.$dataDirectory.') is readable for other users',
- 'hint' => $permissionsModHint);
+ $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 ) {
@@ -427,17 +499,19 @@ class OC_Util {
$parameters['user_autofocus'] = true;
}
if (isset($_REQUEST['redirect_url'])) {
- $redirect_url = $_REQUEST['redirect_url'];
- $parameters['redirect_url'] = urlencode($redirect_url);
+ $redirectUrl = $_REQUEST['redirect_url'];
+ $parameters['redirect_url'] = urlencode($redirectUrl);
}
$parameters['alt_login'] = OC_App::getAlternativeLogIns();
+ $parameters['rememberLoginAllowed'] = self::rememberLoginAllowed();
OC_Template::printGuestPage("", "login", $parameters);
}
/**
- * Check if the app is enabled, redirects to home if not
+ * @brief Check if the app is enabled, redirects to home if not
+ * @return void
*/
public static function checkAppEnabled($app) {
if( !OC_App::isEnabled($app)) {
@@ -449,18 +523,21 @@ class OC_Util {
/**
* 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('redirect_url' => OC_Request::requestUri())));
+ array('redirectUrl' => OC_Request::requestUri())
+ ));
exit();
}
}
/**
- * Check if the user is a admin, redirects to home if not
+ * @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())) {
@@ -470,7 +547,28 @@ class OC_Util {
}
/**
- * Check if the user is a subadmin, redirects to home if not
+ * Check if it is allowed to remember login.
+ *
+ * @note Every app can set 'rememberlogin' to 'false' to disable the remember login feature
+ *
+ * @return bool
+ */
+ public static function rememberLoginAllowed() {
+
+ $apps = OC_App::getEnabledApps();
+
+ foreach ($apps as $app) {
+ $appInfo = OC_App::getAppInfo($app);
+ if (isset($appInfo['rememberlogin']) && $appInfo['rememberlogin'] === 'false') {
+ return false;
+ }
+
+ }
+ return true;
+ }
+
+ /**
+ * @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() {
@@ -482,7 +580,8 @@ class OC_Util {
}
/**
- * Redirect to the user default page
+ * @brief Redirect to the user default page
+ * @return void
*/
public static function redirectToDefaultPage() {
if(isset($_REQUEST['redirect_url'])) {
@@ -490,13 +589,11 @@ class OC_Util {
}
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 {
+ } else {
+ $defaultPage = OC_Appconfig::getValue('core', 'defaultpage');
+ if ($defaultPage) {
+ $location = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/'.$defaultPage);
+ } else {
$location = OC_Helper::linkToAbsolute( 'files', 'index.php' );
}
}
@@ -505,28 +602,28 @@ class OC_Util {
exit();
}
- /**
- * 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' . OC_Util::generate_random_bytes(10);
- OC_Config::setValue('instanceid', $id);
- }
- return $id;
- }
+ /**
+ * @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 piont in time when to
+ * 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
- * timespan coded here has expired.
+ * time span coded here has expired.
*/
public static $callLifespan = 3600; // 3600 secs = 1 hour
@@ -546,7 +643,7 @@ class OC_Util {
// Check if a token exists
if(!\OC::$session->exists('requesttoken')) {
// No valid token found, generate a new one.
- $requestToken = self::generate_random_bytes(20);
+ $requestToken = self::generateRandomBytes(20);
\OC::$session->set('requesttoken', $requestToken);
} else {
// Valid token already exists, send it
@@ -567,11 +664,11 @@ class OC_Util {
}
if(isset($_GET['requesttoken'])) {
- $token=$_GET['requesttoken'];
+ $token = $_GET['requesttoken'];
} elseif(isset($_POST['requesttoken'])) {
- $token=$_POST['requesttoken'];
+ $token = $_POST['requesttoken'];
} elseif(isset($_SERVER['HTTP_REQUESTTOKEN'])) {
- $token=$_SERVER['HTTP_REQUESTTOKEN'];
+ $token = $_SERVER['HTTP_REQUESTTOKEN'];
} else {
//no token found.
return false;
@@ -589,11 +686,12 @@ class OC_Util {
/**
* @brief Check an ajax get/post call if the request token is valid. exit if not.
- * Todo: Write howto
+ * @todo Write howto
+ * @return void
*/
public static function callCheck() {
if(!OC_Util::isCallRegistered()) {
- exit;
+ exit();
}
}
@@ -603,27 +701,28 @@ class OC_Util {
* 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 or array of strings
+ * @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 {
- $value = htmlentities((string)$value, ENT_QUOTES, 'UTF-8'); //Specify encoding for PHP<5.4
+ //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.
+ * 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);
@@ -632,48 +731,52 @@ class OC_Util {
}
/**
- * Check if the htaccess file is working by creating a test file in the data directory and trying to access via http
+ * @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() {
+ public static function isHtAccessWorking() {
// testdata
- $filename='/htaccesstest.txt';
- $testcontent='testcontent';
+ $fileName = '/htaccesstest.txt';
+ $testContent = 'testcontent';
// creating a test file
- $testfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$filename;
+ $testFile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$fileName;
- if(file_exists($testfile)) {// already running this test, possible recursive call
+ if(file_exists($testFile)) {// already running this test, possible recursive call
return false;
}
- $fp = @fopen($testfile, 'w');
- @fwrite($fp, $testcontent);
+ $fp = @fopen($testFile, 'w');
+ @fwrite($fp, $testContent);
@fclose($fp);
// accessing the file via http
- $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$filename);
+ $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$fileName);
$fp = @fopen($url, 'r');
$content=@fread($fp, 2048);
@fclose($fp);
// cleanup
- @unlink($testfile);
+ @unlink($testFile);
// does it work ?
- if($content==$testcontent) {
- return(false);
- }else{
- return(true);
+ if($content==$testContent) {
+ return false;
+ } else {
+ return true;
}
}
/**
- * we test if webDAV is working properly
- *
+ * @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 PROFIND and other verbs?
+ * 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)
*
@@ -686,12 +789,6 @@ class OC_Util {
'baseUri' => OC_Helper::linkToRemote('webdav'),
);
- // save the old timeout so that we can restore it later
- $old_timeout=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.
@@ -701,24 +798,22 @@ class OC_Util {
try {
// test PROPFIND
$client->propfind('', array('{DAV:}resourcetype'));
- } catch(\Sabre_DAV_Exception_NotAuthenticated $e) {
+ } catch (\Sabre_DAV_Exception_NotAuthenticated $e) {
$return = true;
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
OC_Log::write('core', 'isWebDAVWorking: NO - Reason: '.$e->getMessage(). ' ('.get_class($e).')', OC_Log::WARN);
$return = false;
}
- // restore the original timeout
- ini_set("default_socket_timeout", $old_timeout);
-
return $return;
}
/**
- * Check if the setlocal call doesn't work. This can happen if the right
+ * 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() {
+ public static function isSetLocaleWorking() {
// setlocale test is pointless on Windows
if (OC_Util::runningOnWindows() ) {
return true;
@@ -732,7 +827,7 @@ class OC_Util {
}
/**
- * Check if the PHP module fileinfo is loaded.
+ * @brief Check if the PHP module fileinfo is loaded.
* @return bool
*/
public static function fileInfoLoaded() {
@@ -740,7 +835,8 @@ class OC_Util {
}
/**
- * Check if the ownCloud server can connect to the internet
+ * @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
@@ -753,30 +849,29 @@ class OC_Util {
if ($connected) {
fclose($connected);
return true;
- }else{
-
+ } else {
// second try in case one server is down
$connected = @fsockopen("apps.owncloud.com", 80);
if ($connected) {
fclose($connected);
return true;
- }else{
+ } else {
return false;
}
-
}
-
}
-
+
/**
- * Check if the connection to the internet is disabled on purpose
+ * @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);
}
/**
- * clear all levels of output buffering
+ * @brief clear all levels of output buffering
+ * @return void
*/
public static function obEnd(){
while (ob_get_level()) {
@@ -786,47 +881,47 @@ class OC_Util {
/**
- * @brief Generates a cryptographical secure pseudorandom string
- * @param Int with the length of the random string
+ * @brief Generates a cryptographic secure pseudo-random string
+ * @param Int $length of the random string
* @return String
- * Please also update secureRNG_available if you change something here
+ * Please also update secureRNGAvailable if you change something here
*/
- public static function generate_random_bytes($length = 30) {
-
+ public static function generateRandomBytes($length = 30) {
// Try to use openssl_random_pseudo_bytes
- if(function_exists('openssl_random_pseudo_bytes')) {
- $pseudo_byte = bin2hex(openssl_random_pseudo_bytes($length, $strong));
+ if (function_exists('openssl_random_pseudo_bytes')) {
+ $pseudoByte = bin2hex(openssl_random_pseudo_bytes($length, $strong));
if($strong == true) {
- return substr($pseudo_byte, 0, $length); // Truncate it to match the length
+ return substr($pseudoByte, 0, $length); // Truncate it to match the length
}
}
// Try to use /dev/urandom
- $fp = @file_get_contents('/dev/urandom', false, null, 0, $length);
- if ($fp !== false) {
- $string = substr(bin2hex($fp), 0, $length);
- return $string;
+ 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;
- $pseudo_byte = "";
+ $pseudoByte = "";
// Select some random characters
for ($i = 0; $i < $length; $i++) {
- $pseudo_byte .= $characters[mt_rand(0, $charactersLength)];
+ $pseudoByte .= $characters[mt_rand(0, $charactersLength)];
}
- return $pseudo_byte;
+ return $pseudoByte;
}
/**
* @brief Checks if a secure random number generator is available
* @return bool
*/
- public static function secureRNG_available() {
-
+ public static function secureRNGAvailable() {
// Check openssl_random_pseudo_bytes
if(function_exists('openssl_random_pseudo_bytes')) {
openssl_random_pseudo_bytes(1, $strong);
@@ -836,9 +931,11 @@ class OC_Util {
}
// Check /dev/urandom
- $fp = @file_get_contents('/dev/urandom', false, null, 0, 1);
- if ($fp !== false) {
- return true;
+ if (!self::runningOnWindows()) {
+ $fp = @file_get_contents('/dev/urandom', false, null, 0, 1);
+ if ($fp !== false) {
+ return true;
+ }
}
return false;
@@ -851,11 +948,8 @@ class OC_Util {
* 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')) {
-
+ if (function_exists('curl_init')) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_HEADER, 0);
@@ -866,10 +960,10 @@ class OC_Util {
curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
curl_setopt($curl, CURLOPT_USERAGENT, "ownCloud Server Crawler");
- if(OC_Config::getValue('proxy', '')<>'') {
+ if(OC_Config::getValue('proxy', '') != '') {
curl_setopt($curl, CURLOPT_PROXY, OC_Config::getValue('proxy'));
}
- if(OC_Config::getValue('proxyuserpwd', '')<>'') {
+ if(OC_Config::getValue('proxyuserpwd', '') != '') {
curl_setopt($curl, CURLOPT_PROXYUSERPWD, OC_Config::getValue('proxyuserpwd'));
}
$data = curl_exec($curl);
@@ -878,7 +972,7 @@ class OC_Util {
} else {
$contextArray = null;
- if(OC_Config::getValue('proxy', '')<>'') {
+ if(OC_Config::getValue('proxy', '') != '') {
$contextArray = array(
'http' => array(
'timeout' => 10,
@@ -893,11 +987,10 @@ class OC_Util {
);
}
-
$ctx = stream_context_create(
$contextArray
);
- $data=@file_get_contents($url, 0, $ctx);
+ $data = @file_get_contents($url, 0, $ctx);
}
return $data;
@@ -910,7 +1003,6 @@ class OC_Util {
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
@@ -920,20 +1012,19 @@ class OC_Util {
$theme = OC_Config::getValue("theme", '');
if($theme === '') {
-
if(is_dir(OC::$SERVERROOT . '/themes/default')) {
$theme = 'default';
}
-
}
return $theme;
}
/**
- * Clear the opcode cache if one exists
+ * @brief Clear the opcode cache if one exists
* This is necessary for writing to the config file
- * in case the opcode cache doesn't revalidate files
+ * in case the opcode cache does not re-validate files
+ * @return void
*/
public static function clearOpcodeCache() {
// APC
@@ -972,8 +1063,10 @@ class OC_Util {
return $value;
}
- public static function basename($file)
- {
+ /**
+ * @return string
+ */
+ public static function basename($file) {
$file = rtrim($file, '/');
$t = explode('/', $file);
return array_pop($t);
diff --git a/lib/vcategories.php b/lib/vcategories.php
deleted file mode 100644
index 84036958359..00000000000
--- a/lib/vcategories.php
+++ /dev/null
@@ -1,821 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Thomas Tanghus
-* @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
-* @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 <http://www.gnu.org/licenses/>.
-*
-*/
-
-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 = '_$!<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)) {
- $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)) {
- $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) {
- 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) {
- $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)) {
- 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;
- $categoryid = (is_string($category) && !is_numeric($category))
- ? $this->array_searchi($category, $this->categories)
- : $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);
- }
-
- 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));
- }
-}