summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2013-07-16 15:22:47 +0200
committerRobin Appelman <icewind@owncloud.com>2013-07-16 15:22:47 +0200
commit0ae8eb4f5e05d9e3c5a22a7278ee104edd95fdf4 (patch)
tree47d53cb6b0deb37aa31a41342c7c73f1f0805ba0 /lib
parent5418c98a81caba2da00b2e81fb56fe373737a7c8 (diff)
parentd673d8c25310f0ea73927b8b252e6823a11087f4 (diff)
downloadnextcloud-server-0ae8eb4f5e05d9e3c5a22a7278ee104edd95fdf4.tar.gz
nextcloud-server-0ae8eb4f5e05d9e3c5a22a7278ee104edd95fdf4.zip
Merge branch 'master' into cache
Diffstat (limited to 'lib')
-rw-r--r--lib/MDB2/Driver/sqlite3.php6
-rw-r--r--lib/api.php18
-rw-r--r--lib/app.php25
-rw-r--r--lib/archive.php6
-rw-r--r--lib/archive/tar.php2
-rw-r--r--lib/archive/zip.php2
-rw-r--r--lib/autoloader.php126
-rw-r--r--lib/backgroundjob/job.php49
-rw-r--r--lib/backgroundjob/joblist.php172
-rw-r--r--lib/backgroundjob/legacy/queuedjob.php18
-rw-r--r--lib/backgroundjob/legacy/regularjob.php15
-rw-r--r--lib/backgroundjob/queuedjob.php28
-rw-r--r--lib/backgroundjob/queuedtask.php105
-rw-r--r--lib/backgroundjob/regulartask.php52
-rw-r--r--lib/backgroundjob/timedjob.php41
-rw-r--r--lib/backgroundjob/worker.php118
-rw-r--r--lib/base.php196
-rw-r--r--lib/cache/file.php1
-rw-r--r--lib/cache/fileglobalgc.php8
-rw-r--r--lib/config.php143
-rw-r--r--lib/connector/sabre/directory.php15
-rw-r--r--lib/connector/sabre/file.php15
-rw-r--r--lib/connector/sabre/locks.php58
-rw-r--r--lib/connector/sabre/maintenanceplugin.php3
-rw-r--r--lib/connector/sabre/node.php6
-rw-r--r--lib/db.php468
-rw-r--r--lib/defaults.php125
-rw-r--r--lib/eventsource.php9
-rw-r--r--lib/files.php39
-rw-r--r--lib/files/cache/backgroundwatcher.php104
-rw-r--r--lib/files/cache/cache.php218
-rw-r--r--lib/files/cache/legacy.php69
-rw-r--r--lib/files/cache/permissions.php63
-rw-r--r--lib/files/cache/scanner.php132
-rw-r--r--lib/files/cache/storage.php60
-rw-r--r--lib/files/cache/updater.php37
-rw-r--r--lib/files/cache/upgrade.php80
-rw-r--r--lib/files/cache/watcher.php2
-rw-r--r--lib/files/filesystem.php122
-rw-r--r--lib/files/mapper.php59
-rw-r--r--lib/files/mount.php216
-rw-r--r--lib/files/mount/manager.php120
-rw-r--r--lib/files/mount/mount.php141
-rw-r--r--lib/files/storage/common.php52
-rw-r--r--lib/files/storage/loader.php38
-rw-r--r--lib/files/storage/local.php454
-rw-r--r--lib/files/storage/mappedlocal.php26
-rw-r--r--lib/files/storage/storage.php283
-rw-r--r--lib/files/storage/wrapper/wrapper.php427
-rw-r--r--lib/files/stream/staticstream.php55
-rw-r--r--lib/files/view.php137
-rw-r--r--lib/helper.php122
-rw-r--r--lib/hintexception.php27
-rw-r--r--lib/hooks/basicemitter.php89
-rw-r--r--lib/hooks/emitter.php32
-rw-r--r--lib/hooks/forwardingemitter.php50
-rw-r--r--lib/hooks/legacyemitter.php16
-rw-r--r--lib/hooks/publicemitter.php20
-rw-r--r--lib/installer.php6
-rw-r--r--lib/json.php2
-rw-r--r--lib/l10n.php20
-rw-r--r--lib/l10n/af_ZA.php3
-rw-r--r--lib/l10n/ar.php44
-rw-r--r--lib/l10n/bg_BG.php19
-rw-r--r--lib/l10n/bn_BD.php11
-rw-r--r--lib/l10n/ca.php19
-rw-r--r--lib/l10n/cs_CZ.php23
-rw-r--r--lib/l10n/cy_GB.php52
-rw-r--r--lib/l10n/da.php27
-rw-r--r--lib/l10n/de.php25
-rw-r--r--lib/l10n/de_DE.php23
-rw-r--r--lib/l10n/el.php23
-rw-r--r--lib/l10n/en@pirate.php3
-rw-r--r--lib/l10n/eo.php29
-rw-r--r--lib/l10n/es.php21
-rw-r--r--lib/l10n/es_AR.php29
-rw-r--r--lib/l10n/et_EE.php30
-rw-r--r--lib/l10n/eu.php26
-rw-r--r--lib/l10n/fa.php24
-rw-r--r--lib/l10n/fi.php3
-rw-r--r--lib/l10n/fi_FI.php20
-rw-r--r--lib/l10n/fr.php21
-rw-r--r--lib/l10n/gl.php21
-rw-r--r--lib/l10n/he.php6
-rw-r--r--lib/l10n/hr.php3
-rw-r--r--lib/l10n/hu_HU.php23
-rw-r--r--lib/l10n/ia.php3
-rw-r--r--lib/l10n/id.php58
-rw-r--r--lib/l10n/is.php4
-rw-r--r--lib/l10n/it.php23
-rw-r--r--lib/l10n/ja_JP.php29
-rw-r--r--lib/l10n/ka_GE.php36
-rw-r--r--lib/l10n/ko.php6
-rw-r--r--lib/l10n/ku_IQ.php5
-rw-r--r--lib/l10n/lb.php8
-rw-r--r--lib/l10n/lt_LT.php18
-rw-r--r--lib/l10n/lv.php16
-rw-r--r--lib/l10n/mk.php6
-rw-r--r--lib/l10n/ms_MY.php3
-rw-r--r--lib/l10n/my_MM.php4
-rw-r--r--lib/l10n/nb_NO.php10
-rw-r--r--lib/l10n/nl.php19
-rw-r--r--lib/l10n/nn_NO.php15
-rw-r--r--lib/l10n/oc.php5
-rw-r--r--lib/l10n/pl.php29
-rw-r--r--lib/l10n/pt_BR.php17
-rw-r--r--lib/l10n/pt_PT.php25
-rw-r--r--lib/l10n/ro.php6
-rw-r--r--lib/l10n/ru.php23
-rw-r--r--lib/l10n/ru_RU.php35
-rw-r--r--lib/l10n/si_LK.php8
-rw-r--r--lib/l10n/sk_SK.php19
-rw-r--r--lib/l10n/sl.php27
-rw-r--r--lib/l10n/sq.php52
-rw-r--r--lib/l10n/sr.php8
-rw-r--r--lib/l10n/sr@latin.php2
-rw-r--r--lib/l10n/sv.php26
-rw-r--r--lib/l10n/ta_LK.php6
-rw-r--r--lib/l10n/te.php13
-rw-r--r--lib/l10n/th_TH.php10
-rw-r--r--lib/l10n/tr.php25
-rw-r--r--lib/l10n/ug.php19
-rw-r--r--lib/l10n/uk.php16
-rw-r--r--lib/l10n/ur_PK.php3
-rw-r--r--lib/l10n/vi.php8
-rw-r--r--lib/l10n/zh_CN.GB2312.php9
-rw-r--r--lib/l10n/zh_CN.php23
-rw-r--r--lib/l10n/zh_TW.php28
-rw-r--r--lib/legacy/config.php103
-rw-r--r--lib/legacy/filesystem.php (renamed from lib/filesystem.php)0
-rw-r--r--lib/legacy/filesystemview.php (renamed from lib/filesystemview.php)0
-rw-r--r--lib/legacy/log.php50
-rw-r--r--lib/legacy/updater.php14
-rw-r--r--lib/log.php153
-rw-r--r--lib/log/errorhandler.php54
-rw-r--r--lib/log/owncloud.php3
-rw-r--r--lib/mail.php7
-rw-r--r--lib/mimetypes.list.php12
-rw-r--r--lib/ocs/result.php2
-rw-r--r--lib/preferences.php2
-rw-r--r--lib/public/backgroundjob.php169
-rw-r--r--lib/public/config.php27
-rw-r--r--lib/public/defaults.php108
-rw-r--r--lib/public/files.php10
-rw-r--r--lib/public/share.php246
-rw-r--r--lib/public/util.php15
-rwxr-xr-xlib/request.php35
-rw-r--r--lib/response.php4
-rw-r--r--lib/session/internal.php39
-rw-r--r--lib/session/memory.php63
-rw-r--r--lib/session/session.php79
-rw-r--r--lib/setup.php813
-rw-r--r--lib/setup/abstractdatabase.php50
-rw-r--r--lib/setup/mssql.php182
-rw-r--r--lib/setup/mysql.php95
-rw-r--r--lib/setup/oci.php210
-rw-r--r--lib/setup/postgresql.php140
-rw-r--r--lib/setup/sqlite.php26
-rw-r--r--lib/template.php41
-rw-r--r--lib/templatelayout.php92
-rw-r--r--lib/updater.php181
-rw-r--r--lib/user.php545
-rw-r--r--lib/user/backend.php22
-rw-r--r--lib/user/database.php10
-rw-r--r--lib/user/dummy.php144
-rw-r--r--lib/user/manager.php228
-rw-r--r--lib/user/session.php173
-rw-r--r--lib/user/user.php197
-rwxr-xr-xlib/util.php212
-rw-r--r--lib/vcategories.php55
-rw-r--r--lib/vobject/compoundproperty.php70
-rw-r--r--lib/vobject/stringproperty.php80
172 files changed, 7688 insertions, 3454 deletions
diff --git a/lib/MDB2/Driver/sqlite3.php b/lib/MDB2/Driver/sqlite3.php
index 8f057cfb6e8..693ceffa01c 100644
--- a/lib/MDB2/Driver/sqlite3.php
+++ b/lib/MDB2/Driver/sqlite3.php
@@ -387,7 +387,7 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
$php_errormsg = '';
$this->connection = new SQLite3($database_file);
if(is_callable(array($this->connection, 'busyTimeout'))) {//busy timout is only available in php>=5.3
- $this->connection->busyTimeout(100);
+ $this->connection->busyTimeout(60000);
}
$this->_lasterror = $this->connection->lastErrorMsg();
if (!$this->connection) {
@@ -892,10 +892,10 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
$connection = $this->getConnection();
if (PEAR::isError($connection)) {
return $connection;
- }
+ }
$statement =$this->connection->prepare($query);
if (!$statement) {
- return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
'unable to prepare statement: '.$query);
}
diff --git a/lib/api.php b/lib/api.php
index 8d6bbb7cc09..31f3f968d9b 100644
--- a/lib/api.php
+++ b/lib/api.php
@@ -67,6 +67,8 @@ class OC_API {
OC::getRouter()->useCollection('ocs');
OC::getRouter()->create($name, $url)
->method($method)
+ ->defaults($defaults)
+ ->requirements($requirements)
->action('OC_API', 'call');
self::$actions[$name] = array();
}
@@ -89,7 +91,7 @@ class OC_API {
$responses = array();
foreach(self::$actions[$name] as $action) {
// Check authentication and availability
- if(!self::isAuthorised(self::$actions[$name])) {
+ if(!self::isAuthorised($action)) {
$responses[] = array(
'app' => $action['app'],
'response' => new OC_OCS_Result(null, OC_API::RESPOND_UNAUTHORISED, 'Unauthorised'),
@@ -111,9 +113,11 @@ class OC_API {
}
$response = self::mergeResponses($responses);
$formats = array('json', 'xml');
+
$format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml';
- self::respond($response);
OC_User::logout();
+
+ self::respond($response, $format);
}
/**
@@ -147,6 +151,7 @@ class OC_API {
}
}
}
+
// Remove any error responses if there is one shipped response that succeeded
if(!empty($shipped['succeeded'])) {
$responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']);
@@ -155,16 +160,19 @@ class OC_API {
// They may have failed for different reasons (different status codes)
// Which reponse code should we return?
// Maybe any that are not OC_API::RESPOND_SERVER_ERROR
- $response = $shipped['failed'][0];
+ $response = reset($shipped['failed']);
return $response;
- } else {
+ } elseif(!empty($thirdparty['failed'])) {
// Return the third party failure result
- $response = $thirdparty['failed'][0];
+ $response = reset($thirdparty['failed']);
return $response;
+ } else {
+ $responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']);
}
// Merge the successful responses
$meta = array();
$data = array();
+
foreach($responses as $app => $response) {
if(OC_App::isShipped($app)) {
$data = array_merge_recursive($response->getData(), $data);
diff --git a/lib/app.php b/lib/app.php
index 55b4543ec9f..baacf508d8e 100644
--- a/lib/app.php
+++ b/lib/app.php
@@ -172,9 +172,18 @@ class OC_App{
return array();
}
$apps=array('files');
- $query = OC_DB::prepare( 'SELECT `appid` FROM `*PREFIX*appconfig`'
- .' WHERE `configkey` = \'enabled\' AND `configvalue`=\'yes\'' );
+ $sql = 'SELECT `appid` FROM `*PREFIX*appconfig`'
+ .' WHERE `configkey` = \'enabled\' AND `configvalue`=\'yes\'';
+ if (OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') {
+ //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
+ $sql = 'SELECT `appid` FROM `*PREFIX*appconfig`'
+ .' WHERE `configkey` = \'enabled\' AND to_char(`configvalue`)=\'yes\'';
+ }
+ $query = OC_DB::prepare( $sql );
$result=$query->execute();
+ if( \OC_DB::isError($result)) {
+ throw new DatabaseException($result->getMessage(), $query);
+ }
while($row=$result->fetchRow()) {
if(array_search($row['appid'], $apps)===false) {
$apps[]=$row['appid'];
@@ -250,6 +259,7 @@ class OC_App{
*/
public static function disable( $app ) {
// check if app is a shipped app or not. if not delete
+ \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
OC_Appconfig::setValue( $app, 'enabled', 'no' );
// check if app is a shipped app or not. if not delete
@@ -340,7 +350,8 @@ class OC_App{
$settings = array();
// by default, settings only contain the help menu
- if(OC_Config::getValue('knowledgebaseenabled', true)==true) {
+ if(OC_Util::getEditionString() === '' &&
+ OC_Config::getValue('knowledgebaseenabled', true)==true) {
$settings = array(
array(
"id" => "help",
@@ -413,7 +424,7 @@ class OC_App{
return $navigation;
}
- /// This is private as well. It simply works, so don't ask for more details
+ // This is private as well. It simply works, so don't ask for more details
private static function proceedNavigation( $list ) {
foreach( $list as &$naventry ) {
if( $naventry['id'] == self::$activeapp ) {
@@ -462,7 +473,7 @@ class OC_App{
}
/**
* Get the directory for the given app.
- * If the app is defined in multiple directory, the first one is taken. (false if not found)
+ * If the app is defined in multiple directories, the first one is taken. (false if not found)
*/
public static function getAppPath($appid) {
if( ($dir = self::findAppInDirectories($appid)) != false) {
@@ -473,7 +484,7 @@ class OC_App{
/**
* Get the path for the given app on the access
- * If the app is defined in multiple directory, the first one is taken. (false if not found)
+ * If the app is defined in multiple directories, the first one is taken. (false if not found)
*/
public static function getAppWebPath($appid) {
if( ($dir = self::findAppInDirectories($appid)) != false) {
@@ -807,7 +818,7 @@ class OC_App{
}
/**
- * check if the app need updating and update when needed
+ * check if the app needs updating and update when needed
*/
public static function checkUpgrade($app) {
if (in_array($app, self::$checkedApps)) {
diff --git a/lib/archive.php b/lib/archive.php
index 61239c82076..70615db714e 100644
--- a/lib/archive.php
+++ b/lib/archive.php
@@ -8,7 +8,7 @@
abstract class OC_Archive{
/**
- * open any of the supporeted archive types
+ * open any of the supported archive types
* @param string path
* @return OC_Archive
*/
@@ -69,7 +69,7 @@ abstract class OC_Archive{
*/
abstract function getFolder($path);
/**
- *get all files in the archive
+ * get all files in the archive
* @return array
*/
abstract function getFiles();
@@ -113,7 +113,7 @@ abstract class OC_Archive{
*/
abstract function getStream($path, $mode);
/**
- * add a folder and all it's content
+ * add a folder and all its content
* @param string $path
* @param string source
* @return bool
diff --git a/lib/archive/tar.php b/lib/archive/tar.php
index e7c81389619..a1c0535b1c3 100644
--- a/lib/archive/tar.php
+++ b/lib/archive/tar.php
@@ -182,7 +182,7 @@ class OC_Archive_TAR extends OC_Archive{
return $folderContent;
}
/**
- *get all files in the archive
+ * get all files in the archive
* @return array
*/
function getFiles() {
diff --git a/lib/archive/zip.php b/lib/archive/zip.php
index 8e31795ded1..8a866716a79 100644
--- a/lib/archive/zip.php
+++ b/lib/archive/zip.php
@@ -94,7 +94,7 @@ class OC_Archive_ZIP extends OC_Archive{
return $folderContent;
}
/**
- *get all files in the archive
+ * get all files in the archive
* @return array
*/
function getFiles() {
diff --git a/lib/autoloader.php b/lib/autoloader.php
new file mode 100644
index 00000000000..21170639092
--- /dev/null
+++ b/lib/autoloader.php
@@ -0,0 +1,126 @@
+<?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;
+
+class Autoloader {
+ private $useGlobalClassPath = true;
+
+ private $prefixPaths = array();
+
+ private $classPaths = array();
+
+ /**
+ * Add a custom prefix to the autoloader
+ *
+ * @param string $prefix
+ * @param string $path
+ */
+ public function registerPrefix($prefix, $path) {
+ $this->prefixPaths[$prefix] = $path;
+ }
+
+ /**
+ * Add a custom classpath to the autoloader
+ *
+ * @param string $class
+ * @param string $path
+ */
+ public function registerClass($class, $path) {
+ $this->classPaths[$class] = $path;
+ }
+
+ /**
+ * disable the usage of the global classpath \OC::$CLASSPATH
+ */
+ public function disableGlobalClassPath() {
+ $this->useGlobalClassPath = false;
+ }
+
+ /**
+ * enable the usage of the global classpath \OC::$CLASSPATH
+ */
+ public function enableGlobalClassPath() {
+ $this->useGlobalClassPath = true;
+ }
+
+ /**
+ * get the possible paths for a class
+ *
+ * @param string $class
+ * @return array|bool an array of possible paths or false if the class is not part of ownCloud
+ */
+ public function findClass($class) {
+ $class = trim($class, '\\');
+
+ $paths = array();
+ if (array_key_exists($class, $this->classPaths)) {
+ $paths[] = $this->classPaths[$class];
+ } else if ($this->useGlobalClassPath and array_key_exists($class, \OC::$CLASSPATH)) {
+ $paths[] = \OC::$CLASSPATH[$class];
+ /**
+ * @TODO: Remove this when necessary
+ * Remove "apps/" from inclusion path for smooth migration to mutli app dir
+ */
+ if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) {
+ \OC_Log::write('core', 'include path for class "' . $class . '" starts with "apps/"', \OC_Log::DEBUG);
+ $paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]);
+ }
+ } elseif (strpos($class, 'OC_') === 0) {
+ // first check for legacy classes if underscores are used
+ $paths[] = 'legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
+ $paths[] = strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
+ } elseif (strpos($class, 'OC\\') === 0) {
+ $paths[] = strtolower(str_replace('\\', '/', substr($class, 3)) . '.php');
+ } elseif (strpos($class, 'OCP\\') === 0) {
+ $paths[] = 'public/' . strtolower(str_replace('\\', '/', substr($class, 4)) . '.php');
+ } elseif (strpos($class, 'OCA\\') === 0) {
+ list(, $app, $rest) = explode('\\', $class, 3);
+ $app = strtolower($app);
+ foreach (\OC::$APPSROOTS as $appDir) {
+ if (stream_resolve_include_path($appDir['path'] . '/' . $app)) {
+ $paths[] = $appDir['path'] . '/' . $app . '/' . strtolower(str_replace('\\', '/', $rest) . '.php');
+ // If not found in the root of the app directory, insert '/lib' after app id and try again.
+ $paths[] = $appDir['path'] . '/' . $app . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php');
+ }
+ }
+ } elseif (strpos($class, 'Test_') === 0) {
+ $paths[] = 'tests/lib/' . strtolower(str_replace('_', '/', substr($class, 5)) . '.php');
+ } elseif (strpos($class, 'Test\\') === 0) {
+ $paths[] = 'tests/lib/' . strtolower(str_replace('\\', '/', substr($class, 5)) . '.php');
+ } else {
+ foreach ($this->prefixPaths as $prefix => $dir) {
+ if (0 === strpos($class, $prefix)) {
+ $path = str_replace('\\', '/', $class) . '.php';
+ $path = str_replace('_', '/', $path);
+ $paths[] = $dir . '/' . $path;
+ }
+ }
+ }
+ return $paths;
+ }
+
+ /**
+ * Load the specified class
+ *
+ * @param string $class
+ * @return bool
+ */
+ public function load($class) {
+ $paths = $this->findClass($class);
+
+ if (is_array($paths)) {
+ foreach ($paths as $path) {
+ if ($fullPath = stream_resolve_include_path($path)) {
+ require_once $fullPath;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/lib/backgroundjob/job.php b/lib/backgroundjob/job.php
new file mode 100644
index 00000000000..49fbffbd684
--- /dev/null
+++ b/lib/backgroundjob/job.php
@@ -0,0 +1,49 @@
+<?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\BackgroundJob;
+
+abstract class Job {
+ protected $id;
+ protected $lastRun;
+ protected $argument;
+
+ /**
+ * @param JobList $jobList
+ */
+ public function execute($jobList) {
+ $jobList->setLastRun($this);
+ $this->run($this->argument);
+ }
+
+ abstract protected function run($argument);
+
+ public function setId($id) {
+ $this->id = $id;
+ }
+
+ public function setLastRun($lastRun) {
+ $this->lastRun = $lastRun;
+ }
+
+ public function setArgument($argument) {
+ $this->argument = $argument;
+ }
+
+ public function getId() {
+ return $this->id;
+ }
+
+ public function getLastRun() {
+ return $this->lastRun;
+ }
+
+ public function getArgument() {
+ return $this->argument;
+ }
+}
diff --git a/lib/backgroundjob/joblist.php b/lib/backgroundjob/joblist.php
new file mode 100644
index 00000000000..cc803dd9b5f
--- /dev/null
+++ b/lib/backgroundjob/joblist.php
@@ -0,0 +1,172 @@
+<?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\BackgroundJob;
+
+/**
+ * Class QueuedJob
+ *
+ * create a background job that is to be executed once
+ *
+ * @package OC\BackgroundJob
+ */
+class JobList {
+ /**
+ * @param Job|string $job
+ * @param mixed $argument
+ */
+ public function add($job, $argument = null) {
+ if (!$this->has($job, $argument)) {
+ if ($job instanceof Job) {
+ $class = get_class($job);
+ } else {
+ $class = $job;
+ }
+ $argument = json_encode($argument);
+ $query = \OC_DB::prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)');
+ $query->execute(array($class, $argument));
+ }
+ }
+
+ /**
+ * @param Job|string $job
+ * @param mixed $argument
+ */
+ public function remove($job, $argument = null) {
+ if ($job instanceof Job) {
+ $class = get_class($job);
+ } else {
+ $class = $job;
+ }
+ if (!is_null($argument)) {
+ $argument = json_encode($argument);
+ $query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
+ $query->execute(array($class, $argument));
+ } else {
+ $query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?');
+ $query->execute(array($class));
+ }
+ }
+
+ /**
+ * check if a job is in the list
+ *
+ * @param $job
+ * @param mixed $argument
+ * @return bool
+ */
+ public function has($job, $argument) {
+ if ($job instanceof Job) {
+ $class = get_class($job);
+ } else {
+ $class = $job;
+ }
+ $argument = json_encode($argument);
+ $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
+ $result = $query->execute(array($class, $argument));
+ return (bool)$result->fetchRow();
+ }
+
+ /**
+ * get all jobs in the list
+ *
+ * @return Job[]
+ */
+ public function getAll() {
+ $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`');
+ $result = $query->execute();
+ $jobs = array();
+ while ($row = $result->fetchRow()) {
+ $jobs[] = $this->buildJob($row);
+ }
+ return $jobs;
+ }
+
+ /**
+ * get the next job in the list
+ *
+ * @return Job
+ */
+ public function getNext() {
+ $lastId = $this->getLastJob();
+ $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1);
+ $result = $query->execute(array($lastId));
+ if ($row = $result->fetchRow()) {
+ return $this->buildJob($row);
+ } else {
+ //begin at the start of the queue
+ $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1);
+ $result = $query->execute();
+ if ($row = $result->fetchRow()) {
+ return $this->buildJob($row);
+ } else {
+ return null; //empty job list
+ }
+ }
+ }
+
+ /**
+ * @param int $id
+ * @return Job
+ */
+ public function getById($id) {
+ $query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?');
+ $result = $query->execute(array($id));
+ if ($row = $result->fetchRow()) {
+ return $this->buildJob($row);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * get the job object from a row in the db
+ *
+ * @param array $row
+ * @return Job
+ */
+ private function buildJob($row) {
+ $class = $row['class'];
+ /**
+ * @var Job $job
+ */
+ $job = new $class();
+ $job->setId($row['id']);
+ $job->setLastRun($row['last_run']);
+ $job->setArgument(json_decode($row['argument']));
+ return $job;
+ }
+
+ /**
+ * set the job that was last ran
+ *
+ * @param Job $job
+ */
+ public function setLastJob($job) {
+ \OC_Appconfig::setValue('backgroundjob', 'lastjob', $job->getId());
+ }
+
+ /**
+ * get the id of the last ran job
+ *
+ * @return int
+ */
+ public function getLastJob() {
+ return \OC_Appconfig::getValue('backgroundjob', 'lastjob', 0);
+ }
+
+ /**
+ * set the lastRun of $job to now
+ *
+ * @param Job $job
+ */
+ public function setLastRun($job) {
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?');
+ $query->execute(array(time(), $job->getId()));
+ }
+}
diff --git a/lib/backgroundjob/legacy/queuedjob.php b/lib/backgroundjob/legacy/queuedjob.php
new file mode 100644
index 00000000000..2bc001103b8
--- /dev/null
+++ b/lib/backgroundjob/legacy/queuedjob.php
@@ -0,0 +1,18 @@
+<?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\BackgroundJob\Legacy;
+
+class QueuedJob extends \OC\BackgroundJob\QueuedJob {
+ public function run($argument) {
+ $class = $argument['klass'];
+ $method = $argument['method'];
+ $parameters = $argument['parameters'];
+ call_user_func(array($class, $method), $parameters);
+ }
+}
diff --git a/lib/backgroundjob/legacy/regularjob.php b/lib/backgroundjob/legacy/regularjob.php
new file mode 100644
index 00000000000..d4cfa348cea
--- /dev/null
+++ b/lib/backgroundjob/legacy/regularjob.php
@@ -0,0 +1,15 @@
+<?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\BackgroundJob\Legacy;
+
+class RegularJob extends \OC\BackgroundJob\Job {
+ public function run($argument) {
+ call_user_func($argument);
+ }
+}
diff --git a/lib/backgroundjob/queuedjob.php b/lib/backgroundjob/queuedjob.php
new file mode 100644
index 00000000000..1714182820d
--- /dev/null
+++ b/lib/backgroundjob/queuedjob.php
@@ -0,0 +1,28 @@
+<?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\BackgroundJob;
+
+/**
+ * Class QueuedJob
+ *
+ * create a background job that is to be executed once
+ *
+ * @package OC\BackgroundJob
+ */
+abstract class QueuedJob extends Job {
+ /**
+ * run the job, then remove it from the joblist
+ *
+ * @param JobList $jobList
+ */
+ public function execute($jobList) {
+ $jobList->remove($this);
+ $this->run($this->argument);
+ }
+}
diff --git a/lib/backgroundjob/queuedtask.php b/lib/backgroundjob/queuedtask.php
deleted file mode 100644
index b2ce6f39ed8..00000000000
--- a/lib/backgroundjob/queuedtask.php
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* 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 manages our queued tasks.
- */
-class OC_BackgroundJob_QueuedTask{
- /**
- * @brief Gets one queued task
- * @param $id ID of the task
- * @return associative array
- */
- public static function find( $id ) {
- $stmt = OC_DB::prepare( 'SELECT * FROM `*PREFIX*queuedtasks` WHERE `id` = ?' );
- $result = $stmt->execute(array($id));
- return $result->fetchRow();
- }
-
- /**
- * @brief Gets all queued tasks
- * @return array with associative arrays
- */
- public static function all() {
- // Array for objects
- $return = array();
-
- // Get Data
- $stmt = OC_DB::prepare( 'SELECT * FROM `*PREFIX*queuedtasks`' );
- $result = $stmt->execute(array());
- while( $row = $result->fetchRow()) {
- $return[] = $row;
- }
-
- return $return;
- }
-
- /**
- * @brief Gets all queued tasks of a specific app
- * @param $app app name
- * @return array with associative arrays
- */
- public static function whereAppIs( $app ) {
- // Array for objects
- $return = array();
-
- // Get Data
- $stmt = OC_DB::prepare( 'SELECT * FROM `*PREFIX*queuedtasks` WHERE `app` = ?' );
- $result = $stmt->execute(array($app));
- while( $row = $result->fetchRow()) {
- $return[] = $row;
- }
-
- // Und weg damit
- return $return;
- }
-
- /**
- * @brief queues a task
- * @param $app app name
- * @param $klass class name
- * @param $method method name
- * @param $parameters all useful data as text
- * @return id of task
- */
- public static function add( $app, $klass, $method, $parameters ) {
- $stmt = OC_DB::prepare( 'INSERT INTO `*PREFIX*queuedtasks` (`app`, `klass`, `method`, `parameters`)'
- .' VALUES(?,?,?,?)' );
- $result = $stmt->execute(array($app, $klass, $method, $parameters ));
-
- return OC_DB::insertid();
- }
-
- /**
- * @brief deletes a queued task
- * @param $id id of task
- * @return true/false
- *
- * Deletes a report
- */
- public static function delete( $id ) {
- $stmt = OC_DB::prepare( 'DELETE FROM `*PREFIX*queuedtasks` WHERE `id` = ?' );
- $result = $stmt->execute(array($id));
-
- return true;
- }
-}
diff --git a/lib/backgroundjob/regulartask.php b/lib/backgroundjob/regulartask.php
deleted file mode 100644
index 9976872ee13..00000000000
--- a/lib/backgroundjob/regulartask.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* 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 manages the regular tasks.
- */
-class OC_BackgroundJob_RegularTask{
- static private $registered = array();
-
- /**
- * @brief creates a regular task
- * @param $klass class name
- * @param $method method name
- * @return true
- */
- static public function register( $klass, $method ) {
- // Create the data structure
- self::$registered["$klass-$method"] = array( $klass, $method );
-
- // No chance for failure ;-)
- return true;
- }
-
- /**
- * @brief gets all regular tasks
- * @return associative array
- *
- * key is string "$klass-$method", value is array( $klass, $method )
- */
- static public function all() {
- return self::$registered;
- }
-}
diff --git a/lib/backgroundjob/timedjob.php b/lib/backgroundjob/timedjob.php
new file mode 100644
index 00000000000..ae9f33505ab
--- /dev/null
+++ b/lib/backgroundjob/timedjob.php
@@ -0,0 +1,41 @@
+<?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\BackgroundJob;
+
+/**
+ * Class QueuedJob
+ *
+ * create a background job that is to be executed at an interval
+ *
+ * @package OC\BackgroundJob
+ */
+abstract class TimedJob extends Job {
+ protected $interval = 0;
+
+ /**
+ * set the interval for the job
+ *
+ * @param int $interval
+ */
+ public function setInterval($interval) {
+ $this->interval = $interval;
+ }
+
+ /**
+ * run the job if
+ *
+ * @param JobList $jobList
+ */
+ public function execute($jobList) {
+ if ((time() - $this->lastRun) > $this->interval) {
+ $jobList->setLastRun($this);
+ $this->run($this->argument);
+ }
+ }
+}
diff --git a/lib/backgroundjob/worker.php b/lib/backgroundjob/worker.php
deleted file mode 100644
index e966ac9647c..00000000000
--- a/lib/backgroundjob/worker.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* 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 does the dirty work.
- *
- * TODO: locking in doAllSteps
- */
-class OC_BackgroundJob_Worker{
- /**
- * @brief executes all tasks
- * @return boolean
- *
- * This method executes all regular tasks and then all queued tasks.
- * This method should be called by cli scripts that do not let the user
- * wait.
- */
- public static function doAllSteps() {
- // Do our regular work
- $lasttask = OC_Appconfig::getValue( 'core', 'backgroundjobs_task', '' );
-
- $regular_tasks = OC_BackgroundJob_RegularTask::all();
- ksort( $regular_tasks );
- foreach( $regular_tasks as $key => $value ) {
- if( strcmp( $key, $lasttask ) > 0 ) {
- // Set "restart here" config value
- OC_Appconfig::setValue( 'core', 'backgroundjobs_task', $key );
- call_user_func( $value );
- }
- }
- // Reset "start here" config value
- OC_Appconfig::setValue( 'core', 'backgroundjobs_task', '' );
-
- // Do our queued tasks
- $queued_tasks = OC_BackgroundJob_QueuedTask::all();
- foreach( $queued_tasks as $task ) {
- OC_BackgroundJob_QueuedTask::delete( $task['id'] );
- call_user_func( array( $task['klass'], $task['method'] ), $task['parameters'] );
- }
-
- return true;
- }
-
- /**
- * @brief does a single task
- * @return boolean
- *
- * This method executes one task. It saves the last state and continues
- * with the next step. This method should be used by webcron and ajax
- * services.
- */
- public static function doNextStep() {
- $laststep = OC_Appconfig::getValue( 'core', 'backgroundjobs_step', 'regular_tasks' );
-
- if( $laststep == 'regular_tasks' ) {
- // get last app
- $lasttask = OC_Appconfig::getValue( 'core', 'backgroundjobs_task', '' );
-
- // What's the next step?
- $regular_tasks = OC_BackgroundJob_RegularTask::all();
- ksort( $regular_tasks );
- $done = false;
-
- // search for next background job
- foreach( $regular_tasks as $key => $value ) {
- if( strcmp( $key, $lasttask ) > 0 ) {
- OC_Appconfig::setValue( 'core', 'backgroundjobs_task', $key );
- $done = true;
- call_user_func( $value );
- break;
- }
- }
-
- if( $done == false ) {
- // Next time load queued tasks
- OC_Appconfig::setValue( 'core', 'backgroundjobs_step', 'queued_tasks' );
- }
- }
- else{
- $tasks = OC_BackgroundJob_QueuedTask::all();
- if( count( $tasks )) {
- $task = $tasks[0];
- // delete job before we execute it. This prevents endless loops
- // of failing jobs.
- OC_BackgroundJob_QueuedTask::delete($task['id']);
-
- // execute job
- call_user_func( array( $task['klass'], $task['method'] ), $task['parameters'] );
- }
- else{
- // Next time load queued tasks
- OC_Appconfig::setValue( 'core', 'backgroundjobs_step', 'regular_tasks' );
- OC_Appconfig::setValue( 'core', 'backgroundjobs_task', '' );
- }
- }
-
- return true;
- }
-}
diff --git a/lib/base.php b/lib/base.php
index 59b861ffce1..53aa7b09fd5 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -75,52 +75,14 @@ class OC {
protected static $router = null;
/**
- * SPL autoload
+ * @var \OC\Session\Session
*/
- public static function autoload($className) {
- if (array_key_exists($className, OC::$CLASSPATH)) {
- $path = OC::$CLASSPATH[$className];
- /** @TODO: Remove this when necessary
- Remove "apps/" from inclusion path for smooth migration to mutli app dir
- */
- if (strpos($path, 'apps/') === 0) {
- OC_Log::write('core', 'include path for class "' . $className . '" starts with "apps/"', OC_Log::DEBUG);
- $path = str_replace('apps/', '', $path);
- }
- } elseif (strpos($className, 'OC_') === 0) {
- $path = strtolower(str_replace('_', '/', substr($className, 3)) . '.php');
- } elseif (strpos($className, 'OC\\') === 0) {
- $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- } elseif (strpos($className, 'OCP\\') === 0) {
- $path = 'public/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- } elseif (strpos($className, 'OCA\\') === 0) {
- foreach (self::$APPSROOTS as $appDir) {
- $path = $appDir['path'] . '/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php');
- $fullPath = stream_resolve_include_path($path);
- if (file_exists($fullPath)) {
- require_once $fullPath;
- return false;
- }
- }
- } elseif (strpos($className, 'Sabre_') === 0) {
- $path = str_replace('_', '/', $className) . '.php';
- } elseif (strpos($className, 'Symfony\\Component\\Routing\\') === 0) {
- $path = 'symfony/routing/' . str_replace('\\', '/', $className) . '.php';
- } elseif (strpos($className, 'Sabre\\VObject') === 0) {
- $path = str_replace('\\', '/', $className) . '.php';
- } elseif (strpos($className, 'Test_') === 0) {
- $path = 'tests/lib/' . strtolower(str_replace('_', '/', substr($className, 5)) . '.php');
- } elseif (strpos($className, 'Test\\') === 0) {
- $path = 'tests/lib/' . strtolower(str_replace('\\', '/', substr($className, 5)) . '.php');
- } else {
- return false;
- }
+ public static $session = null;
- if ($fullPath = stream_resolve_include_path($path)) {
- require_once $fullPath;
- }
- return false;
- }
+ /**
+ * @var \OC\Autoloader $loader
+ */
+ public static $loader = null;
public static function initPaths() {
// calculate the root directories
@@ -211,11 +173,12 @@ class OC {
public static function checkConfig() {
if (file_exists(OC::$SERVERROOT . "/config/config.php")
and !is_writable(OC::$SERVERROOT . "/config/config.php")) {
+ $defaults = new OC_Defaults();
$tmpl = new OC_Template('', 'error', 'guest');
$tmpl->assign('errors', array(1 => array(
'error' => "Can't write into config directory 'config'",
- 'hint' => 'You can usually fix this by giving the webserver user write access'
- .' to the config directory in owncloud'
+ '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>.'
)));
$tmpl->printPage();
exit();
@@ -273,10 +236,7 @@ class OC {
$currentVersion = implode('.', OC_Util::getVersion());
if (version_compare($currentVersion, $installedVersion, '>')) {
if ($showTemplate && !OC_Config::getValue('maintenance', false)) {
- OC_Config::setValue('maintenance', true);
- OC_Log::write('core',
- 'starting upgrade from ' . $installedVersion . ' to ' . $currentVersion,
- OC_Log::DEBUG);
+ OC_Config::setValue('theme', '');
$minimizerCSS = new OC_Minimizer_CSS();
$minimizerCSS->clearCache();
$minimizerJS = new OC_Minimizer_JS();
@@ -296,13 +256,16 @@ class OC {
public static function initTemplateEngine() {
// Add the stuff we need always
- OC_Util::addScript("jquery-1.7.2.min");
+ OC_Util::addScript("jquery-1.10.0.min");
+ OC_Util::addScript("jquery-migrate-1.2.1.min");
OC_Util::addScript("jquery-ui-1.10.0.custom");
OC_Util::addScript("jquery-showpassword");
OC_Util::addScript("jquery.infieldlabel");
OC_Util::addScript("jquery-tipsy");
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("eventsource");
OC_Util::addScript("config");
@@ -314,6 +277,7 @@ class OC {
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");
}
@@ -321,14 +285,21 @@ class OC {
// prevents javascript from accessing php session cookies
ini_set('session.cookie_httponly', '1;');
- // set the session name to the instance id - which is unique
- session_name(OC_Util::getInstanceId());
-
- // if session cant be started break with http 500 error
- if (session_start() === false){
- OC_Log::write('core', 'Session could not be initialized',
+ // set the cookie path to the ownCloud directory
+ $cookie_path = OC::$WEBROOT ?: '/';
+ ini_set('session.cookie_path', $cookie_path);
+
+ //set the session object to a dummy session so code relying on the session existing still works
+ self::$session = new \OC\Session\Memory('');
+
+ try{
+ // set the session name to the instance id - which is unique
+ self::$session = new \OC\Session\Internal(OC_Util::getInstanceId());
+ // if session cant be started break with http 500 error
+ }catch (Exception $e){
+ OC_Log::write('core', 'Session could not be initialized',
OC_Log::ERROR);
-
+
header('HTTP/1.1 500 Internal Server Error');
OC_Util::addStyle("styles");
$error = 'Session could not be initialized. Please contact your ';
@@ -341,24 +312,33 @@ class OC {
exit();
}
+ $sessionLifeTime = self::getSessionLifeTime();
// regenerate session id periodically to avoid session fixation
- if (!isset($_SESSION['SID_CREATED'])) {
- $_SESSION['SID_CREATED'] = time();
- } else if (time() - $_SESSION['SID_CREATED'] > 60*60*12) {
+ if (!self::$session->exists('SID_CREATED')) {
+ self::$session->set('SID_CREATED', time());
+ } else if (time() - self::$session->get('SID_CREATED') > $sessionLifeTime / 2) {
session_regenerate_id(true);
- $_SESSION['SID_CREATED'] = time();
+ self::$session->set('SID_CREATED', time());
}
// session timeout
- if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 60*60*24)) {
+ if (self::$session->exists('LAST_ACTIVITY') && (time() - self::$session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
if (isset($_COOKIE[session_name()])) {
- setcookie(session_name(), '', time() - 42000, '/');
+ setcookie(session_name(), '', time() - 42000, $cookie_path);
}
session_unset();
session_destroy();
session_start();
}
- $_SESSION['LAST_ACTIVITY'] = time();
+
+ self::$session->set('LAST_ACTIVITY', time());
+ }
+
+ /**
+ * @return int
+ */
+ private static function getSessionLifeTime() {
+ return OC_Config::getValue('session_lifetime', 60 * 60 * 24);
}
public static function getRouter() {
@@ -383,8 +363,14 @@ class OC {
public static function init() {
// register autoloader
- spl_autoload_register(array('OC', 'autoload'));
- OC_Util::issetlocaleworking();
+ require_once __DIR__ . '/autoloader.php';
+ self::$loader=new \OC\Autoloader();
+ 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('Sabre\\VObject', '3rdparty');
+ self::$loader->registerPrefix('Sabre_', '3rdparty');
+ spl_autoload_register(array(self::$loader, 'load'));
// set some stuff
//ob_start();
@@ -398,8 +384,8 @@ class OC {
ini_set('arg_separator.output', '&amp;');
// try to switch magic quotes off.
- if (get_magic_quotes_gpc()) {
- @set_magic_quotes_runtime(false);
+ if (get_magic_quotes_gpc()==1) {
+ ini_set('magic_quotes_runtime', 0);
}
//try to configure php to enable big file uploads.
@@ -416,9 +402,6 @@ class OC {
@ini_set('post_max_size', '10G');
@ini_set('file_uploads', '50');
- //try to set the session lifetime to 60min
- @ini_set('gc_maxlifetime', '3600');
-
//copy http auth headers for apache+php-fcgid work around
if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
@@ -441,6 +424,7 @@ class OC {
}
self::initPaths();
+ OC_Util::issetlocaleworking();
// set debug mode if an xdebug session is active
if (!defined('DEBUG') || !DEBUG) {
@@ -450,9 +434,8 @@ class OC {
}
if (!defined('PHPUNIT_RUN') and !(defined('DEBUG') and DEBUG)) {
- register_shutdown_function(array('OC_Log', 'onShutdown'));
- set_error_handler(array('OC_Log', 'onError'));
- set_exception_handler(array('OC_Log', 'onException'));
+ OC\Log\ErrorHandler::register();
+ OC\Log\ErrorHandler::setLogger(OC_Log::$object);
}
// register the stream wrappers
@@ -461,11 +444,15 @@ class OC {
stream_wrapper_register('close', 'OC\Files\Stream\Close');
stream_wrapper_register('oc', 'OC\Files\Stream\OC');
+ self::initTemplateEngine();
+ if ( !self::$CLI ) {
+ self::initSession();
+ } else {
+ self::$session = new \OC\Session\Memory('');
+ }
self::checkConfig();
self::checkInstalled();
self::checkSSL();
- self::initSession();
- self::initTemplateEngine();
$errors = OC_Util::checkServer();
if (count($errors) > 0) {
@@ -473,16 +460,20 @@ class OC {
exit;
}
+ //try to set the session lifetime
+ $sessionLifeTime = self::getSessionLifeTime();
+ @ini_set('gc_maxlifetime', (string)$sessionLifeTime);
+
// User and Groups
if (!OC_Config::getValue("installed", false)) {
- $_SESSION['user_id'] = '';
+ self::$session->set('user_id','');
}
OC_User::useBackend(new OC_User_Database());
OC_Group::useBackend(new OC_Group_Database());
- if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SESSION['user_id'])
- && $_SERVER['PHP_AUTH_USER'] != $_SESSION['user_id']) {
+ if (isset($_SERVER['PHP_AUTH_USER']) && self::$session->exists('user_id')
+ && $_SERVER['PHP_AUTH_USER'] != self::$session->get('user_id')) {
OC_User::logout();
}
@@ -554,9 +545,15 @@ class OC {
* register hooks for the cache
*/
public static function registerCacheHooks() {
- // register cache cleanup jobs
- OC_BackgroundJob_RegularTask::register('OC_Cache_FileGlobal', 'gc');
- OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener');
+ 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');
+ } catch (Exception $e) {
+
+ }
+ OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener');
+ }
}
/**
@@ -572,10 +569,12 @@ class OC {
* register hooks for sharing
*/
public static function registerShareHooks() {
- OC_Hook::connect('OC_User', 'post_deleteUser', 'OCP\Share', 'post_deleteUser');
- OC_Hook::connect('OC_User', 'post_addToGroup', 'OCP\Share', 'post_addToGroup');
- OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OCP\Share', 'post_removeFromGroup');
- OC_Hook::connect('OC_User', 'post_deleteGroup', 'OCP\Share', 'post_deleteGroup');
+ if(\OC_Config::getValue('installed')) {
+ OC_Hook::connect('OC_User', 'post_deleteUser', 'OCP\Share', 'post_deleteUser');
+ OC_Hook::connect('OC_User', 'post_addToGroup', 'OCP\Share', 'post_addToGroup');
+ OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OCP\Share', 'post_removeFromGroup');
+ OC_Hook::connect('OC_User', 'post_deleteGroup', 'OCP\Share', 'post_deleteGroup');
+ }
}
/**
@@ -598,6 +597,9 @@ class OC {
self::checkUpgrade();
}
+ // Test it the user is already authenticated using Apaches AuthType Basic... very usable in combination with LDAP
+ OC::tryBasicAuthLogin();
+
if (!self::$CLI) {
try {
if (!OC_Config::getValue('maintenance', false)) {
@@ -625,8 +627,13 @@ class OC {
// Handle redirect URL for logged in users
if (isset($_REQUEST['redirect_url']) && OC_User::isLoggedIn()) {
$location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url']));
- header('Location: ' . $location);
- return;
+
+ // Deny the redirect if the URL contains a @
+ // This prevents unvalidated redirects like ?redirect_url=:user@domain.com
+ if (strpos($location, '@') === false) {
+ header('Location: ' . $location);
+ return;
+ }
}
// Handle WebDAV
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
@@ -694,15 +701,11 @@ class OC {
// remember was checked after last login
if (OC::tryRememberLogin()) {
$error[] = 'invalidcookie';
-
// Someone wants to log in :
} elseif (OC::tryFormLogin()) {
$error[] = 'invalidpassword';
-
- // The user is already authenticated using Apaches AuthType Basic... very usable in combination with LDAP
- } elseif (OC::tryBasicAuthLogin()) {
- $error[] = 'invalidpassword';
}
+
OC_Util::displayLoginPage(array_unique($error));
}
@@ -770,7 +773,7 @@ class OC {
if (OC_User::login($_POST["user"], $_POST["password"])) {
// setting up the time zone
if (isset($_POST['timezone-offset'])) {
- $_SESSION['timezone'] = $_POST['timezone-offset'];
+ self::$session->set('timezone', $_POST['timezone-offset']);
}
self::cleanupLoginTokens($_POST['user']);
@@ -800,8 +803,7 @@ class OC {
if (OC_User::login($_SERVER["PHP_AUTH_USER"], $_SERVER["PHP_AUTH_PW"])) {
//OC_Log::write('core',"Logged in with HTTP Authentication", OC_Log::DEBUG);
OC_User::unsetMagicInCookie();
- $_REQUEST['redirect_url'] = OC_Request::requestUri();
- OC_Util::redirectToDefaultPage();
+ $_SERVER['HTTP_REQUESTTOKEN'] = OC_Util::callRegister();
}
return true;
}
diff --git a/lib/cache/file.php b/lib/cache/file.php
index f9ecf41dcac..531e1d50f40 100644
--- a/lib/cache/file.php
+++ b/lib/cache/file.php
@@ -14,6 +14,7 @@ class OC_Cache_File{
return $this->storage;
}
if(OC_User::isLoggedIn()) {
+ \OC\Files\Filesystem::initMountPoints(OC_User::getUser());
$subdir = 'cache';
$view = new \OC\Files\View('/'.OC_User::getUser());
if(!$view->file_exists($subdir)) {
diff --git a/lib/cache/fileglobalgc.php b/lib/cache/fileglobalgc.php
new file mode 100644
index 00000000000..a29c31f9063
--- /dev/null
+++ b/lib/cache/fileglobalgc.php
@@ -0,0 +1,8 @@
+<?php
+
+
+class OC_Cache_FileGlobalGC extends \OC\BackgroundJob\Job{
+ public function run($argument){
+ OC_Cache_FileGlobal::gc();
+ }
+}
diff --git a/lib/config.php b/lib/config.php
index c94eb278159..00d9f5b4247 100644
--- a/lib/config.php
+++ b/lib/config.php
@@ -34,16 +34,34 @@
*
*/
+namespace OC;
+
/**
* This class is responsible for reading and writing config.php, the very basic
- * configuration file of owncloud.
+ * configuration file of ownCloud.
*/
-class OC_Config{
+class Config {
// associative array key => value
- private static $cache = array();
+ protected $cache = array();
+
+ protected $configDir;
+ protected $configFilename;
- // Is the cache filled?
- private static $init = false;
+ protected $debugMode;
+
+ /**
+ * @param $configDir path to the config dir, needs to end with '/'
+ */
+ public function __construct($configDir) {
+ $this->configDir = $configDir;
+ $this->configFilename = $this->configDir.'config.php';
+ $this->readData();
+ $this->setDebugMode(defined('DEBUG') && DEBUG);
+ }
+
+ public function setDebugMode($enable) {
+ $this->debugMode = $enable;
+ }
/**
* @brief Lists all available config keys
@@ -52,10 +70,8 @@ class OC_Config{
* This function returns all keys saved in config.php. Please note that it
* does not return the values.
*/
- public static function getKeys() {
- self::readData();
-
- return array_keys( self::$cache );
+ public function getKeys() {
+ return array_keys($this->cache);
}
/**
@@ -67,11 +83,9 @@ class OC_Config{
* This function gets the value from config.php. If it does not exist,
* $default will be returned.
*/
- public static function getValue( $key, $default = null ) {
- self::readData();
-
- if( array_key_exists( $key, self::$cache )) {
- return self::$cache[$key];
+ public function getValue($key, $default = null) {
+ if (isset($this->cache[$key])) {
+ return $this->cache[$key];
}
return $default;
@@ -81,103 +95,90 @@ class OC_Config{
* @brief Sets a value
* @param string $key key
* @param string $value value
- * @return bool
*
- * This function sets the value and writes the config.php. If the file can
- * not be written, false will be returned.
+ * This function sets the value and writes the config.php.
+ *
*/
- public static function setValue( $key, $value ) {
- self::readData();
-
+ public function setValue($key, $value) {
// Add change
- self::$cache[$key] = $value;
+ $this->cache[$key] = $value;
// Write changes
- self::writeData();
- return true;
+ $this->writeData();
}
/**
* @brief Removes a key from the config
* @param string $key key
- * @return bool
*
- * This function removes a key from the config.php. If owncloud has no
- * write access to config.php, the function will return false.
+ * This function removes a key from the config.php.
+ *
*/
- public static function deleteKey( $key ) {
- self::readData();
-
- if( array_key_exists( $key, self::$cache )) {
+ public function deleteKey($key) {
+ if (isset($this->cache[$key])) {
// Delete key from cache
- unset( self::$cache[$key] );
+ unset($this->cache[$key]);
// Write changes
- self::writeData();
+ $this->writeData();
}
-
- return true;
}
/**
* @brief Loads the config file
- * @return bool
*
* Reads the config file and saves it to the cache
*/
- private static function readData() {
- if( self::$init ) {
- return true;
- }
-
- if( !file_exists( OC::$SERVERROOT."/config/config.php" )) {
- return false;
+ private function readData() {
+ // Default config
+ $configFiles = array($this->configFilename);
+ // Add all files in the config dir ending with config.php
+ $extra = glob($this->configDir.'*.config.php');
+ if (is_array($extra)) {
+ natsort($extra);
+ $configFiles = array_merge($configFiles, $extra);
}
-
- // Include the file, save the data from $CONFIG
- include OC::$SERVERROOT."/config/config.php";
- if( isset( $CONFIG ) && is_array( $CONFIG )) {
- self::$cache = $CONFIG;
+ // Include file and merge config
+ foreach ($configFiles as $file) {
+ if (!file_exists($file)) {
+ continue;
+ }
+ unset($CONFIG);
+ include $file;
+ if (isset($CONFIG) && is_array($CONFIG)) {
+ $this->cache = array_merge($this->cache, $CONFIG);
+ }
}
-
- // We cached everything
- self::$init = true;
-
- return true;
}
/**
* @brief Writes the config file
- * @return bool
*
* Saves the config to the config file.
*
*/
- public static function writeData() {
+ private function writeData() {
// Create a php file ...
- $content = "<?php\n ";
- if (defined('DEBUG') && DEBUG) {
+ $defaults = new \OC_Defaults;
+ $content = "<?php\n";
+ if ($this->debugMode) {
$content .= "define('DEBUG',true);\n";
}
- $content .= "\$CONFIG = ";
- $content .= var_export(self::$cache, true);
+ $content .= '$CONFIG = ';
+ $content .= var_export($this->cache, true);
$content .= ";\n";
- $filename = OC::$SERVERROOT."/config/config.php";
// Write the file
- $result=@file_put_contents( $filename, $content );
- if(!$result) {
- $tmpl = new OC_Template( '', 'error', 'guest' );
- $tmpl->assign('errors', array(1=>array(
- 'error'=>"Can't write into config directory 'config'",
- 'hint'=>'You can usually fix this by giving the webserver user write access'
- .' to the config directory in owncloud')));
- $tmpl->printPage();
- exit;
+ $result = @file_put_contents($this->configFilename, $content);
+ if (!$result) {
+ $url = $defaults->getDocBaseUrl() . '/server/5.0/admin_manual/installation/installation_source.html#set-the-directory-permissions';
+ throw new HintException(
+ "Can't write into config directory 'config'",
+ 'This can usually be fixed by '
+ .'<a href="' . $url . '" target="_blank">giving the webserver write access to the config directory</a>.');
}
// Prevent others not to read the config
- @chmod($filename, 0640);
-
- return true;
+ @chmod($this->configFilename, 0640);
+ \OC_Util::clearOpcodeCache();
}
}
diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php
index 6ccb54b79ab..3d15a2a584d 100644
--- a/lib/connector/sabre/directory.php
+++ b/lib/connector/sabre/directory.php
@@ -45,9 +45,15 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
*
* @param string $name Name of the file
* @param resource|string $data Initial payload
+ * @throws Sabre_DAV_Exception_Forbidden
* @return null|string
*/
public function createFile($name, $data = null) {
+
+ if (!\OC\Files\Filesystem::isCreatable($this->path)) {
+ throw new \Sabre_DAV_Exception_Forbidden();
+ }
+
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
$info = OC_FileChunking::decodeName($name);
if (empty($info)) {
@@ -102,10 +108,15 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
* Creates a new subdirectory
*
* @param string $name
+ * @throws Sabre_DAV_Exception_Forbidden
* @return void
*/
public function createDirectory($name) {
+ if (!\OC\Files\Filesystem::isCreatable($this->path)) {
+ throw new \Sabre_DAV_Exception_Forbidden();
+ }
+
$newPath = $this->path . '/' . $name;
if(!\OC\Files\Filesystem::mkdir($newPath)) {
throw new Sabre_DAV_Exception_Forbidden('Could not create directory '.$newPath);
@@ -203,9 +214,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
* Deletes all files in this directory, and then itself
*
* @return void
+ * @throws Sabre_DAV_Exception_Forbidden
*/
public function delete() {
+ if (!\OC\Files\Filesystem::isDeletable($this->path)) {
+ throw new \Sabre_DAV_Exception_Forbidden();
+ }
if ($this->path != "/Shared") {
foreach($this->getChildren() as $child) $child->delete();
\OC\Files\Filesystem::rmdir($this->path);
diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php
index 91646312e90..438d9871c22 100644
--- a/lib/connector/sabre/file.php
+++ b/lib/connector/sabre/file.php
@@ -41,24 +41,29 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
* return an ETag, and just return null.
*
* @param resource $data
+ * @throws Sabre_DAV_Exception_Forbidden
* @return string|null
*/
public function put($data) {
+ if (!\OC\Files\Filesystem::isUpdatable($this->path)) {
+ throw new \Sabre_DAV_Exception_Forbidden();
+ }
+
// mark file as partial while uploading (ignored by the scanner)
$partpath = $this->path . '.part';
\OC\Files\Filesystem::file_put_contents($partpath, $data);
//detect aborted upload
- if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT' ) {
+ if (isset ($_SERVER['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);
+ 'expected filesize ' . $expected . ' got ' . $actual);
}
}
}
@@ -69,7 +74,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
//allow sync clients to send the mtime along in a header
$mtime = OC_Request::hasModificationTime();
if ($mtime !== false) {
- if(\OC\Files\Filesystem::touch($this->path, $mtime)) {
+ if (\OC\Files\Filesystem::touch($this->path, $mtime)) {
header('X-OC-MTime: accepted');
}
}
@@ -92,9 +97,13 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
* Delete the current file
*
* @return void
+ * @throws Sabre_DAV_Exception_Forbidden
*/
public function delete() {
+ if (!\OC\Files\Filesystem::isDeletable($this->path)) {
+ throw new \Sabre_DAV_Exception_Forbidden();
+ }
\OC\Files\Filesystem::unlink($this->path);
}
diff --git a/lib/connector/sabre/locks.php b/lib/connector/sabre/locks.php
index e58e584fb41..69496c15ada 100644
--- a/lib/connector/sabre/locks.php
+++ b/lib/connector/sabre/locks.php
@@ -45,7 +45,12 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
// but otherwise reading locks from SQLite Databases will return
// nothing
$query = 'SELECT * FROM `*PREFIX*locks`'
- .' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( `uri` = ?)';
+ .' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( `uri` = ?)';
+ if (OC_Config::getValue( "dbtype") === 'oci') {
+ //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
+ $query = 'SELECT * FROM `*PREFIX*locks`'
+ .' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( to_char(`uri`) = ?)';
+ }
$params = array(OC_User::getUser(), $uri);
// We need to check locks for every part in the uri.
@@ -60,23 +65,31 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
if ($currentPath) $currentPath.='/';
$currentPath.=$part;
-
- $query.=' OR (`depth` != 0 AND `uri` = ?)';
+ //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
+ if (OC_Config::getValue( "dbtype") === 'oci') {
+ $query.=' OR (`depth` != 0 AND to_char(`uri`) = ?)';
+ } else {
+ $query.=' OR (`depth` != 0 AND `uri` = ?)';
+ }
$params[] = $currentPath;
}
if ($returnChildLocks) {
- $query.=' OR (`uri` LIKE ?)';
+ //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
+ if (OC_Config::getValue( "dbtype") === 'oci') {
+ $query.=' OR (to_char(`uri`) LIKE ?)';
+ } else {
+ $query.=' OR (`uri` LIKE ?)';
+ }
$params[] = $uri . '/%';
}
$query.=')';
- $stmt = OC_DB::prepare( $query );
- $result = $stmt->execute( $params );
-
+ $result = OC_DB::executeAudited( $query, $params );
+
$lockList = array();
while( $row = $result->fetchRow()) {
@@ -113,14 +126,17 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
$locks = $this->getLocks($uri, false);
$exists = false;
foreach($locks as $lock) {
- if ($lock->token == $lockInfo->token) $exists = true;
+ if ($lock->token == $lockInfo->token) {
+ $exists = true;
+ break;
+ }
}
if ($exists) {
- $query = OC_DB::prepare( 'UPDATE `*PREFIX*locks`'
- .' SET `owner` = ?, `timeout` = ?, `scope` = ?, `depth` = ?, `uri` = ?, `created` = ?'
- .' WHERE `userid` = ? AND `token` = ?' );
- $result = $query->execute( array(
+ $sql = 'UPDATE `*PREFIX*locks`'
+ .' SET `owner` = ?, `timeout` = ?, `scope` = ?, `depth` = ?, `uri` = ?, `created` = ?'
+ .' WHERE `userid` = ? AND `token` = ?';
+ $result = OC_DB::executeAudited( $sql, array(
$lockInfo->owner,
$lockInfo->timeout,
$lockInfo->scope,
@@ -131,10 +147,10 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
$lockInfo->token)
);
} else {
- $query = OC_DB::prepare( 'INSERT INTO `*PREFIX*locks`'
- .' (`userid`,`owner`,`timeout`,`scope`,`depth`,`uri`,`created`,`token`)'
- .' VALUES (?,?,?,?,?,?,?,?)' );
- $result = $query->execute( array(
+ $sql = 'INSERT INTO `*PREFIX*locks`'
+ .' (`userid`,`owner`,`timeout`,`scope`,`depth`,`uri`,`created`,`token`)'
+ .' VALUES (?,?,?,?,?,?,?,?)';
+ $result = OC_DB::executeAudited( $sql, array(
OC_User::getUser(),
$lockInfo->owner,
$lockInfo->timeout,
@@ -159,10 +175,14 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
*/
public function unlock($uri, Sabre_DAV_Locks_LockInfo $lockInfo) {
- $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND `uri` = ? AND `token` = ?' );
- $result = $query->execute( array(OC_User::getUser(), $uri, $lockInfo->token));
+ $sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND `uri` = ? AND `token` = ?';
+ if (OC_Config::getValue( "dbtype") === 'oci') {
+ //FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
+ $sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND to_char(`uri`) = ? AND `token` = ?';
+ }
+ $result = OC_DB::executeAudited( $sql, array(OC_User::getUser(), $uri, $lockInfo->token));
- return $result->numRows() === 1;
+ return $result === 1;
}
diff --git a/lib/connector/sabre/maintenanceplugin.php b/lib/connector/sabre/maintenanceplugin.php
index 329fa4443ad..2eda269afc2 100644
--- a/lib/connector/sabre/maintenanceplugin.php
+++ b/lib/connector/sabre/maintenanceplugin.php
@@ -50,6 +50,9 @@ class OC_Connector_Sabre_MaintenancePlugin extends Sabre_DAV_ServerPlugin
if (OC_Config::getValue('maintenance', false)) {
throw new Sabre_DAV_Exception_ServiceUnavailable();
}
+ if (OC::checkUpgrade(false)) {
+ throw new Sabre_DAV_Exception_ServiceUnavailable('Upgrade needed');
+ }
return true;
}
diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php
index 360c3066d05..0bffa58af78 100644
--- a/lib/connector/sabre/node.php
+++ b/lib/connector/sabre/node.php
@@ -101,7 +101,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
/**
* @brief Ensure that the fileinfo cache is filled
- & @note Uses OC_FileCache or a direct stat
+ * @note Uses OC_FileCache or a direct stat
*/
protected function getFileinfoCache() {
if (!isset($this->fileinfo_cache)) {
@@ -189,8 +189,8 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
*/
public function getProperties($properties) {
if (is_null($this->property_cache)) {
- $query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?' );
- $result = $query->execute( array( OC_User::getUser(), $this->path ));
+ $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?';
+ $result = OC_DB::executeAudited( $sql, array( OC_User::getUser(), $this->path ) );
$this->property_cache = array();
while( $row = $result->fetchRow()) {
diff --git a/lib/db.php b/lib/db.php
index 9699b216f6f..6fec60e53ce 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -23,7 +23,8 @@
class DatabaseException extends Exception{
private $query;
- public function __construct($message, $query){
+ //FIXME getQuery seems to be unused, maybe use parent constructor with $message, $code and $previous
+ public function __construct($message, $query = null){
parent::__construct($message);
$this->query = $query;
}
@@ -179,28 +180,18 @@ class OC_DB {
$dsn = 'oci:dbname=//' . $host . '/' . $name;
}
break;
- case 'mssql':
+ case 'mssql':
if ($port) {
$dsn='sqlsrv:Server='.$host.','.$port.';Database='.$name;
} else {
$dsn='sqlsrv:Server='.$host.';Database='.$name;
}
- break;
+ break;
default:
return false;
}
- try{
- self::$PDO=new PDO($dsn, $user, $pass, $opts);
- }catch(PDOException $e) {
- OC_Log::write('core', $e->getMessage(), OC_Log::FATAL);
- OC_User::setUserId(null);
-
- // send http status 503
- header('HTTP/1.1 503 Service Temporarily Unavailable');
- header('Status: 503 Service Temporarily Unavailable');
- OC_Template::printErrorPage('Failed to connect to database');
- die();
- }
+ self::$PDO=new PDO($dsn, $user, $pass, $opts);
+
// We always, really always want associative arrays
self::$PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
self::$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
@@ -273,18 +264,13 @@ class OC_DB {
break;
case 'oci':
$dsn = array(
- 'phptype' => 'oci8',
- 'username' => $user,
- 'password' => $pass,
- 'charset' => 'AL32UTF8',
+ 'phptype' => 'oci8',
+ 'username' => $user,
+ 'password' => $pass,
+ 'service' => $name,
+ 'hostspec' => $host,
+ 'charset' => 'AL32UTF8',
);
- if ($host != '') {
- $dsn['hostspec'] = $host;
- $dsn['database'] = $name;
- } else { // use dbname for hostspec
- $dsn['hostspec'] = $name;
- $dsn['database'] = $user;
- }
break;
case 'mssql':
$dsn = array(
@@ -303,19 +289,8 @@ class OC_DB {
// Try to establish connection
self::$MDB2 = MDB2::factory( $dsn, $options );
-
- // Die if we could not connect
- if( PEAR::isError( self::$MDB2 )) {
- OC_Log::write('core', self::$MDB2->getUserInfo(), OC_Log::FATAL);
- OC_Log::write('core', self::$MDB2->getMessage(), OC_Log::FATAL);
- OC_User::setUserId(null);
-
- // send http status 503
- header('HTTP/1.1 503 Service Temporarily Unavailable');
- header('Status: 503 Service Temporarily Unavailable');
- OC_Template::printErrorPage('Failed to connect to database');
- die();
- }
+
+ self::raiseExceptionOnError( self::$MDB2 );
// We always, really always want associative arrays
self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
@@ -330,11 +305,12 @@ class OC_DB {
* @param string $query Query string
* @param int $limit
* @param int $offset
+ * @param bool $isManipulation
* @return MDB2_Statement_Common prepared SQL query
*
* SQL query via MDB2 prepare(), needs to be execute()'d!
*/
- static public function prepare( $query , $limit=null, $offset=null ) {
+ static public function prepare( $query , $limit = null, $offset = null, $isManipulation = null) {
if (!is_null($limit) && $limit != -1) {
if (self::$backend == self::BACKEND_MDB2) {
@@ -367,14 +343,27 @@ class OC_DB {
// Optimize the query
$query = self::processQuery( $query );
-
+ if(OC_Config::getValue( "log_query", false)) {
+ OC_Log::write('core', 'DB prepare : '.$query, OC_Log::DEBUG);
+ }
self::connect();
+
+ if ($isManipulation === null) {
+ //try to guess, so we return the number of rows on manipulations
+ $isManipulation = self::isManipulation($query);
+ }
+
// return the result
if(self::$backend==self::BACKEND_MDB2) {
- $result = self::$connection->prepare( $query );
+ // differentiate between query and manipulation
+ if ($isManipulation) {
+ $result = self::$connection->prepare( $query, null, MDB2_PREPARE_MANIP );
+ } else {
+ $result = self::$connection->prepare( $query, null, MDB2_PREPARE_RESULT );
+ }
// Die if we have an error (error means: bad query, not 0 results!)
- if( PEAR::isError($result)) {
+ if( self::isError($result)) {
throw new DatabaseException($result->getMessage(), $query);
}
}else{
@@ -383,7 +372,8 @@ class OC_DB {
}catch(PDOException $e) {
throw new DatabaseException($e->getMessage(), $query);
}
- $result=new PDOStatementWrapper($result);
+ // differentiate between query and manipulation
+ $result = new PDOStatementWrapper($result, $isManipulation);
}
if ((is_null($limit) || $limit == -1) and self::$cachingEnabled ) {
$type = OC_Config::getValue( "dbtype", "sqlite" );
@@ -393,11 +383,87 @@ class OC_DB {
}
return $result;
}
+
+ /**
+ * tries to guess the type of statement based on the first 10 characters
+ * the current check allows some whitespace but does not work with IF EXISTS or other more complex statements
+ *
+ * @param string $sql
+ */
+ static public function isManipulation( $sql ) {
+ $selectOccurence = stripos ($sql, "SELECT");
+ if ($selectOccurence !== false && $selectOccurence < 10) {
+ return false;
+ }
+ $insertOccurence = stripos ($sql, "INSERT");
+ if ($insertOccurence !== false && $insertOccurence < 10) {
+ return true;
+ }
+ $updateOccurence = stripos ($sql, "UPDATE");
+ if ($updateOccurence !== false && $updateOccurence < 10) {
+ return true;
+ }
+ $deleteOccurance = stripos ($sql, "DELETE");
+ if ($deleteOccurance !== false && $deleteOccurance < 10) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @brief execute a prepared statement, on error write log and throw exception
+ * @param mixed $stmt PDOStatementWrapper | MDB2_Statement_Common ,
+ * an array with 'sql' and optionally 'limit' and 'offset' keys
+ * .. or a simple sql query string
+ * @param array $parameters
+ * @return result
+ * @throws DatabaseException
+ */
+ static public function executeAudited( $stmt, array $parameters = null) {
+ if (is_string($stmt)) {
+ // convert to an array with 'sql'
+ if (stripos($stmt,'LIMIT') !== false) { //OFFSET requires LIMIT, se we only neet to check for LIMIT
+ // TODO try to convert LIMIT OFFSET notation to parameters, see fixLimitClauseForMSSQL
+ $message = 'LIMIT and OFFSET are forbidden for portability reasons,'
+ . ' pass an array with \'limit\' and \'offset\' instead';
+ throw new DatabaseException($message);
+ }
+ $stmt = array('sql' => $stmt, 'limit' => null, 'offset' => null);
+ }
+ if (is_array($stmt)){
+ // convert to prepared statement
+ if ( ! array_key_exists('sql', $stmt) ) {
+ $message = 'statement array must at least contain key \'sql\'';
+ throw new DatabaseException($message);
+ }
+ if ( ! array_key_exists('limit', $stmt) ) {
+ $stmt['limit'] = null;
+ }
+ if ( ! array_key_exists('limit', $stmt) ) {
+ $stmt['offset'] = null;
+ }
+ $stmt = self::prepare($stmt['sql'], $stmt['limit'], $stmt['offset']);
+ }
+ self::raiseExceptionOnError($stmt, 'Could not prepare statement');
+ if ($stmt instanceof PDOStatementWrapper || $stmt instanceof MDB2_Statement_Common) {
+ $result = $stmt->execute($parameters);
+ self::raiseExceptionOnError($result, 'Could not execute statement');
+ } else {
+ if (is_object($stmt)) {
+ $message = 'Expected a prepared statement or array got ' . get_class($stmt);
+ } else {
+ $message = 'Expected a prepared statement or array got ' . gettype($stmt);
+ }
+ throw new DatabaseException($message);
+ }
+ return $result;
+ }
/**
* @brief gets last value of autoincrement
* @param string $table The optional table name (will replace *PREFIX*) and add sequence suffix
* @return int id
+ * @throws DatabaseException
*
* MDB2 lastInsertID()
*
@@ -407,25 +473,27 @@ class OC_DB {
public static function insertid($table=null) {
self::connect();
$type = OC_Config::getValue( "dbtype", "sqlite" );
- if( $type == 'pgsql' ) {
- $query = self::prepare('SELECT lastval() AS id');
- $row = $query->execute()->fetchRow();
+ if( $type === 'pgsql' ) {
+ $result = self::executeAudited('SELECT lastval() AS id');
+ $row = $result->fetchRow();
+ self::raiseExceptionOnError($row, 'fetching row for insertid failed');
return $row['id'];
- }
- if( $type == 'mssql' ) {
+ } else if( $type === 'mssql' || $type === 'oci') {
if($table !== null) {
$prefix = OC_Config::getValue( "dbtableprefix", "oc_" );
$table = str_replace( '*PREFIX*', $prefix, $table );
}
- return self::$connection->lastInsertId($table);
- }else{
+ $result = self::$connection->lastInsertId($table);
+ } else {
if($table !== null) {
$prefix = OC_Config::getValue( "dbtableprefix", "oc_" );
$suffix = OC_Config::getValue( "dbsequencesuffix", "_id_seq" );
$table = str_replace( '*PREFIX*', $prefix, $table ).$suffix;
}
- return self::$connection->lastInsertId($table);
+ $result = self::$connection->lastInsertId($table);
}
+ self::raiseExceptionOnError($result, 'insertid failed');
+ return $result;
}
/**
@@ -515,11 +583,9 @@ class OC_DB {
//clean up memory
unlink( $file2 );
+
+ self::raiseExceptionOnError($definition,'Failed to parse the database definition');
- // Die in case something went wrong
- if( $definition instanceof MDB2_Schema_Error ) {
- OC_Template::printErrorPage( $definition->getMessage().': '.$definition->getUserInfo() );
- }
if(OC_Config::getValue('dbtype', 'sqlite')==='oci') {
unset($definition['charset']); //or MDB2 tries SHUTDOWN IMMEDIATE
$oldname = $definition['name'];
@@ -531,11 +597,7 @@ class OC_DB {
$ret=self::$schema->createDatabase( $definition );
- // Die in case something went wrong
- if( $ret instanceof MDB2_Error ) {
- OC_Template::printErrorPage( self::$MDB2->getDebugOutput().' '.$ret->getMessage() . ': '
- . $ret->getUserInfo() );
- }
+ self::raiseExceptionOnError($ret,'Failed to create the database structure');
return true;
}
@@ -550,18 +612,17 @@ class OC_DB {
$CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" );
self::connectScheme();
+
+ if(OC_Config::getValue('dbtype', 'sqlite')==='oci') {
+ //set dbname, it is unset because oci uses 'service' to connect
+ self::$schema->db->database_name=self::$schema->db->dsn['username'];
+ }
// read file
$content = file_get_contents( $file );
$previousSchema = self::$schema->getDefinitionFromDatabase();
- if (PEAR::isError($previousSchema)) {
- $error = $previousSchema->getMessage();
- $detail = $previousSchema->getDebugInfo();
- $message = 'Failed to get existing database structure for updating ('.$error.', '.$detail.')';
- OC_Log::write('core', $message, OC_Log::FATAL);
- throw new Exception($message);
- }
+ self::raiseExceptionOnError($previousSchema,'Failed to get existing database structure for updating');
// Make changes and save them to an in-memory file
$file2 = 'static://db_scheme';
@@ -579,19 +640,19 @@ class OC_DB {
$content = str_replace( '<default>0000-00-00 00:00:00</default>',
'<default>CURRENT_TIMESTAMP</default>', $content );
}
+ if(OC_Config::getValue('dbtype', 'sqlite')==='oci') {
+ unset($previousSchema['charset']); //or MDB2 tries SHUTDOWN IMMEDIATE
+ $oldname = $previousSchema['name'];
+ $previousSchema['name']=OC_Config::getValue( "dbuser", $oldname );
+ //TODO check identifiers are at most 30 chars long
+ }
file_put_contents( $file2, $content );
$op = self::$schema->updateDatabase($file2, $previousSchema, array(), false);
//clean up memory
unlink( $file2 );
- if (PEAR::isError($op)) {
- $error = $op->getMessage();
- $detail = $op->getDebugInfo();
- $message = 'Failed to update database structure ('.$error.', '.$detail.')';
- OC_Log::write('core', $message, OC_Log::FATAL);
- throw new Exception($message);
- }
+ self::raiseExceptionOnError($op,'Failed to update database structure');
return true;
}
@@ -620,7 +681,7 @@ class OC_DB {
* @brief Insert a row if a matching row doesn't exists.
* @param string $table. The table to insert into in the form '*PREFIX*tableName'
* @param array $input. An array of fieldname/value pairs
- * @returns The return value from PDOStatementWrapper->execute()
+ * @returns int number of updated rows
*/
public static function insertIfNotExist($table, $input) {
self::connect();
@@ -633,59 +694,50 @@ class OC_DB {
$type = self::$type;
$query = '';
+ $inserts = array_values($input);
// differences in escaping of table names ('`' for mysql) and getting the current timestamp
if( $type == 'sqlite' || $type == 'sqlite3' ) {
// NOTE: For SQLite we have to use this clumsy approach
// otherwise all fieldnames used must have a unique key.
- $query = 'SELECT * FROM "' . $table . '" WHERE ';
+ $query = 'SELECT * FROM `' . $table . '` WHERE ';
foreach($input as $key => $value) {
- $query .= $key . " = '" . $value . '\' AND ';
+ $query .= '`' . $key . '` = ? AND ';
}
$query = substr($query, 0, strlen($query) - 5);
try {
- $stmt = self::prepare($query);
- $result = $stmt->execute();
- } catch(PDOException $e) {
- $entry = 'DB Error: "'.$e->getMessage() . '"<br />';
- $entry .= 'Offending command was: ' . $query . '<br />';
- OC_Log::write('core', $entry, OC_Log::FATAL);
- error_log('DB error: '.$entry);
- OC_Template::printErrorPage( $entry );
+ $result = self::executeAudited($query, $inserts);
+ } catch(DatabaseException $e) {
+ OC_Template::printExceptionErrorPage( $e );
}
- if($result->numRows() == 0) {
- $query = 'INSERT INTO "' . $table . '" ("'
- . implode('","', array_keys($input)) . '") VALUES("'
- . implode('","', array_values($input)) . '")';
+ if((int)$result->numRows() === 0) {
+ $query = 'INSERT INTO `' . $table . '` (`'
+ . implode('`,`', array_keys($input)) . '`) VALUES('
+ . str_repeat('?,', count($input)-1).'? ' . ')';
} else {
- return true;
+ return 0; //no rows updated
}
} elseif( $type == 'pgsql' || $type == 'oci' || $type == 'mysql' || $type == 'mssql') {
- $query = 'INSERT INTO `' .$table . '` ('
- . implode(',', array_keys($input)) . ') SELECT \''
- . implode('\',\'', array_values($input)) . '\' FROM ' . $table . ' WHERE ';
+ $query = 'INSERT INTO `' .$table . '` (`'
+ . implode('`,`', array_keys($input)) . '`) SELECT '
+ . str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative?
+ . 'FROM `' . $table . '` WHERE ';
foreach($input as $key => $value) {
- $query .= $key . " = '" . $value . '\' AND ';
+ $query .= '`' . $key . '` = ? AND ';
}
$query = substr($query, 0, strlen($query) - 5);
$query .= ' HAVING COUNT(*) = 0';
+ $inserts = array_merge($inserts, $inserts);
}
- // TODO: oci should be use " (quote) instead of ` (backtick).
- //OC_Log::write('core', __METHOD__ . ', type: ' . $type . ', query: ' . $query, OC_Log::DEBUG);
-
try {
- $result = self::prepare($query);
+ $result = self::executeAudited($query, $inserts);
} catch(PDOException $e) {
- $entry = 'DB Error: "'.$e->getMessage() . '"<br />';
- $entry .= 'Offending command was: ' . $query.'<br />';
- OC_Log::write('core', $entry, OC_Log::FATAL);
- error_log('DB error: ' . $entry);
- OC_Template::printErrorPage( $entry );
+ OC_Template::printExceptionErrorPage( $e );
}
- return $result->execute();
+ return $result;
}
/**
@@ -720,15 +772,16 @@ class OC_DB {
}elseif( $type == 'oci' ) {
$query = str_replace( '`', '"', $query );
$query = str_ireplace( 'NOW()', 'CURRENT_TIMESTAMP', $query );
+ $query = str_ireplace( 'UNIX_TIMESTAMP()', '((CAST(SYS_EXTRACT_UTC(systimestamp) AS DATE))-TO_DATE(\'1970101000000\',\'YYYYMMDDHH24MiSS\'))*24*3600', $query );
}elseif( $type == 'mssql' ) {
$query = preg_replace( "/\`(.*?)`/", "[$1]", $query );
$query = str_replace( 'NOW()', 'CURRENT_TIMESTAMP', $query );
$query = str_replace( 'now()', 'CURRENT_TIMESTAMP', $query );
$query = str_replace( 'LENGTH(', 'LEN(', $query );
$query = str_replace( 'SUBSTR(', 'SUBSTRING(', $query );
-
- $query = self::fixLimitClauseForMSSQL($query);
- }
+
+ $query = self::fixLimitClauseForMSSQL($query);
+ }
// replace table name prefix
$query = str_replace( '*PREFIX*', $prefix, $query );
@@ -736,60 +789,60 @@ class OC_DB {
return $query;
}
- private static function fixLimitClauseForMSSQL($query) {
- $limitLocation = stripos ($query, "LIMIT");
-
- if ( $limitLocation === false ) {
- return $query;
- }
-
- // total == 0 means all results - not zero results
- //
- // First number is either total or offset, locate it by first space
- //
- $offset = substr ($query, $limitLocation + 5);
- $offset = substr ($offset, 0, stripos ($offset, ' '));
- $offset = trim ($offset);
-
- // check for another parameter
- if (stripos ($offset, ',') === false) {
- // no more parameters
- $offset = 0;
- $total = intval ($offset);
- } else {
- // found another parameter
- $offset = intval ($offset);
-
- $total = substr ($query, $limitLocation + 5);
- $total = substr ($total, stripos ($total, ','));
-
- $total = substr ($total, 0, stripos ($total, ' '));
- $total = intval ($total);
- }
-
- $query = trim (substr ($query, 0, $limitLocation));
-
- if ($offset == 0 && $total !== 0) {
- if (strpos($query, "SELECT") === false) {
- $query = "TOP {$total} " . $query;
- } else {
- $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query);
- }
- } else if ($offset > 0) {
- $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query);
- $query = 'SELECT *
- FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3
- FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3';
-
- if ($total > 0) {
- $query .= ' WHERE line3 BETWEEN ' . ($offset + 1) . ' AND ' . ($offset + $total);
- } else {
- $query .= ' WHERE line3 > ' . $offset;
- }
- }
- return $query;
- }
-
+ private static function fixLimitClauseForMSSQL($query) {
+ $limitLocation = stripos ($query, "LIMIT");
+
+ if ( $limitLocation === false ) {
+ return $query;
+ }
+
+ // total == 0 means all results - not zero results
+ //
+ // First number is either total or offset, locate it by first space
+ //
+ $offset = substr ($query, $limitLocation + 5);
+ $offset = substr ($offset, 0, stripos ($offset, ' '));
+ $offset = trim ($offset);
+
+ // check for another parameter
+ if (stripos ($offset, ',') === false) {
+ // no more parameters
+ $offset = 0;
+ $total = intval ($offset);
+ } else {
+ // found another parameter
+ $offset = intval ($offset);
+
+ $total = substr ($query, $limitLocation + 5);
+ $total = substr ($total, stripos ($total, ','));
+
+ $total = substr ($total, 0, stripos ($total, ' '));
+ $total = intval ($total);
+ }
+
+ $query = trim (substr ($query, 0, $limitLocation));
+
+ if ($offset == 0 && $total !== 0) {
+ if (strpos($query, "SELECT") === false) {
+ $query = "TOP {$total} " . $query;
+ } else {
+ $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query);
+ }
+ } else if ($offset > 0) {
+ $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query);
+ $query = 'SELECT *
+ FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3
+ FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3';
+
+ if ($total > 0) {
+ $query .= ' WHERE line3 BETWEEN ' . ($offset + 1) . ' AND ' . ($offset + $total);
+ } else {
+ $query .= ' WHERE line3 > ' . $offset;
+ }
+ }
+ return $query;
+ }
+
/**
* @brief drop a table
* @param string $tableName the table to drop
@@ -885,15 +938,46 @@ class OC_DB {
* @return bool
*/
public static function isError($result) {
- if(!$result) {
+ //MDB2 returns an MDB2_Error object
+ if (class_exists('PEAR') === true && PEAR::isError($result)) {
return true;
- }elseif(self::$backend==self::BACKEND_MDB2 and PEAR::isError($result)) {
+ }
+ //PDO returns false on error (and throws an exception)
+ if (self::$backend===self::BACKEND_PDO and $result === false) {
return true;
- }else{
- return false;
}
+
+ return false;
}
+ /**
+ * check if a result is an error and throws an exception, works with MDB2 and PDOException
+ * @param mixed $result
+ * @param string $message
+ * @return void
+ * @throws DatabaseException
+ */
+ public static function raiseExceptionOnError($result, $message = null) {
+ if(self::isError($result)) {
+ if ($message === null) {
+ $message = self::getErrorMessage($result);
+ } else {
+ $message .= ', Root cause:' . self::getErrorMessage($result);
+ }
+ throw new DatabaseException($message, self::getErrorCode($result));
+ }
+ }
+
+ public static function getErrorCode($error) {
+ if ( class_exists('PEAR') === true && PEAR::isError($error) ) {
+ /** @var $error PEAR_Error */
+ return $error->getCode();
+ }
+ if ( self::$backend==self::BACKEND_PDO and self::$PDO ) {
+ return self::$PDO->errorCode();
+ }
+ return -1;
+ }
/**
* returns the error code and message as a string for logging
* works with MDB2 and PDOException
@@ -901,25 +985,24 @@ class OC_DB {
* @return string
*/
public static function getErrorMessage($error) {
- if ( self::$backend==self::BACKEND_MDB2 and PEAR::isError($error) ) {
+ if ( class_exists('PEAR') === true && PEAR::isError($error) ) {
$msg = $error->getCode() . ': ' . $error->getMessage();
- if (defined('DEBUG') && DEBUG) {
- $msg .= '(' . $error->getDebugInfo() . ')';
- }
- } elseif (self::$backend==self::BACKEND_PDO and self::$PDO) {
+ $msg .= ' (' . $error->getDebugInfo() . ')';
+
+ return $msg;
+ }
+ if (self::$backend==self::BACKEND_PDO and self::$PDO) {
$msg = self::$PDO->errorCode() . ': ';
$errorInfo = self::$PDO->errorInfo();
if (is_array($errorInfo)) {
$msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
$msg .= 'Driver Code = '.$errorInfo[1] . ', ';
$msg .= 'Driver Message = '.$errorInfo[2];
- }else{
- $msg = '';
}
- }else{
- $msg = '';
+ return $msg;
}
- return $msg;
+
+ return '';
}
/**
@@ -940,17 +1023,23 @@ class PDOStatementWrapper{
/**
* @var PDOStatement
*/
- private $statement=null;
- private $lastArguments=array();
+ private $statement = null;
+ private $isManipulation = false;
+ private $lastArguments = array();
- public function __construct($statement) {
- $this->statement=$statement;
+ public function __construct($statement, $isManipulation = false) {
+ $this->statement = $statement;
+ $this->isManipulation = $isManipulation;
}
/**
- * make execute return the result instead of a bool
+ * make execute return the result or updated row count instead of a bool
*/
public function execute($input=array()) {
+ if(OC_Config::getValue( "log_query", false)) {
+ $params_str = str_replace("\n"," ",var_export($input,true));
+ OC_Log::write('core', 'DB execute with arguments : '.$params_str, OC_Log::DEBUG);
+ }
$this->lastArguments = $input;
if (count($input) > 0) {
@@ -962,16 +1051,19 @@ class PDOStatementWrapper{
$input = $this->tryFixSubstringLastArgumentDataForMSSQL($input);
}
- $result=$this->statement->execute($input);
+ $result = $this->statement->execute($input);
} else {
- $result=$this->statement->execute();
+ $result = $this->statement->execute();
}
- if ($result) {
- return $this;
- } else {
+ if ($result === false) {
return false;
}
+ if ($this->isManipulation) {
+ return $this->statement->rowCount();
+ } else {
+ return $this;
+ }
}
private function tryFixSubstringLastArgumentDataForMSSQL($input) {
@@ -1063,14 +1155,14 @@ class PDOStatementWrapper{
die ($entry);
}
}
-
+
/**
* provide numRows
*/
public function numRows() {
$regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i';
if (preg_match($regex, $this->statement->queryString, $output) > 0) {
- $query = OC_DB::prepare("SELECT COUNT(*) FROM {$output[1]}", PDO::FETCH_NUM);
+ $query = OC_DB::prepare("SELECT COUNT(*) FROM {$output[1]}");
return $query->execute($this->lastArguments)->fetchColumn();
}else{
return $this->statement->rowCount();
diff --git a/lib/defaults.php b/lib/defaults.php
new file mode 100644
index 00000000000..196bb5cf14d
--- /dev/null
+++ b/lib/defaults.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * Default strings and values which differ between the enterprise and the
+ * community edition. Use the get methods to always get the right strings.
+ */
+
+
+if (file_exists(OC::$SERVERROOT . '/themes/' . OC_Util::getTheme() . '/defaults.php')) {
+ require_once 'themes/' . OC_Util::getTheme() . '/defaults.php';
+}
+
+class OC_Defaults {
+
+ private $theme;
+
+ private $defaultEntity;
+ private $defaultName;
+ private $defaultBaseUrl;
+ private $defaultSyncClientUrl;
+ private $defaultDocBaseUrl;
+ private $defaultSlogan;
+ private $defaultLogoClaim;
+
+ function __construct() {
+ $l = OC_L10N::get('core');
+
+ $this->defaultEntity = "ownCloud";
+ $this->defaultName = "ownCloud";
+ $this->defaultBaseUrl = "http://owncloud.org";
+ $this->defaultSyncClientUrl = " http://owncloud.org/sync-clients/";
+ $this->defaultDocBaseUrl = "http://doc.owncloud.org";
+ $this->defaultSlogan = $l->t("web services under your control");
+ $this->defaultLogoClaim = "";
+
+ if (class_exists("OC_Theme")) {
+ $this->theme = new OC_Theme();
+ }
+ }
+
+ private function themeExist($method) {
+ if (OC_Util::getTheme() !== '' && method_exists('OC_Theme', $method)) {
+ return true;
+ }
+ return false;
+ }
+
+ public function getBaseUrl() {
+ if ($this->themeExist('getBaseUrl')) {
+ return $this->theme->getBaseUrl();
+ } else {
+ return $this->defaultBaseUrl;
+ }
+ }
+
+ public function getSyncClientUrl() {
+ if ($this->themeExist('getSyncClientUrl')) {
+ return $this->theme->getSyncClientUrl();
+ } else {
+ return $this->defaultSyncClientUrl;
+ }
+ }
+
+ public function getDocBaseUrl() {
+ if ($this->themeExist('getDocBaseUrl')) {
+ return $this->theme->getDocBaseUrl();
+ } else {
+ return $this->defaultDocBaseUrl;
+ }
+ }
+
+ public function getName() {
+ if ($this->themeExist('getName')) {
+ return $this->theme->getName();
+ } else {
+ return $this->defaultName;
+ }
+ }
+
+ public function getEntity() {
+ if ($this->themeExist('getEntity')) {
+ return $this->theme->getEntity();
+ } else {
+ return $this->defaultEntity;
+ }
+ }
+
+ public function getSlogan() {
+ if ($this->themeExist('getSlogan')) {
+ return $this->theme->getSlogan();
+ } else {
+ return $this->defaultSlogan;
+ }
+ }
+
+ public function getLogoClaim() {
+ if ($this->themeExist('getLogoClaim')) {
+ return $this->theme->getLogoClaim();
+ } else {
+ return $this->defaultLogoClaim;
+ }
+ }
+
+ public function getShortFooter() {
+ if ($this->themeExist('getShortFooter')) {
+ $footer = $this->theme->getShortFooter();
+ } else {
+ $footer = "<a href=\"". $this->getBaseUrl() . "\" target=\"_blank\">" .$this->getEntity() . "</a>".
+ ' – ' . $this->getSlogan();
+ }
+
+ return $footer;
+ }
+
+ public function getLongFooter() {
+ if ($this->themeExist('getLongFooter')) {
+ $footer = $this->theme->getLongFooter();
+ } else {
+ $footer = $this->getShortFooter();
+ }
+
+ return $footer;
+ }
+
+}
diff --git a/lib/eventsource.php b/lib/eventsource.php
index 63f19792529..31d6edc1874 100644
--- a/lib/eventsource.php
+++ b/lib/eventsource.php
@@ -25,7 +25,7 @@
* wrapper for server side events (http://en.wikipedia.org/wiki/Server-sent_events)
* includes a fallback for older browsers and IE
*
- * use server side events with causion, to many open requests can hang the server
+ * use server side events with caution, to many open requests can hang the server
*/
class OC_EventSource{
private $fallback;
@@ -43,6 +43,7 @@ class OC_EventSource{
header("Content-Type: text/event-stream");
}
if( !OC_Util::isCallRegistered()) {
+ $this->send('error', 'Possible CSRF attack. Connection will be closed.');
exit();
}
flush();
@@ -51,10 +52,10 @@ class OC_EventSource{
/**
* send a message to the client
- * @param string type
- * @param object data
+ * @param string $type
+ * @param object $data
*
- * if only one paramater is given, a typeless message will be send with that paramater as data
+ * if only one parameter is given, a typeless message will be send with that parameter as data
*/
public function send($type, $data=null) {
if(is_null($data)) {
diff --git a/lib/files.php b/lib/files.php
index 04ba51d9d24..f5dffd970d2 100644
--- a/lib/files.php
+++ b/lib/files.php
@@ -46,6 +46,7 @@ class OC_Files {
public static function get($dir, $files, $only_header = false) {
$xsendfile = false;
if (isset($_SERVER['MOD_X_SENDFILE_ENABLED']) ||
+ isset($_SERVER['MOD_X_SENDFILE2_ENABLED']) ||
isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) {
$xsendfile = true;
}
@@ -59,11 +60,7 @@ class OC_Files {
$executionTime = intval(ini_get('max_execution_time'));
set_time_limit(0);
$zip = new ZipArchive();
- if ($xsendfile) {
- $filename = OC_Helper::tmpFileNoClean('.zip');
- }else{
- $filename = OC_Helper::tmpFile('.zip');
- }
+ $filename = OC_Helper::tmpFile('.zip');
if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) {
exit("cannot open <$filename>\n");
}
@@ -78,6 +75,9 @@ class OC_Files {
}
}
$zip->close();
+ if ($xsendfile) {
+ $filename = OC_Helper::moveToNoClean($filename);
+ }
$basename = basename($dir);
if ($basename) {
$name = $basename . '.zip';
@@ -91,17 +91,16 @@ class OC_Files {
$executionTime = intval(ini_get('max_execution_time'));
set_time_limit(0);
$zip = new ZipArchive();
- if ($xsendfile) {
- $filename = OC_Helper::tmpFileNoClean('.zip');
- }else{
- $filename = OC_Helper::tmpFile('.zip');
- }
+ $filename = OC_Helper::tmpFile('.zip');
if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) {
exit("cannot open <$filename>\n");
}
$file = $dir . '/' . $files;
self::zipAddDir($file, $zip);
$zip->close();
+ if ($xsendfile) {
+ $filename = OC_Helper::moveToNoClean($filename);
+ }
$name = $files . '.zip';
set_time_limit($executionTime);
} else {
@@ -125,8 +124,11 @@ class OC_Files {
header('Content-Length: ' . filesize($filename));
self::addSendfileHeader($filename);
}else{
+ $filesize = \OC\Files\Filesystem::filesize($filename);
header('Content-Type: '.\OC\Files\Filesystem::getMimeType($filename));
- header("Content-Length: ".\OC\Files\Filesystem::filesize($filename));
+ if ($filesize > -1) {
+ header("Content-Length: ".$filesize);
+ }
list($storage) = \OC\Files\Filesystem::resolvePath($filename);
if ($storage instanceof \OC\Files\Storage\Local) {
self::addSendfileHeader(\OC\Files\Filesystem::getLocalFile($filename));
@@ -169,7 +171,22 @@ class OC_Files {
private static function addSendfileHeader($filename) {
if (isset($_SERVER['MOD_X_SENDFILE_ENABLED'])) {
header("X-Sendfile: " . $filename);
+ }
+ if (isset($_SERVER['MOD_X_SENDFILE2_ENABLED'])) {
+ if (isset($_SERVER['HTTP_RANGE']) &&
+ preg_match("/^bytes=([0-9]+)-([0-9]*)$/", $_SERVER['HTTP_RANGE'], $range)) {
+ $filelength = filesize($filename);
+ if ($range[2] == "") {
+ $range[2] = $filelength - 1;
+ }
+ header("Content-Range: bytes $range[1]-$range[2]/" . $filelength);
+ header("HTTP/1.1 206 Partial content");
+ header("X-Sendfile2: " . str_replace(",", "%2c", rawurlencode($filename)) . " $range[1]-$range[2]");
+ } else {
+ header("X-Sendfile: " . $filename);
+ }
}
+
if (isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) {
header("X-Accel-Redirect: " . $filename);
}
diff --git a/lib/files/cache/backgroundwatcher.php b/lib/files/cache/backgroundwatcher.php
new file mode 100644
index 00000000000..923804f48d0
--- /dev/null
+++ b/lib/files/cache/backgroundwatcher.php
@@ -0,0 +1,104 @@
+<?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\Cache;
+
+use \OC\Files\Mount;
+use \OC\Files\Filesystem;
+
+class BackgroundWatcher {
+ static $folderMimetype = null;
+
+ static private function getFolderMimetype() {
+ if (!is_null(self::$folderMimetype)) {
+ return self::$folderMimetype;
+ }
+ $sql = 'SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?';
+ $result = \OC_DB::executeAudited($sql, array('httpd/unix-directory'));
+ $row = $result->fetchRow();
+ return $row['id'];
+ }
+
+ static private function checkUpdate($id) {
+ $cacheItem = Cache::getById($id);
+ if (is_null($cacheItem)) {
+ return;
+ }
+ list($storageId, $internalPath) = $cacheItem;
+ $mounts = Filesystem::getMountByStorageId($storageId);
+
+ if (count($mounts) === 0) {
+ //if the storage we need isn't mounted on default, try to find a user that has access to the storage
+ $permissionsCache = new Permissions($storageId);
+ $users = $permissionsCache->getUsers($id);
+ if (count($users) === 0) {
+ return;
+ }
+ Filesystem::initMountPoints($users[0]);
+ $mounts = Filesystem::getMountByStorageId($storageId);
+ if (count($mounts) === 0) {
+ return;
+ }
+ }
+ $storage = $mounts[0]->getStorage();
+ $watcher = new Watcher($storage);
+ $watcher->checkUpdate($internalPath);
+ }
+
+ /**
+ * get the next fileid in the cache
+ *
+ * @param int $previous
+ * @param bool $folder
+ * @return int
+ */
+ static private function getNextFileId($previous, $folder) {
+ if ($folder) {
+ $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` = ? ORDER BY `fileid` ASC', 1);
+ } else {
+ $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` != ? ORDER BY `fileid` ASC', 1);
+ }
+ $result = \OC_DB::executeAudited($stmt, array($previous,self::getFolderMimetype()));
+ if ($row = $result->fetchRow()) {
+ return $row['fileid'];
+ } else {
+ return 0;
+ }
+ }
+
+ static public function checkNext() {
+ // check both 1 file and 1 folder, this way new files are detected quicker because there are less folders than files usually
+ $previousFile = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_file', 0);
+ $previousFolder = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_folder', 0);
+ $nextFile = self::getNextFileId($previousFile, false);
+ $nextFolder = self::getNextFileId($previousFolder, true);
+ \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_file', $nextFile);
+ \OC_Appconfig::setValue('files', 'backgroundwatcher_previous_folder', $nextFolder);
+ if ($nextFile > 0) {
+ self::checkUpdate($nextFile);
+ }
+ if ($nextFolder > 0) {
+ self::checkUpdate($nextFolder);
+ }
+ }
+
+ static public function checkAll() {
+ $previous = 0;
+ $next = 1;
+ while ($next != 0) {
+ $next = self::getNextFileId($previous, true);
+ self::checkUpdate($next);
+ }
+ $previous = 0;
+ $next = 1;
+ while ($next != 0) {
+ $next = self::getNextFileId($previous, false);
+ self::checkUpdate($next);
+ }
+ }
+}
diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php
index 91bcb73a55d..3818fdbd840 100644
--- a/lib/files/cache/cache.php
+++ b/lib/files/cache/cache.php
@@ -30,11 +30,9 @@ class Cache {
private $storageId;
/**
- * numeric storage id
- *
- * @var int $numericId
+ * @var Storage $storageCache
*/
- private $numericId;
+ private $storageCache;
private $mimetypeIds = array();
private $mimetypes = array();
@@ -52,19 +50,11 @@ class Cache {
$this->storageId = md5($this->storageId);
}
- $query = \OC_DB::prepare('SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?');
- $result = $query->execute(array($this->storageId));
- if ($row = $result->fetchRow()) {
- $this->numericId = $row['numeric_id'];
- } else {
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*storages`(`id`) VALUES(?)');
- $query->execute(array($this->storageId));
- $this->numericId = \OC_DB::insertid('*PREFIX*storages');
- }
+ $this->storageCache = new Storage($storage);
}
public function getNumericStorageId() {
- return $this->numericId;
+ return $this->storageCache->getNumericId();
}
/**
@@ -75,13 +65,11 @@ class Cache {
*/
public function getMimetypeId($mime) {
if (!isset($this->mimetypeIds[$mime])) {
- $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?');
- $result = $query->execute(array($mime));
+ $result = \OC_DB::executeAudited('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?', array($mime));
if ($row = $result->fetchRow()) {
$this->mimetypeIds[$mime] = $row['id'];
} else {
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*mimetypes`(`mimetype`) VALUES(?)');
- $query->execute(array($mime));
+ $result = \OC_DB::executeAudited('INSERT INTO `*PREFIX*mimetypes`(`mimetype`) VALUES(?)', array($mime));
$this->mimetypeIds[$mime] = \OC_DB::insertid('*PREFIX*mimetypes');
}
$this->mimetypes[$this->mimetypeIds[$mime]] = $mime;
@@ -91,8 +79,8 @@ class Cache {
public function getMimetype($id) {
if (!isset($this->mimetypes[$id])) {
- $query = \OC_DB::prepare('SELECT `mimetype` FROM `*PREFIX*mimetypes` WHERE `id` = ?');
- $result = $query->execute(array($id));
+ $sql = 'SELECT `mimetype` FROM `*PREFIX*mimetypes` WHERE `id` = ?';
+ $result = \OC_DB::executeAudited($sql, array($id));
if ($row = $result->fetchRow()) {
$this->mimetypes[$id] = $row['mimetype'];
} else {
@@ -106,22 +94,31 @@ class Cache {
* get the stored metadata of a file or folder
*
* @param string/int $file
- * @return array
+ * @return array | false
*/
public function get($file) {
if (is_string($file) or $file == '') {
+ // normalize file
+ $file = $this->normalize($file);
+
$where = 'WHERE `storage` = ? AND `path_hash` = ?';
- $params = array($this->numericId, md5($file));
+ $params = array($this->getNumericStorageId(), md5($file));
} else { //file id
$where = 'WHERE `fileid` = ?';
$params = array($file);
}
- $query = \OC_DB::prepare(
- 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
- FROM `*PREFIX*filecache` ' . $where);
- $result = $query->execute($params);
+ $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
+ `storage_mtime`, `encrypted`, `unencrypted_size`, `etag`
+ FROM `*PREFIX*filecache` ' . $where;
+ $result = \OC_DB::executeAudited($sql, $params);
$data = $result->fetchRow();
+ //FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO
+ //PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false
+ if ($data === null) {
+ $data = false;
+ }
+
//merge partial data
if (!$data and is_string($file)) {
if (isset($this->partial[$file])) {
@@ -133,9 +130,13 @@ class Cache {
$data['size'] = (int)$data['size'];
$data['mtime'] = (int)$data['mtime'];
$data['encrypted'] = (bool)$data['encrypted'];
+ $data['unencrypted_size'] = (int)$data['unencrypted_size'];
$data['storage'] = $this->storageId;
$data['mimetype'] = $this->getMimetype($data['mimetype']);
$data['mimepart'] = $this->getMimetype($data['mimepart']);
+ if ($data['storage_mtime'] == 0) {
+ $data['storage_mtime'] = $data['mtime'];
+ }
}
return $data;
@@ -150,14 +151,17 @@ class Cache {
public function getFolderContents($folder) {
$fileId = $this->getId($folder);
if ($fileId > -1) {
- $query = \OC_DB::prepare(
- 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
- FROM `*PREFIX*filecache` WHERE parent = ? ORDER BY `name` ASC');
- $result = $query->execute(array($fileId));
+ $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
+ `storage_mtime`, `encrypted`, `unencrypted_size`, `etag`
+ FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC';
+ $result = \OC_DB::executeAudited($sql,array($fileId));
$files = $result->fetchAll();
foreach ($files as &$file) {
$file['mimetype'] = $this->getMimetype($file['mimetype']);
$file['mimepart'] = $this->getMimetype($file['mimepart']);
+ if ($file['storage_mtime'] == 0) {
+ $file['storage_mtime'] = $file['mtime'];
+ }
}
return $files;
} else {
@@ -178,6 +182,9 @@ class Cache {
$this->update($id, $data);
return $id;
} else {
+ // normalize file
+ $file = $this->normalize($file);
+
if (isset($this->partial[$file])) { //add any saved partial data
$data = array_merge($this->partial[$file], $data);
unset($this->partial[$file]);
@@ -198,15 +205,12 @@ class Cache {
list($queryParts, $params) = $this->buildParts($data);
$queryParts[] = '`storage`';
- $params[] = $this->numericId;
+ $params[] = $this->getNumericStorageId();
$valuesPlaceholder = array_fill(0, count($queryParts), '?');
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`(' . implode(', ', $queryParts) . ')'
- . ' VALUES(' . implode(', ', $valuesPlaceholder) . ')');
- $result = $query->execute($params);
- if (\OC_DB::isError($result)) {
- \OCP\Util::writeLog('cache', 'Insert to cache failed: '.$result, \OCP\Util::ERROR);
- }
+ $sql = 'INSERT INTO `*PREFIX*filecache` (' . implode(', ', $queryParts) . ')'
+ . ' VALUES (' . implode(', ', $valuesPlaceholder) . ')';
+ \OC_DB::executeAudited($sql, $params);
return (int)\OC_DB::insertid('*PREFIX*filecache');
}
@@ -219,12 +223,22 @@ class Cache {
* @param array $data
*/
public function update($id, array $data) {
+
+ if(isset($data['path'])) {
+ // normalize path
+ $data['path'] = $this->normalize($data['path']);
+ }
+
+ if(isset($data['name'])) {
+ // normalize path
+ $data['name'] = $this->normalize($data['name']);
+ }
+
list($queryParts, $params) = $this->buildParts($data);
$params[] = $id;
- $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=?'
- . ' WHERE fileid = ?');
- $query->execute($params);
+ $sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? WHERE `fileid` = ?';
+ \OC_DB::executeAudited($sql, $params);
}
/**
@@ -234,7 +248,7 @@ class Cache {
* @return array
*/
function buildParts(array $data) {
- $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted', 'etag');
+ $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'unencrypted_size', 'etag');
$params = array();
$queryParts = array();
foreach ($data as $name => $value) {
@@ -246,6 +260,11 @@ class Cache {
$params[] = $this->getMimetypeId(substr($value, 0, strpos($value, '/')));
$queryParts[] = '`mimepart`';
$value = $this->getMimetypeId($value);
+ } elseif ($name === 'storage_mtime') {
+ if (!isset($data['mtime'])) {
+ $params[] = $value;
+ $queryParts[] = '`mtime`';
+ }
}
$params[] = $value;
$queryParts[] = '`' . $name . '`';
@@ -261,11 +280,13 @@ class Cache {
* @return int
*/
public function getId($file) {
- $pathHash = md5($file);
+ // normalize file
+ $file = $this->normalize($file);
- $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?');
- $result = $query->execute(array($this->numericId, $pathHash));
+ $pathHash = md5($file);
+ $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
+ $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $pathHash));
if ($row = $result->fetchRow()) {
return $row['fileid'];
} else {
@@ -314,8 +335,9 @@ class Cache {
$this->remove($child['path']);
}
}
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?');
- $query->execute(array($entry['fileid']));
+
+ $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?';
+ \OC_DB::executeAudited($sql, array($entry['fileid']));
$permissionsCache = new Permissions($this->storageId);
$permissionsCache->remove($entry['fileid']);
@@ -328,35 +350,41 @@ class Cache {
* @param string $target
*/
public function move($source, $target) {
- $sourceId = $this->getId($source);
- $newParentId = $this->getParentId($target);
+ // normalize source and target
+ $source = $this->normalize($source);
+ $target = $this->normalize($target);
- //find all child entries
- $query = \OC_DB::prepare('SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `path` LIKE ?');
- $result = $query->execute(array($source . '/%'));
- $childEntries = $result->fetchAll();
- $sourceLength = strlen($source);
- $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
+ $sourceData = $this->get($source);
+ $sourceId = $sourceData['fileid'];
+ $newParentId = $this->getParentId($target);
- foreach ($childEntries as $child) {
- $targetPath = $target . substr($child['path'], $sourceLength);
- $query->execute(array($targetPath, md5($targetPath), $child['fileid']));
+ if ($sourceData['mimetype'] === 'httpd/unix-directory') {
+ //find all child entries
+ $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
+ $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $source . '/%'));
+ $childEntries = $result->fetchAll();
+ $sourceLength = strlen($source);
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
+
+ foreach ($childEntries as $child) {
+ $targetPath = $target . substr($child['path'], $sourceLength);
+ \OC_DB::executeAudited($query, array($targetPath, md5($targetPath), $child['fileid']));
+ }
}
- $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `parent` =?'
- . ' WHERE `fileid` = ?');
- $query->execute(array($target, md5($target), $newParentId, $sourceId));
+ $sql = 'UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?';
+ \OC_DB::executeAudited($sql, array($target, md5($target), basename($target), $newParentId, $sourceId));
}
/**
* remove all entries for files that are stored on the storage from the cache
*/
public function clear() {
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE storage = ?');
- $query->execute(array($this->numericId));
+ $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
+ \OC_DB::executeAudited($sql, array($this->getNumericStorageId()));
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*storages` WHERE id = ?');
- $query->execute(array($this->storageId));
+ $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
+ \OC_DB::executeAudited($sql, array($this->storageId));
}
/**
@@ -365,9 +393,12 @@ class Cache {
* @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
*/
public function getStatus($file) {
+ // normalize file
+ $file = $this->normalize($file);
+
$pathHash = md5($file);
- $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?');
- $result = $query->execute(array($this->numericId, $pathHash));
+ $sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
+ $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId(), $pathHash));
if ($row = $result->fetchRow()) {
if ((int)$row['size'] === -1) {
return self::SHALLOW;
@@ -390,11 +421,13 @@ class Cache {
* @return array of file data
*/
public function search($pattern) {
- $query = \OC_DB::prepare('
- SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
- FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?'
- );
- $result = $query->execute(array($pattern, $this->numericId));
+
+ // normalize pattern
+ $pattern = $this->normalize($pattern);
+
+ $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag`
+ FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?';
+ $result = \OC_DB::executeAudited($sql, array($pattern, $this->getNumericStorageId()));
$files = array();
while ($row = $result->fetchRow()) {
$row['mimetype'] = $this->getMimetype($row['mimetype']);
@@ -416,12 +449,10 @@ class Cache {
} else {
$where = '`mimepart` = ?';
}
- $query = \OC_DB::prepare('
- SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
- FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'
- );
+ $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag`
+ FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?';
$mimetype = $this->getMimetypeId($mimetype);
- $result = $query->execute(array($mimetype, $this->numericId));
+ $result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId()));
$files = array();
while ($row = $result->fetchRow()) {
$row['mimetype'] = $this->getMimetype($row['mimetype']);
@@ -440,7 +471,7 @@ class Cache {
$this->calculateFolderSize($path);
if ($path !== '') {
$parent = dirname($path);
- if ($parent === '.') {
+ if ($parent === '.' or $parent === '/') {
$parent = '';
}
$this->correctFolderSize($parent);
@@ -458,8 +489,8 @@ class Cache {
if ($id === -1) {
return 0;
}
- $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*filecache` WHERE `parent` = ? AND `storage` = ?');
- $result = $query->execute(array($id, $this->numericId));
+ $sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `parent` = ? AND `storage` = ?';
+ $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId()));
$totalSize = 0;
$hasChilds = 0;
while ($row = $result->fetchRow()) {
@@ -485,8 +516,8 @@ class Cache {
* @return int[]
*/
public function getAll() {
- $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?');
- $result = $query->execute(array($this->numericId));
+ $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?';
+ $result = \OC_DB::executeAudited($sql, array($this->getNumericStorageId()));
$ids = array();
while ($row = $result->fetchRow()) {
$ids[] = $row['fileid'];
@@ -505,8 +536,8 @@ class Cache {
*/
public function getIncomplete() {
$query = \OC_DB::prepare('SELECT `path` FROM `*PREFIX*filecache`'
- . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC LIMIT 1');
- $result = $query->execute(array($this->numericId));
+ . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC',1);
+ $result = \OC_DB::executeAudited($query, array($this->getNumericStorageId()));
if ($row = $result->fetchRow()) {
return $row['path'];
} else {
@@ -517,11 +548,12 @@ class Cache {
/**
* get the storage id of the storage for a file and the internal path of the file
*
+ * @param int $id
* @return array, first element holding the storage id, second the path
*/
static public function getById($id) {
- $query = \OC_DB::prepare('SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?');
- $result = $query->execute(array($id));
+ $sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
+ $result = \OC_DB::executeAudited($sql, array($id));
if ($row = $result->fetchRow()) {
$numericId = $row['storage'];
$path = $row['path'];
@@ -529,12 +561,20 @@ class Cache {
return null;
}
- $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?');
- $result = $query->execute(array($numericId));
- if ($row = $result->fetchRow()) {
- return array($row['id'], $path);
+ if ($id = Storage::getStorageId($numericId)) {
+ return array($id, $path);
} else {
return null;
}
}
+
+ /**
+ * normalize the given path
+ * @param $path
+ * @return string
+ */
+ public function normalize($path) {
+
+ return \OC_Util::normalizeUnicode($path);
+ }
}
diff --git a/lib/files/cache/legacy.php b/lib/files/cache/legacy.php
index 2b8689fcbda..8eed1f67a5d 100644
--- a/lib/files/cache/legacy.php
+++ b/lib/files/cache/legacy.php
@@ -20,9 +20,14 @@ class Legacy {
$this->user = $user;
}
+ /**
+ * get the numbers of items in the legacy cache
+ *
+ * @return int
+ */
function getCount() {
- $query = \OC_DB::prepare('SELECT COUNT(`id`) AS `count` FROM `*PREFIX*fscache` WHERE `user` = ?');
- $result = $query->execute(array($this->user));
+ $sql = 'SELECT COUNT(`id`) AS `count` FROM `*PREFIX*fscache` WHERE `user` = ?';
+ $result = \OC_DB::executeAudited($sql, array($this->user));
if ($row = $result->fetchRow()) {
return $row['count'];
} else {
@@ -40,7 +45,7 @@ class Legacy {
return $this->cacheHasItems;
}
try {
- $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `user` = ? LIMIT 1');
+ $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `user` = ?',1);
} catch (\Exception $e) {
$this->cacheHasItems = false;
return false;
@@ -62,26 +67,70 @@ class Legacy {
}
/**
+ * get an item from the legacy cache
+ *
* @param string|int $path
* @return array
*/
function get($path) {
if (is_numeric($path)) {
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `id` = ?');
+ $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `id` = ?';
} else {
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?');
+ $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?';
}
- $result = $query->execute(array($path));
- return $result->fetchRow();
+ $result = \OC_DB::executeAudited($sql, array($path));
+ $data = $result->fetchRow();
+ $data['etag'] = $this->getEtag($data['path'], $data['user']);
+ return $data;
}
/**
+ * Get the ETag for the given path
+ *
+ * @param type $path
+ * @return string
+ */
+ function getEtag($path, $user = null) {
+ static $query = null;
+
+ $pathDetails = explode('/', $path, 4);
+ if((!$user) && !isset($pathDetails[1])) {
+ //no user!? Too odd, return empty string.
+ return '';
+ } else if(!$user) {
+ //guess user from path, if no user passed.
+ $user = $pathDetails[1];
+ }
+
+ if(!isset($pathDetails[3]) || is_null($pathDetails[3])) {
+ $relativePath = '';
+ } else {
+ $relativePath = $pathDetails[3];
+ }
+
+ if(is_null($query)){
+ $query = \OC_DB::prepare('SELECT `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = \'{DAV:}getetag\'');
+ }
+ $result = \OC_DB::executeAudited($query,array($user, '/' . $relativePath));
+ if ($row = $result->fetchRow()) {
+ return trim($row['propertyvalue'], '"');
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * get all child items of an item from the legacy cache
+ *
* @param int $id
* @return array
*/
function getChildren($id) {
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?');
- $result = $query->execute(array($id));
- return $result->fetchAll();
+ $result = \OC_DB::executeAudited('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?', array($id));
+ $data = $result->fetchAll();
+ foreach ($data as $i => $item) {
+ $data[$i]['etag'] = $this->getEtag($item['path'], $item['user']);
+ }
+ return $data;
}
}
diff --git a/lib/files/cache/permissions.php b/lib/files/cache/permissions.php
index a5c9c144054..2e2bdb20b78 100644
--- a/lib/files/cache/permissions.php
+++ b/lib/files/cache/permissions.php
@@ -33,8 +33,8 @@ class Permissions {
* @return int (-1 if file no permissions set)
*/
public function get($fileId, $user) {
- $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*permissions` WHERE `user` = ? AND `fileid` = ?');
- $result = $query->execute(array($user, $fileId));
+ $sql = 'SELECT `permissions` FROM `*PREFIX*permissions` WHERE `user` = ? AND `fileid` = ?';
+ $result = \OC_DB::executeAudited($sql, array($user, $fileId));
if ($row = $result->fetchRow()) {
return $row['permissions'];
} else {
@@ -51,13 +51,11 @@ class Permissions {
*/
public function set($fileId, $user, $permissions) {
if (self::get($fileId, $user) !== -1) {
- $query = \OC_DB::prepare('UPDATE `*PREFIX*permissions` SET `permissions` = ?'
- . ' WHERE `user` = ? AND `fileid` = ?');
+ $sql = 'UPDATE `*PREFIX*permissions` SET `permissions` = ? WHERE `user` = ? AND `fileid` = ?';
} else {
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*permissions`(`permissions`, `user`, `fileid`)'
- . ' VALUES(?, ?,? )');
+ $sql = 'INSERT INTO `*PREFIX*permissions`(`permissions`, `user`, `fileid`) VALUES(?, ?,? )';
}
- $query->execute(array($permissions, $user, $fileId));
+ \OC_DB::executeAudited($sql, array($permissions, $user, $fileId));
}
/**
@@ -75,9 +73,30 @@ class Permissions {
$params[] = $user;
$inPart = implode(', ', array_fill(0, count($fileIds), '?'));
- $query = \OC_DB::prepare('SELECT `fileid`, `permissions` FROM `*PREFIX*permissions`'
- . ' WHERE `fileid` IN (' . $inPart . ') AND `user` = ?');
- $result = $query->execute($params);
+ $sql = 'SELECT `fileid`, `permissions` FROM `*PREFIX*permissions`'
+ . ' WHERE `fileid` IN (' . $inPart . ') AND `user` = ?';
+ $result = \OC_DB::executeAudited($sql, $params);
+ $filePermissions = array();
+ while ($row = $result->fetchRow()) {
+ $filePermissions[$row['fileid']] = $row['permissions'];
+ }
+ return $filePermissions;
+ }
+
+ /**
+ * get the permissions for all files in a folder
+ *
+ * @param int $parentId
+ * @param string $user
+ * @return int[]
+ */
+ public function getDirectoryPermissions($parentId, $user) {
+ $sql = 'SELECT `*PREFIX*permissions`.`fileid`, `permissions`
+ FROM `*PREFIX*permissions`
+ INNER JOIN `*PREFIX*filecache` ON `*PREFIX*permissions`.`fileid` = `*PREFIX*filecache`.`fileid`
+ WHERE `*PREFIX*filecache`.`parent` = ? AND `*PREFIX*permissions`.`user` = ?';
+
+ $result = \OC_DB::executeAudited($sql, array($parentId, $user));
$filePermissions = array();
while ($row = $result->fetchRow()) {
$filePermissions[$row['fileid']] = $row['permissions'];
@@ -93,18 +112,32 @@ class Permissions {
*/
public function remove($fileId, $user = null) {
if (is_null($user)) {
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ?');
- $query->execute(array($fileId));
+ \OC_DB::executeAudited('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ?', array($fileId));
} else {
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?');
- $query->execute(array($fileId, $user));
+ $sql = 'DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?';
+ \OC_DB::executeAudited($sql, array($fileId, $user));
}
}
public function removeMultiple($fileIds, $user) {
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?');
foreach ($fileIds as $fileId) {
- $query->execute(array($fileId, $user));
+ \OC_DB::executeAudited($query, array($fileId, $user));
+ }
+ }
+
+ /**
+ * get the list of users which have permissions stored for a file
+ *
+ * @param int $fileId
+ */
+ public function getUsers($fileId) {
+ $sql = 'SELECT `user` FROM `*PREFIX*permissions` WHERE `fileid` = ?';
+ $result = \OC_DB::executeAudited($sql, array($fileId));
+ $users = array();
+ while ($row = $result->fetchRow()) {
+ $users[] = $row['user'];
}
+ return $users;
}
}
diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php
index f285f3bed11..9b94a24f481 100644
--- a/lib/files/cache/scanner.php
+++ b/lib/files/cache/scanner.php
@@ -8,6 +8,8 @@
namespace OC\Files\Cache;
+use OC\Files\Filesystem;
+
class Scanner {
/**
* @var \OC\Files\Storage\Storage $storage
@@ -27,6 +29,9 @@ class Scanner {
const SCAN_RECURSIVE = true;
const SCAN_SHALLOW = false;
+ const REUSE_ETAG = 1;
+ const REUSE_SIZE = 2;
+
public function __construct(\OC\Files\Storage\Storage $storage) {
$this->storage = $storage;
$this->storageId = $this->storage->getId();
@@ -51,6 +56,7 @@ class Scanner {
$data['size'] = $this->storage->filesize($path);
}
$data['etag'] = $this->storage->getETag($path);
+ $data['storage_mtime'] = $data['mtime'];
return $data;
}
@@ -58,85 +64,122 @@ class Scanner {
* scan a single file and store it in the cache
*
* @param string $file
- * @param bool $checkExisting check existing folder sizes in the cache instead of always using -1 for folder size
+ * @param int $reuseExisting
* @return array with metadata of the scanned file
*/
- public function scanFile($file, $checkExisting = false) {
- \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId));
- $data = $this->getData($file);
- if ($data) {
- if ($file) {
- $parent = dirname($file);
- if ($parent === '.') {
- $parent = '';
+ public function scanFile($file, $reuseExisting = 0) {
+ if (!self::isPartialFile($file)
+ and !Filesystem::isFileBlacklisted($file)
+ ) {
+ \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId));
+ $data = $this->getData($file);
+ if ($data) {
+ if ($file) {
+ $parent = dirname($file);
+ if ($parent === '.' or $parent === '/') {
+ $parent = '';
+ }
+ if (!$this->cache->inCache($parent)) {
+ $this->scanFile($parent);
+ }
}
- if (!$this->cache->inCache($parent)) {
- $this->scanFile($parent);
+ $newData = $data;
+ if ($reuseExisting and $cacheData = $this->cache->get($file)) {
+ // only reuse data if the file hasn't explicitly changed
+ if ($data['mtime'] === $cacheData['mtime']) {
+ if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) {
+ $data['size'] = $cacheData['size'];
+ }
+ if ($reuseExisting & self::REUSE_ETAG) {
+ $data['etag'] = $cacheData['etag'];
+ }
+ }
+ // Only update metadata that has changed
+ $newData = array_diff($data, $cacheData);
}
}
- if ($checkExisting and $cacheData = $this->cache->get($file)) {
- if ($data['size'] === -1) {
- $data['size'] = $cacheData['size'];
- }
- if ($data['mtime'] === $cacheData['mtime']) {
- $data['etag'] = $cacheData['etag'];
- }
+ if (!empty($newData)) {
+ $this->cache->put($file, $newData);
}
- $this->cache->put($file, $data);
+ return $data;
}
- return $data;
+ return null;
}
/**
- * scan all the files in a folder and store them in the cache
+ * scan a folder and all it's children
*
* @param string $path
- * @param SCAN_RECURSIVE/SCAN_SHALLOW $recursive
- * @param bool $onlyChilds
+ * @param bool $recursive
+ * @param int $reuse
* @return int the size of the scanned folder or -1 if the size is unknown at this stage
*/
- public function scan($path, $recursive = self::SCAN_RECURSIVE, $onlyChilds = false) {
- \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_folder', array('path' => $path, 'storage' => $this->storageId));
- $childQueue = array();
- if (!$onlyChilds) {
- $this->scanFile($path);
+ public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) {
+ if ($reuse === -1) {
+ $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : 0;
}
+ $this->scanFile($path, $reuse);
+ return $this->scanChildren($path, $recursive, $reuse);
+ }
+ /**
+ * scan all the files and folders in a folder
+ *
+ * @param string $path
+ * @param bool $recursive
+ * @param int $reuse
+ * @return int the size of the scanned folder or -1 if the size is unknown at this stage
+ */
+ public function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) {
+ if ($reuse === -1) {
+ $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : 0;
+ }
+ \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_folder', array('path' => $path, 'storage' => $this->storageId));
$size = 0;
+ $childQueue = array();
+ $existingChildren = array();
+ if ($this->cache->inCache($path)) {
+ $children = $this->cache->getFolderContents($path);
+ foreach ($children as $child) {
+ $existingChildren[] = $child['name'];
+ }
+ }
+ $newChildren = array();
if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) {
\OC_DB::beginTransaction();
while ($file = readdir($dh)) {
- if (!$this->isIgnoredFile($file)) {
- $child = ($path) ? $path . '/' . $file : $file;
- $data = $this->scanFile($child, $recursive === self::SCAN_SHALLOW);
+ $child = ($path) ? $path . '/' . $file : $file;
+ if (!Filesystem::isIgnoredDir($file)) {
+ $newChildren[] = $file;
+ $data = $this->scanFile($child, $reuse);
if ($data) {
if ($data['size'] === -1) {
if ($recursive === self::SCAN_RECURSIVE) {
$childQueue[] = $child;
- $data['size'] = 0;
} else {
$size = -1;
}
- }
-
- if ($size !== -1) {
+ } else if ($size !== -1) {
$size += $data['size'];
}
}
}
}
+ $removedChildren = \array_diff($existingChildren, $newChildren);
+ foreach ($removedChildren as $childName) {
+ $child = ($path) ? $path . '/' . $childName : $childName;
+ $this->cache->remove($child);
+ }
\OC_DB::commit();
foreach ($childQueue as $child) {
- $childSize = $this->scan($child, self::SCAN_RECURSIVE, true);
+ $childSize = $this->scanChildren($child, self::SCAN_RECURSIVE);
if ($childSize === -1) {
$size = -1;
} else {
$size += $childSize;
}
}
- if ($size !== -1) {
- $this->cache->put($path, array('size' => $size));
- }
+ $this->cache->put($path, array('size' => $size));
}
return $size;
}
@@ -148,11 +191,8 @@ class Scanner {
* @param String $file
* @return boolean
*/
- private function isIgnoredFile($file) {
- if ($file === '.' || $file === '..'
- || pathinfo($file, PATHINFO_EXTENSION) === 'part'
- || \OC\Files\Filesystem::isFileBlacklisted($file)
- ) {
+ public static function isPartialFile($file) {
+ if (pathinfo($file, PATHINFO_EXTENSION) === 'part') {
return true;
}
return false;
@@ -162,9 +202,11 @@ class Scanner {
* walk over any folders that are not fully scanned yet and scan them
*/
public function backgroundScan() {
- while (($path = $this->cache->getIncomplete()) !== false) {
+ $lastPath = null;
+ while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) {
$this->scan($path);
$this->cache->correctFolderSize($path);
+ $lastPath = $path;
}
}
}
diff --git a/lib/files/cache/storage.php b/lib/files/cache/storage.php
new file mode 100644
index 00000000000..8a9e47ca36d
--- /dev/null
+++ b/lib/files/cache/storage.php
@@ -0,0 +1,60 @@
+<?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\Cache;
+
+/**
+ * Class Storage
+ *
+ * cache storage specific data
+ *
+ * @package OC\Files\Cache
+ */
+class Storage {
+ private $storageId;
+ private $numericId;
+
+ /**
+ * @param \OC\Files\Storage\Storage|string $storage
+ */
+ public function __construct($storage) {
+ if ($storage instanceof \OC\Files\Storage\Storage) {
+ $this->storageId = $storage->getId();
+ } else {
+ $this->storageId = $storage;
+ }
+ if (strlen($this->storageId) > 64) {
+ $this->storageId = md5($this->storageId);
+ }
+
+ $sql = 'SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?';
+ $result = \OC_DB::executeAudited($sql, array($this->storageId));
+ if ($row = $result->fetchRow()) {
+ $this->numericId = $row['numeric_id'];
+ } else {
+ $sql = 'INSERT INTO `*PREFIX*storages` (`id`) VALUES(?)';
+ \OC_DB::executeAudited($sql, array($this->storageId));
+ $this->numericId = \OC_DB::insertid('*PREFIX*storages');
+ }
+ }
+
+ public function getNumericId() {
+ return $this->numericId;
+ }
+
+ public static function getStorageId($numericId) {
+
+ $sql = 'SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?';
+ $result = \OC_DB::executeAudited($sql, array($numericId));
+ if ($row = $result->fetchRow()) {
+ return $row['id'];
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/lib/files/cache/updater.php b/lib/files/cache/updater.php
index e760ba71bc6..1f30173a8f8 100644
--- a/lib/files/cache/updater.php
+++ b/lib/files/cache/updater.php
@@ -7,6 +7,7 @@
*/
namespace OC\Files\Cache;
+use OCP\Util;
/**
* listen to filesystem hooks and change the cache accordingly
@@ -16,7 +17,7 @@ class Updater {
/**
* resolve a path to a storage and internal path
*
- * @param string $path
+ * @param string $path the relative path
* @return array consisting of the storage and the internal path
*/
static public function resolvePath($path) {
@@ -24,6 +25,11 @@ class Updater {
return $view->resolvePath($path);
}
+ /**
+ * perform a write update
+ *
+ * @param string $path the relative path of the file
+ */
static public function writeUpdate($path) {
/**
* @var \OC\Files\Storage\Storage $storage
@@ -39,6 +45,11 @@ class Updater {
}
}
+ /**
+ * perform a delete update
+ *
+ * @param string $path the relative path of the file
+ */
static public function deleteUpdate($path) {
/**
* @var \OC\Files\Storage\Storage $storage
@@ -53,6 +64,12 @@ class Updater {
}
}
+ /**
+ * preform a rename update
+ *
+ * @param string $from the relative path of the source file
+ * @param string $to the relative path of the target file
+ */
static public function renameUpdate($from, $to) {
/**
* @var \OC\Files\Storage\Storage $storageFrom
@@ -86,7 +103,7 @@ class Updater {
static public function correctFolder($path, $time) {
if ($path !== '' && $path !== '/') {
$parent = dirname($path);
- if ($parent === '.') {
+ if ($parent === '.' || $parent === '\\') {
$parent = '';
}
/**
@@ -100,6 +117,8 @@ class Updater {
if ($id !== -1) {
$cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath)));
self::correctFolder($parent, $time);
+ } else {
+ Util::writeLog('core', 'Path not in cache: '.$internalPath, Util::ERROR);
}
}
}
@@ -115,6 +134,20 @@ class Updater {
/**
* @param array $params
*/
+ static public function touchHook($params) {
+ $path = $params['path'];
+ list($storage, $internalPath) = self::resolvePath($path);
+ $cache = $storage->getCache();
+ $id = $cache->getId($internalPath);
+ if ($id !== -1) {
+ $cache->update($id, array('etag' => $storage->getETag($internalPath)));
+ }
+ self::writeUpdate($path);
+ }
+
+ /**
+ * @param array $params
+ */
static public function renameHook($params) {
self::renameUpdate($params['oldpath'], $params['newpath']);
}
diff --git a/lib/files/cache/upgrade.php b/lib/files/cache/upgrade.php
index 230690d35c3..cfb9a117311 100644
--- a/lib/files/cache/upgrade.php
+++ b/lib/files/cache/upgrade.php
@@ -26,17 +26,16 @@ class Upgrade {
}
/**
- * Preform a shallow upgrade
+ * Preform a upgrade a path and it's childs
*
* @param string $path
- * @param int $mode
+ * @param bool $mode
*/
function upgradePath($path, $mode = Scanner::SCAN_RECURSIVE) {
if (!$this->legacy->hasItems()) {
return;
}
\OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $path);
-
if ($row = $this->legacy->get($path)) {
$data = $this->getNewData($row);
if ($data) {
@@ -47,7 +46,10 @@ class Upgrade {
}
/**
+ * upgrade all child elements of an item
+ *
* @param int $id
+ * @param bool $mode
*/
function upgradeChilds($id, $mode = Scanner::SCAN_RECURSIVE) {
$children = $this->legacy->getChildren($id);
@@ -64,29 +66,38 @@ class Upgrade {
}
/**
+ * insert data into the new cache
+ *
* @param array $data the data for the new cache
*/
function insert($data) {
- if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) {
+ static $insertQuery = null;
+ if(is_null($insertQuery)) {
$insertQuery = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`
- ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted` )
- VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
-
- $insertQuery->execute(array($data['id'], $data['storage'],
+ ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` )
+ VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
+ }
+ if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) {
+ \OC_DB::executeAudited($insertQuery, array($data['id'], $data['storage'],
$data['path'], $data['path_hash'], $data['parent'], $data['name'],
- $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted']));
+ $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'], $data['etag']));
}
}
/**
+ * check if an item is already in the new cache
+ *
* @param string $storage
* @param string $pathHash
* @param string $id
* @return bool
*/
function inCache($storage, $pathHash, $id) {
- $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?');
- $result = $query->execute(array($storage, $pathHash, $id));
+ static $query = null;
+ if(is_null($query)) {
+ $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?');
+ }
+ $result = \OC_DB::executeAudited($query, array($storage, $pathHash, $id));
return (bool)$result->fetchRow();
}
@@ -94,9 +105,32 @@ class Upgrade {
* get the new data array from the old one
*
* @param array $data the data from the old cache
+ * Example data array
+ * Array
+ * (
+ * [id] => 418
+ * [path] => /tina/files/picture.jpg //relative to datadir
+ * [path_hash] => 66d4547e372888deed80b24fec9b192b
+ * [parent] => 234
+ * [name] => picture.jpg
+ * [user] => tina
+ * [size] => 1265283
+ * [ctime] => 1363909709
+ * [mtime] => 1363909709
+ * [mimetype] => image/jpeg
+ * [mimepart] => image
+ * [encrypted] => 0
+ * [versioned] => 0
+ * [writable] => 1
+ * )
+ *
* @return array
*/
function getNewData($data) {
+ //Make sure there is a path, otherwise we can do nothing.
+ if(!isset($data['path'])) {
+ return false;
+ }
$newData = $data;
/**
* @var \OC\Files\Storage\Storage $storage
@@ -104,6 +138,7 @@ class Upgrade {
*/
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']);
if ($storage) {
+ $newData['etag'] = $data['etag'];
$newData['path_hash'] = md5($internalPath);
$newData['path'] = $internalPath;
$newData['storage'] = $this->getNumericId($storage);
@@ -135,6 +170,8 @@ class Upgrade {
}
/**
+ * get the numeric id for a mimetype
+ *
* @param string $mimetype
* @param \OC\Files\Storage\Storage $storage
* @return int
@@ -166,4 +203,25 @@ class Upgrade {
static function upgradeDone($user) {
\OCP\Config::setUserValue($user, 'files', 'cache_version', 5);
}
+
+ /**
+ * Does a "silent" upgrade, i.e. without an Event-Source as triggered
+ * on User-Login via Ajax. This method is called within the regular
+ * ownCloud upgrade.
+ *
+ * @param string $user a User ID
+ */
+ public static function doSilentUpgrade($user) {
+ if(!self::needUpgrade($user)) {
+ return;
+ }
+ $legacy = new \OC\Files\Cache\Legacy($user);
+ if ($legacy->hasItems()) {
+ \OC_DB::beginTransaction();
+ $upgrade = new \OC\Files\Cache\Upgrade($legacy);
+ $upgrade->upgradePath('/' . $user . '/files');
+ \OC_DB::commit();
+ }
+ \OC\Files\Cache\Upgrade::upgradeDone($user);
+ }
}
diff --git a/lib/files/cache/watcher.php b/lib/files/cache/watcher.php
index 31059ec7f56..8bfd4602f3a 100644
--- a/lib/files/cache/watcher.php
+++ b/lib/files/cache/watcher.php
@@ -43,7 +43,7 @@ class Watcher {
*/
public function checkUpdate($path) {
$cachedEntry = $this->cache->get($path);
- if ($this->storage->hasUpdated($path, $cachedEntry['mtime'])) {
+ if ($this->storage->hasUpdated($path, $cachedEntry['storage_mtime'])) {
if ($this->storage->is_dir($path)) {
$this->scanner->scan($path, Scanner::SCAN_SHALLOW);
} else {
diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php
index d32e082ade9..1bf7270c7f1 100644
--- a/lib/files/filesystem.php
+++ b/lib/files/filesystem.php
@@ -8,7 +8,7 @@
/**
* Class for abstraction of filesystem functions
- * This class won't call any filesystem functions for itself but but will pass them to the correct OC_Filestorage object
+ * This class won't call any filesystem functions for itself but will pass them to the correct OC_Filestorage object
* this class should also handle all the file permission related stuff
*
* Hooks provided:
@@ -23,15 +23,23 @@
* post_rename(oldpath,newpath)
* copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order)
* post_rename(oldpath,newpath)
+ * post_initMountPoints(user, user_dir)
*
* the &run parameter can be set to false to prevent the operation from occurring
*/
namespace OC\Files;
+use OC\Files\Storage\Loader;
const FREE_SPACE_UNKNOWN = -2;
+const FREE_SPACE_UNLIMITED = -3;
class Filesystem {
+ /**
+ * @var Mount\Manager $mounts
+ */
+ private static $mounts;
+
public static $loaded = false;
/**
* @var \OC\Files\View $defaultInstance
@@ -136,6 +144,18 @@ class Filesystem {
const signal_param_run = 'run';
/**
+ * @var \OC\Files\Storage\Loader $loader
+ */
+ private static $loader;
+
+ public static function getLoader(){
+ if (!self::$loader) {
+ self::$loader = new Loader();
+ }
+ return self::$loader;
+ }
+
+ /**
* get the mountpoint of the storage object for a path
* ( note: because a storage is not always mounted inside the fakeroot, the
* returned mountpoint is relative to the absolute root of the filesystem
@@ -145,7 +165,10 @@ class Filesystem {
* @return string
*/
static public function getMountPoint($path) {
- $mount = Mount::find($path);
+ if (!self::$mounts) {
+ \OC_Util::setupFS();
+ }
+ $mount = self::$mounts->find($path);
if ($mount) {
return $mount->getMountPoint();
} else {
@@ -160,8 +183,11 @@ class Filesystem {
* @return string[]
*/
static public function getMountPoints($path) {
+ if (!self::$mounts) {
+ \OC_Util::setupFS();
+ }
$result = array();
- $mounts = Mount::findIn($path);
+ $mounts = self::$mounts->findIn($path);
foreach ($mounts as $mount) {
$result[] = $mount->getMountPoint();
}
@@ -175,18 +201,46 @@ class Filesystem {
* @return \OC\Files\Storage\Storage
*/
public static function getStorage($mountPoint) {
- $mount = Mount::find($mountPoint);
+ if (!self::$mounts) {
+ \OC_Util::setupFS();
+ }
+ $mount = self::$mounts->find($mountPoint);
return $mount->getStorage();
}
/**
+ * @param $id
+ * @return Mount\Mount[]
+ */
+ public static function getMountByStorageId($id) {
+ if (!self::$mounts) {
+ \OC_Util::setupFS();
+ }
+ return self::$mounts->findByStorageId($id);
+ }
+
+ /**
+ * @param $id
+ * @return Mount\Mount[]
+ */
+ public static function getMountByNumericId($id) {
+ if (!self::$mounts) {
+ \OC_Util::setupFS();
+ }
+ return self::$mounts->findByNumericId($id);
+ }
+
+ /**
* resolve a path to a storage and internal path
*
* @param string $path
* @return array consisting of the storage and the internal path
*/
static public function resolvePath($path) {
- $mount = Mount::find($path);
+ if (!self::$mounts) {
+ \OC_Util::setupFS();
+ }
+ $mount = self::$mounts->find($path);
if ($mount) {
return array($mount->getStorage(), $mount->getInternalPath($path));
} else {
@@ -198,8 +252,13 @@ class Filesystem {
if (self::$defaultInstance) {
return false;
}
+ self::getLoader();
self::$defaultInstance = new View($root);
+ if (!self::$mounts) {
+ self::$mounts = new Mount\Manager();
+ }
+
//load custom mount config
self::initMountPoints($user);
@@ -208,6 +267,12 @@ class Filesystem {
return true;
}
+ static public function initMounts() {
+ if (!self::$mounts) {
+ self::$mounts = new Mount\Manager();
+ }
+ }
+
/**
* Initialize system and personal mount points for a user
*
@@ -279,12 +344,15 @@ class Filesystem {
}
}
}
+
+ // Chance to mount for other storages
+ \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root));
}
/**
- * fill in the correct values for $user, and $password placeholders
+ * fill in the correct values for $user
*
- * @param string $input
+ * @param string $user
* @param string $input
* @return string
*/
@@ -306,6 +374,7 @@ class Filesystem {
*/
static public function tearDown() {
self::clearMounts();
+ self::$defaultInstance = null;
}
/**
@@ -322,7 +391,9 @@ class Filesystem {
* clear all mounts and storage backends
*/
public static function clearMounts() {
- Mount::clear();
+ if (self::$mounts) {
+ self::$mounts->clear();
+ }
}
/**
@@ -333,7 +404,11 @@ class Filesystem {
* @param string $mountpoint
*/
static public function mount($class, $arguments, $mountpoint) {
- new Mount($class, $mountpoint, $arguments);
+ if (!self::$mounts) {
+ \OC_Util::setupFS();
+ }
+ $mount = new Mount\Mount($class, $mountpoint, $arguments, self::getLoader());
+ self::$mounts->addMount($mount);
}
/**
@@ -418,6 +493,19 @@ class Filesystem {
}
/**
+ * @brief check if the directory should be ignored when scanning
+ * NOTE: the special directories . and .. would cause never ending recursion
+ * @param String $dir
+ * @return boolean
+ */
+ static public function isIgnoredDir($dir) {
+ if ($dir === '.' || $dir === '..') {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* following functions are equivalent to their php builtin equivalents for arguments/return values.
*/
static public function mkdir($path) {
@@ -580,9 +668,8 @@ class Filesystem {
$path = substr($path, 0, -1);
}
//normalize unicode if possible
- if (class_exists('Normalizer')) {
- $path = \Normalizer::normalize($path);
- }
+ $path = \OC_Util::normalizeUnicode($path);
+
return $path;
}
@@ -620,16 +707,17 @@ class Filesystem {
* get the content of a directory
*
* @param string $directory path under datadirectory
+ * @param string $mimetype_filter limit returned content to this mimetype or mimepart
* @return array
*/
- public static function getDirectoryContent($directory) {
- return self::$defaultInstance->getDirectoryContent($directory);
+ public static function getDirectoryContent($directory, $mimetype_filter = '') {
+ return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
}
/**
* Get the path of a file by id
*
- * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
+ * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
*
* @param int $id
* @return string
@@ -659,8 +747,4 @@ class Filesystem {
}
}
-\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
-\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
-\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');
-
\OC_Util::setupFS();
diff --git a/lib/files/mapper.php b/lib/files/mapper.php
index 179e28e5e76..47abd4e52fe 100644
--- a/lib/files/mapper.php
+++ b/lib/files/mapper.php
@@ -53,11 +53,9 @@ class Mapper
}
if ($isLogicPath) {
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?');
- $query->execute(array($path));
+ \OC_DB::executeAudited('DELETE FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?', array($path));
} else {
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*file_map` WHERE `physic_path` LIKE ?');
- $query->execute(array($path));
+ \OC_DB::executeAudited('DELETE FROM `*PREFIX*file_map` WHERE `physic_path` LIKE ?', array($path));
}
}
@@ -73,8 +71,8 @@ class Mapper
$physicPath1 = $this->logicToPhysical($path1, true);
$physicPath2 = $this->logicToPhysical($path2, true);
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?');
- $result = $query->execute(array($path1.'%'));
+ $sql = 'SELECT * FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?';
+ $result = \OC_DB::executeAudited($sql, array($path1.'%'));
$updateQuery = \OC_DB::prepare('UPDATE `*PREFIX*file_map`'
.' SET `logic_path` = ?'
.' , `logic_path_hash` = ?'
@@ -88,7 +86,8 @@ class Mapper
$newPhysic = $physicPath2.$this->stripRootFolder($currentPhysic, $physicPath1);
if ($path1 !== $currentLogic) {
try {
- $updateQuery->execute(array($newLogic, md5($newLogic), $newPhysic, md5($newPhysic), $currentLogic));
+ \OC_DB::executeAudited($updateQuery, array($newLogic, md5($newLogic), $newPhysic, md5($newPhysic),
+ $currentLogic));
} catch (\Exception $e) {
error_log('Mapper::Copy failed '.$currentLogic.' -> '.$newLogic.'\n'.$e);
throw $e;
@@ -123,8 +122,8 @@ class Mapper
private function resolveLogicPath($logicPath) {
$logicPath = $this->stripLast($logicPath);
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `logic_path_hash` = ?');
- $result = $query->execute(array(md5($logicPath)));
+ $sql = 'SELECT * FROM `*PREFIX*file_map` WHERE `logic_path_hash` = ?';
+ $result = \OC_DB::executeAudited($sql, array(md5($logicPath)));
$result = $result->fetchRow();
if ($result === false) {
return null;
@@ -135,8 +134,8 @@ class Mapper
private function resolvePhysicalPath($physicalPath) {
$physicalPath = $this->stripLast($physicalPath);
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `physic_path_hash` = ?');
- $result = $query->execute(array(md5($physicalPath)));
+ $sql = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `physic_path_hash` = ?');
+ $result = \OC_DB::executeAudited($sql, array(md5($physicalPath)));
$result = $result->fetchRow();
return $result['logic_path'];
@@ -163,33 +162,40 @@ class Mapper
}
private function insert($logicPath, $physicalPath) {
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*file_map`(`logic_path`, `physic_path`, `logic_path_hash`, `physic_path_hash`) VALUES(?, ?, ?, ?)');
- $query->execute(array($logicPath, $physicalPath, md5($logicPath), md5($physicalPath)));
+ $sql = 'INSERT INTO `*PREFIX*file_map` (`logic_path`, `physic_path`, `logic_path_hash`, `physic_path_hash`)
+ VALUES (?, ?, ?, ?)';
+ \OC_DB::executeAudited($sql, array($logicPath, $physicalPath, md5($logicPath), md5($physicalPath)));
}
- private function slugifyPath($path, $index=null) {
+ public function slugifyPath($path, $index=null) {
$path = $this->stripRootFolder($path, $this->unchangedPhysicalRoot);
$pathElements = explode('/', $path);
$sluggedElements = array();
-
+
+ $last= end($pathElements);
+
foreach ($pathElements as $pathElement) {
// remove empty elements
if (empty($pathElement)) {
continue;
}
- // TODO: remove file ext before slugify on last element
$sluggedElements[] = self::slugify($pathElement);
}
- //
- // TODO: add the index before the file extension
- //
+ // apply index to file name
if ($index !== null) {
- $last= end($sluggedElements);
- array_pop($sluggedElements);
- array_push($sluggedElements, $last.'-'.$index);
+ $last= array_pop($sluggedElements);
+
+ // if filename contains periods - add index number before last period
+ if (preg_match('~\.[^\.]+$~i',$last,$extension)){
+ array_push($sluggedElements, substr($last,0,-(strlen($extension[0]))).'-'.$index.$extension[0]);
+ } else {
+ // if filename doesn't contain periods add index ofter the last char
+ array_push($sluggedElements, $last.'-'.$index);
+ }
+
}
$sluggedPath = $this->unchangedPhysicalRoot.implode('/', $sluggedElements);
@@ -204,8 +210,8 @@ class Mapper
*/
private function slugify($text)
{
- // replace non letter or digits by -
- $text = preg_replace('~[^\\pL\d]+~u', '-', $text);
+ // replace non letter or digits or dots by -
+ $text = preg_replace('~[^\\pL\d\.]+~u', '-', $text);
// trim
$text = trim($text, '-');
@@ -219,7 +225,10 @@ class Mapper
$text = strtolower($text);
// remove unwanted characters
- $text = preg_replace('~[^-\w]+~', '', $text);
+ $text = preg_replace('~[^-\w\.]+~', '', $text);
+
+ // trim ending dots (for security reasons and win compatibility)
+ $text = preg_replace('~\.+$~', '', $text);
if (empty($text)) {
return uniqid();
diff --git a/lib/files/mount.php b/lib/files/mount.php
deleted file mode 100644
index 1c9382d78e7..00000000000
--- a/lib/files/mount.php
+++ /dev/null
@@ -1,216 +0,0 @@
-<?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 OC\Files;
-
-class Mount {
- /**
- * @var Mount[]
- */
- static private $mounts = array();
-
- /**
- * @var \OC\Files\Storage\Storage $storage
- */
- private $storage = null;
- private $class;
- private $storageId;
- private $arguments = array();
- private $mountPoint;
-
- /**
- * @param string|\OC\Files\Storage\Storage $storage
- * @param string $mountpoint
- * @param array $arguments (optional)
- */
- public function __construct($storage, $mountpoint, $arguments = null) {
- if (is_null($arguments)) {
- $arguments = array();
- }
-
- $mountpoint = self::formatPath($mountpoint);
- if ($storage instanceof \OC\Files\Storage\Storage) {
- $this->class = get_class($storage);
- $this->storage = $storage;
- } else {
- // Update old classes to new namespace
- if (strpos($storage, 'OC_Filestorage_') !== false) {
- $storage = '\OC\Files\Storage\\' . substr($storage, 15);
- }
- $this->class = $storage;
- $this->arguments = $arguments;
- }
- $this->mountPoint = $mountpoint;
-
- self::$mounts[$this->mountPoint] = $this;
- }
-
- /**
- * @return string
- */
- public function getMountPoint() {
- return $this->mountPoint;
- }
-
- /**
- * @return \OC\Files\Storage\Storage
- */
- private function createStorage() {
- if (class_exists($this->class)) {
- try {
- return new $this->class($this->arguments);
- } catch (\Exception $exception) {
- \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR);
- return null;
- }
- } else {
- \OC_Log::write('core', 'storage backend ' . $this->class . ' not found', \OC_Log::ERROR);
- return null;
- }
- }
-
- /**
- * @return \OC\Files\Storage\Storage
- */
- public function getStorage() {
- if (is_null($this->storage)) {
- $this->storage = $this->createStorage();
- }
- return $this->storage;
- }
-
- /**
- * @return string
- */
- public function getStorageId() {
- if (!$this->storageId) {
- if (is_null($this->storage)) {
- $this->storage = $this->createStorage();
- }
- $this->storageId = $this->storage->getId();
- if (strlen($this->storageId) > 64) {
- $this->storageId = md5($this->storageId);
- }
- }
- return $this->storageId;
- }
-
- /**
- * @param string $path
- * @return string
- */
- public function getInternalPath($path) {
- if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) {
- $internalPath = '';
- } else {
- $internalPath = substr($path, strlen($this->mountPoint));
- }
- return $internalPath;
- }
-
- /**
- * @param string $path
- * @return string
- */
- private static function formatPath($path) {
- $path = Filesystem::normalizePath($path);
- if (strlen($path) > 1) {
- $path .= '/';
- }
- return $path;
- }
-
- /**
- * Find the mount for $path
- *
- * @param $path
- * @return Mount
- */
- public static function find($path) {
- $path = self::formatPath($path);
- if (isset(self::$mounts[$path])) {
- return self::$mounts[$path];
- }
-
- \OC_Hook::emit('OC_Filesystem', 'get_mountpoint', array('path' => $path));
- $foundMountPoint = '';
- $mountPoints = array_keys(self::$mounts);
- foreach ($mountPoints as $mountpoint) {
- if (strpos($path, $mountpoint) === 0 and strlen($mountpoint) > strlen($foundMountPoint)) {
- $foundMountPoint = $mountpoint;
- }
- }
- if (isset(self::$mounts[$foundMountPoint])) {
- return self::$mounts[$foundMountPoint];
- } else {
- return null;
- }
- }
-
- /**
- * Find all mounts in $path
- *
- * @param $path
- * @return Mount[]
- */
- public static function findIn($path) {
- $path = self::formatPath($path);
- $result = array();
- $pathLength = strlen($path);
- $mountPoints = array_keys(self::$mounts);
- foreach ($mountPoints as $mountPoint) {
- if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) {
- $result[] = self::$mounts[$mountPoint];
- }
- }
- return $result;
- }
-
- public static function clear() {
- self::$mounts = array();
- }
-
- /**
- * Find mounts by storage id
- *
- * @param string $id
- * @return Mount[]
- */
- public static function findByStorageId($id) {
- if (strlen($id) > 64) {
- $id = md5($id);
- }
- $result = array();
- foreach (self::$mounts as $mount) {
- if ($mount->getStorageId() === $id) {
- $result[] = $mount;
- }
- }
- return $result;
- }
-
- /**
- * Find mounts by numeric storage id
- *
- * @param string $id
- * @return Mount
- */
- public static function findByNumericId($id) {
- $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?');
- $result = $query->execute(array($id))->fetchOne();
- if ($result) {
- $id = $result;
- foreach (self::$mounts as $mount) {
- if ($mount->getStorageId() === $id) {
- return $mount;
- }
- }
- }
- return false;
- }
-}
diff --git a/lib/files/mount/manager.php b/lib/files/mount/manager.php
new file mode 100644
index 00000000000..25a5fe241cc
--- /dev/null
+++ b/lib/files/mount/manager.php
@@ -0,0 +1,120 @@
+<?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 OC\Files\Mount;
+
+use \OC\Files\Filesystem;
+
+class Manager {
+ /**
+ * @var Mount[]
+ */
+ private $mounts = array();
+
+ /**
+ * @param Mount $mount
+ */
+ public function addMount($mount) {
+ $this->mounts[$mount->getMountPoint()] = $mount;
+ }
+
+ /**
+ * Find the mount for $path
+ *
+ * @param $path
+ * @return Mount
+ */
+ public function find($path) {
+ \OC_Util::setupFS();
+ $path = $this->formatPath($path);
+ if (isset($this->mounts[$path])) {
+ return $this->mounts[$path];
+ }
+
+ \OC_Hook::emit('OC_Filesystem', 'get_mountpoint', array('path' => $path));
+ $foundMountPoint = '';
+ $mountPoints = array_keys($this->mounts);
+ foreach ($mountPoints as $mountpoint) {
+ if (strpos($path, $mountpoint) === 0 and strlen($mountpoint) > strlen($foundMountPoint)) {
+ $foundMountPoint = $mountpoint;
+ }
+ }
+ if (isset($this->mounts[$foundMountPoint])) {
+ return $this->mounts[$foundMountPoint];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find all mounts in $path
+ *
+ * @param $path
+ * @return Mount[]
+ */
+ public function findIn($path) {
+ \OC_Util::setupFS();
+ $path = $this->formatPath($path);
+ $result = array();
+ $pathLength = strlen($path);
+ $mountPoints = array_keys($this->mounts);
+ foreach ($mountPoints as $mountPoint) {
+ if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) {
+ $result[] = $this->mounts[$mountPoint];
+ }
+ }
+ return $result;
+ }
+
+ public function clear() {
+ $this->mounts = array();
+ }
+
+ /**
+ * Find mounts by storage id
+ *
+ * @param string $id
+ * @return Mount[]
+ */
+ public function findByStorageId($id) {
+ \OC_Util::setupFS();
+ if (strlen($id) > 64) {
+ $id = md5($id);
+ }
+ $result = array();
+ foreach ($this->mounts as $mount) {
+ if ($mount->getStorageId() === $id) {
+ $result[] = $mount;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Find mounts by numeric storage id
+ *
+ * @param string $id
+ * @return Mount
+ */
+ public function findByNumericId($id) {
+ $storageId = \OC\Files\Cache\Storage::getStorageId($id);
+ return $this->findByStorageId($storageId);
+ }
+
+ /**
+ * @param string $path
+ * @return string
+ */
+ private function formatPath($path) {
+ $path = Filesystem::normalizePath($path);
+ if (strlen($path) > 1) {
+ $path .= '/';
+ }
+ return $path;
+ }
+}
diff --git a/lib/files/mount/mount.php b/lib/files/mount/mount.php
new file mode 100644
index 00000000000..17b0055ee84
--- /dev/null
+++ b/lib/files/mount/mount.php
@@ -0,0 +1,141 @@
+<?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 OC\Files\Mount;
+
+use \OC\Files\Filesystem;
+use OC\Files\Storage\Loader;
+use OC\Files\Storage\Storage;
+
+class Mount {
+ /**
+ * @var \OC\Files\Storage\Storage $storage
+ */
+ private $storage = null;
+ private $class;
+ private $storageId;
+ private $arguments = array();
+ private $mountPoint;
+
+ /**
+ * @var \OC\Files\Storage\Loader $loader
+ */
+ private $loader;
+
+ /**
+ * @param string | \OC\Files\Storage\Storage $storage
+ * @param string $mountpoint
+ * @param array $arguments (optional)\
+ * @param \OC\Files\Storage\Loader $loader
+ */
+ public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
+ if (is_null($arguments)) {
+ $arguments = array();
+ }
+ if (is_null($loader)) {
+ $this->loader = new Loader();
+ } else {
+ $this->loader = $loader;
+ }
+
+ $mountpoint = $this->formatPath($mountpoint);
+ if ($storage instanceof Storage) {
+ $this->class = get_class($storage);
+ $this->storage = $this->loader->wrap($mountpoint, $storage);
+ } else {
+ // Update old classes to new namespace
+ if (strpos($storage, 'OC_Filestorage_') !== false) {
+ $storage = '\OC\Files\Storage\\' . substr($storage, 15);
+ }
+ $this->class = $storage;
+ $this->arguments = $arguments;
+ }
+ $this->mountPoint = $mountpoint;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMountPoint() {
+ return $this->mountPoint;
+ }
+
+ /**
+ * create the storage that is mounted
+ *
+ * @return \OC\Files\Storage\Storage
+ */
+ private function createStorage() {
+ if (class_exists($this->class)) {
+ try {
+ return $this->loader->load($this->mountPoint, $this->class, $this->arguments);
+ } catch (\Exception $exception) {
+ \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR);
+ return null;
+ }
+ } else {
+ \OC_Log::write('core', 'storage backend ' . $this->class . ' not found', \OC_Log::ERROR);
+ return null;
+ }
+ }
+
+ /**
+ * @return \OC\Files\Storage\Storage
+ */
+ public function getStorage() {
+ if (is_null($this->storage)) {
+ $this->storage = $this->createStorage();
+ }
+ return $this->storage;
+ }
+
+ /**
+ * @return string
+ */
+ public function getStorageId() {
+ if (!$this->storageId) {
+ if (is_null($this->storage)) {
+ $storage = $this->createStorage(); //FIXME: start using exceptions
+ if (is_null($storage)) {
+ return null;
+ }
+ $this->storage = $storage;
+ }
+ $this->storageId = $this->storage->getId();
+ if (strlen($this->storageId) > 64) {
+ $this->storageId = md5($this->storageId);
+ }
+ }
+ return $this->storageId;
+ }
+
+ /**
+ * @param string $path
+ * @return string
+ */
+ public function getInternalPath($path) {
+ if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) {
+ $internalPath = '';
+ } else {
+ $internalPath = substr($path, strlen($this->mountPoint));
+ }
+ return $internalPath;
+ }
+
+ /**
+ * @param string $path
+ * @return string
+ */
+ private function formatPath($path) {
+ $path = Filesystem::normalizePath($path);
+ if (strlen($path) > 1) {
+ $path .= '/';
+ }
+ return $path;
+ }
+}
diff --git a/lib/files/storage/common.php b/lib/files/storage/common.php
index 8aa227ec0b7..3da13ac4df0 100644
--- a/lib/files/storage/common.php
+++ b/lib/files/storage/common.php
@@ -21,6 +21,11 @@ namespace OC\Files\Storage;
*/
abstract class Common implements \OC\Files\Storage\Storage {
+ private $cache;
+ private $scanner;
+ private $permissioncache;
+ private $watcher;
+ private $storageCache;
public function __construct($parameters) {
}
@@ -133,27 +138,21 @@ abstract class Common implements \OC\Files\Storage\Storage {
*/
public function deleteAll($directory, $empty = false) {
$directory = trim($directory, '/');
-
- if (!$this->file_exists(\OCP\USER::getUser() . '/' . $directory)
- || !$this->is_dir(\OCP\USER::getUser() . '/' . $directory)
- ) {
- return false;
- } elseif (!$this->isReadable(\OCP\USER::getUser() . '/' . $directory)) {
+ if (!$this->is_dir($directory) || !$this->isReadable($directory)) {
return false;
} else {
- $directoryHandle = $this->opendir(\OCP\USER::getUser() . '/' . $directory);
+ $directoryHandle = $this->opendir($directory);
while ($contents = readdir($directoryHandle)) {
- if ($contents != '.' && $contents != '..') {
- $path = $directory . "/" . $contents;
+ if (!\OC\Files\Filesystem::isIgnoredDir($contents)) {
+ $path = $directory . '/' . $contents;
if ($this->is_dir($path)) {
$this->deleteAll($path);
} else {
- $this->unlink(\OCP\USER::getUser() . '/' . $path); // TODO: make unlink use same system path as is_dir
+ $this->unlink($path);
}
}
}
- //$this->closedir( $directoryHandle ); // TODO: implement closedir in OC_FSV
- if ($empty == false) {
+ if ($empty === false) {
if (!$this->rmdir($directory)) {
return false;
}
@@ -269,19 +268,38 @@ abstract class Common implements \OC\Files\Storage\Storage {
}
public function getCache($path = '') {
- return new \OC\Files\Cache\Cache($this);
+ if (!isset($this->cache)) {
+ $this->cache = new \OC\Files\Cache\Cache($this);
+ }
+ return $this->cache;
}
public function getScanner($path = '') {
- return new \OC\Files\Cache\Scanner($this);
+ if (!isset($this->scanner)) {
+ $this->scanner = new \OC\Files\Cache\Scanner($this);
+ }
+ return $this->scanner;
}
public function getPermissionsCache($path = '') {
- return new \OC\Files\Cache\Permissions($this);
+ if (!isset($this->permissioncache)) {
+ $this->permissioncache = new \OC\Files\Cache\Permissions($this);
+ }
+ return $this->permissioncache;
}
public function getWatcher($path = '') {
- return new \OC\Files\Cache\Watcher($this);
+ if (!isset($this->watcher)) {
+ $this->watcher = new \OC\Files\Cache\Watcher($this);
+ }
+ return $this->watcher;
+ }
+
+ public function getStorageCache(){
+ if (!isset($this->storageCache)) {
+ $this->storageCache = new \OC\Files\Cache\Storage($this);
+ }
+ return $this->storageCache;
}
/**
@@ -345,7 +363,7 @@ abstract class Common implements \OC\Files\Storage\Storage {
* get the free space in the storage
*
* @param $path
- * return int
+ * @return int
*/
public function free_space($path) {
return \OC\Files\FREE_SPACE_UNKNOWN;
diff --git a/lib/files/storage/loader.php b/lib/files/storage/loader.php
new file mode 100644
index 00000000000..2572ef443bc
--- /dev/null
+++ b/lib/files/storage/loader.php
@@ -0,0 +1,38 @@
+<?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 OC\Files\Storage;
+
+class Loader {
+ /**
+ * @var callable[] $storageWrappers
+ */
+ private $storageWrappers = array();
+
+ /**
+ * allow modifier storage behaviour by adding wrappers around storages
+ *
+ * $callback should be a function of type (string $mountPoint, Storage $storage) => Storage
+ *
+ * @param callable $callback
+ */
+ public function addStorageWrapper($callback) {
+ $this->storageWrappers[] = $callback;
+ }
+
+ public function load($mountPoint, $class, $arguments) {
+ return $this->wrap($mountPoint, new $class($arguments));
+ }
+
+ public function wrap($mountPoint, $storage) {
+ foreach ($this->storageWrappers as $wrapper) {
+ $storage = $wrapper($mountPoint, $storage);
+ }
+ return $storage;
+ }
+}
diff --git a/lib/files/storage/local.php b/lib/files/storage/local.php
index 7b637a97059..b08fd73ce19 100644
--- a/lib/files/storage/local.php
+++ b/lib/files/storage/local.php
@@ -14,249 +14,297 @@ if (\OC_Util::runningOnWindows()) {
}
} else {
-/**
- * for local filestore, we only have to map the paths
- */
-class Local extends \OC\Files\Storage\Common{
- protected $datadir;
- public function __construct($arguments) {
- $this->datadir=$arguments['datadir'];
- if(substr($this->datadir, -1)!=='/') {
- $this->datadir.='/';
+ /**
+ * for local filestore, we only have to map the paths
+ */
+ class Local extends \OC\Files\Storage\Common {
+ protected $datadir;
+
+ public function __construct($arguments) {
+ $this->datadir = $arguments['datadir'];
+ if (substr($this->datadir, -1) !== '/') {
+ $this->datadir .= '/';
+ }
}
- }
- public function __destruct() {
- }
- public function getId(){
- return 'local::'.$this->datadir;
- }
- public function mkdir($path) {
- return @mkdir($this->datadir.$path);
- }
- public function rmdir($path) {
- return @rmdir($this->datadir.$path);
- }
- public function opendir($path) {
- return opendir($this->datadir.$path);
- }
- public function is_dir($path) {
- if(substr($path, -1)=='/') {
- $path=substr($path, 0, -1);
+
+ public function __destruct() {
}
- return is_dir($this->datadir.$path);
- }
- public function is_file($path) {
- return is_file($this->datadir.$path);
- }
- public function stat($path) {
- $fullPath = $this->datadir . $path;
- $statResult = stat($fullPath);
- if ($statResult['size'] < 0) {
- $size = self::getFileSizeFromOS($fullPath);
- $statResult['size'] = $size;
- $statResult[7] = $size;
+ public function getId() {
+ return 'local::' . $this->datadir;
}
- return $statResult;
- }
- public function filetype($path) {
- $filetype=filetype($this->datadir.$path);
- if($filetype=='link') {
- $filetype=filetype(realpath($this->datadir.$path));
+
+ public function mkdir($path) {
+ return @mkdir($this->datadir . $path);
}
- return $filetype;
- }
- public function filesize($path) {
- if($this->is_dir($path)) {
- return 0;
- }else{
+
+ public function rmdir($path) {
+ try {
+ $it = new \RecursiveIteratorIterator(
+ new \RecursiveDirectoryIterator($this->datadir . $path),
+ \RecursiveIteratorIterator::CHILD_FIRST
+ );
+ foreach ($it as $file) {
+ /**
+ * @var \SplFileInfo $file
+ */
+ if (in_array($file->getBasename(), array('.', '..'))) {
+ continue;
+ } elseif ($file->isDir()) {
+ rmdir($file->getPathname());
+ } elseif ($file->isFile() || $file->isLink()) {
+ unlink($file->getPathname());
+ }
+ }
+ return rmdir($this->datadir . $path);
+ } catch (\UnexpectedValueException $e) {
+ return false;
+ }
+ }
+
+ public function opendir($path) {
+ return opendir($this->datadir . $path);
+ }
+
+ public function is_dir($path) {
+ if (substr($path, -1) == '/') {
+ $path = substr($path, 0, -1);
+ }
+ return is_dir($this->datadir . $path);
+ }
+
+ public function is_file($path) {
+ return is_file($this->datadir . $path);
+ }
+
+ public function stat($path) {
$fullPath = $this->datadir . $path;
- $fileSize = filesize($fullPath);
- if ($fileSize < 0) {
- return self::getFileSizeFromOS($fullPath);
+ $statResult = stat($fullPath);
+
+ if ($statResult['size'] < 0) {
+ $size = self::getFileSizeFromOS($fullPath);
+ $statResult['size'] = $size;
+ $statResult[7] = $size;
}
+ return $statResult;
+ }
- return $fileSize;
+ public function filetype($path) {
+ $filetype = filetype($this->datadir . $path);
+ if ($filetype == 'link') {
+ $filetype = filetype(realpath($this->datadir . $path));
+ }
+ return $filetype;
}
- }
- public function isReadable($path) {
- return is_readable($this->datadir.$path);
- }
- public function isUpdatable($path) {
- return is_writable($this->datadir.$path);
- }
- public function file_exists($path) {
- return file_exists($this->datadir.$path);
- }
- public function filemtime($path) {
- return filemtime($this->datadir.$path);
- }
- public function touch($path, $mtime=null) {
- // sets the modification time of the file to the given value.
- // If mtime is nil the current time is set.
- // note that the access time of the file always changes to the current time.
- if(!is_null($mtime)) {
- $result=touch( $this->datadir.$path, $mtime );
- }else{
- $result=touch( $this->datadir.$path);
+
+ public function filesize($path) {
+ if ($this->is_dir($path)) {
+ return 0;
+ } else {
+ $fullPath = $this->datadir . $path;
+ $fileSize = filesize($fullPath);
+ if ($fileSize < 0) {
+ return self::getFileSizeFromOS($fullPath);
+ }
+
+ return $fileSize;
+ }
}
- if( $result ) {
- clearstatcache( true, $this->datadir.$path );
+
+ public function isReadable($path) {
+ return is_readable($this->datadir . $path);
}
- return $result;
- }
- public function file_get_contents($path) {
- return file_get_contents($this->datadir.$path);
- }
- public function file_put_contents($path, $data) {//trigger_error("$path = ".var_export($path, 1));
- return file_put_contents($this->datadir.$path, $data);
- }
- public function unlink($path) {
- return $this->delTree($path);
- }
- public function rename($path1, $path2) {
- if (!$this->isUpdatable($path1)) {
- \OC_Log::write('core', 'unable to rename, file is not writable : '.$path1, \OC_Log::ERROR);
- return false;
+ public function isUpdatable($path) {
+ return is_writable($this->datadir . $path);
}
- if(! $this->file_exists($path1)) {
- \OC_Log::write('core', 'unable to rename, file does not exists : '.$path1, \OC_Log::ERROR);
- return false;
+
+ public function file_exists($path) {
+ return file_exists($this->datadir . $path);
}
- if($return=rename($this->datadir.$path1, $this->datadir.$path2)) {
+ public function filemtime($path) {
+ return filemtime($this->datadir . $path);
}
- return $return;
- }
- public function copy($path1, $path2) {
- if($this->is_dir($path2)) {
- if(!$this->file_exists($path2)) {
- $this->mkdir($path2);
+
+ public function touch($path, $mtime = null) {
+ // sets the modification time of the file to the given value.
+ // If mtime is nil the current time is set.
+ // note that the access time of the file always changes to the current time.
+ if ($this->file_exists($path) and !$this->isUpdatable($path)) {
+ return false;
+ }
+ if (!is_null($mtime)) {
+ $result = touch($this->datadir . $path, $mtime);
+ } else {
+ $result = touch($this->datadir . $path);
}
- $source=substr($path1, strrpos($path1, '/')+1);
- $path2.=$source;
+ if ($result) {
+ clearstatcache(true, $this->datadir . $path);
+ }
+
+ return $result;
}
- return copy($this->datadir.$path1, $this->datadir.$path2);
- }
- public function fopen($path, $mode) {
- if($return=fopen($this->datadir.$path, $mode)) {
- switch($mode) {
- case 'r':
- break;
- case 'r+':
- case 'w+':
- case 'x+':
- case 'a+':
- break;
- case 'w':
- case 'x':
- case 'a':
- break;
+
+ public function file_get_contents($path) {
+ return file_get_contents($this->datadir . $path);
+ }
+
+ public function file_put_contents($path, $data) { //trigger_error("$path = ".var_export($path, 1));
+ return file_put_contents($this->datadir . $path, $data);
+ }
+
+ public function unlink($path) {
+ return $this->delTree($path);
+ }
+
+ public function rename($path1, $path2) {
+ if (!$this->isUpdatable($path1)) {
+ \OC_Log::write('core', 'unable to rename, file is not writable : ' . $path1, \OC_Log::ERROR);
+ return false;
+ }
+ if (!$this->file_exists($path1)) {
+ \OC_Log::write('core', 'unable to rename, file does not exists : ' . $path1, \OC_Log::ERROR);
+ return false;
}
+
+ if ($return = rename($this->datadir . $path1, $this->datadir . $path2)) {
+ }
+ return $return;
}
- return $return;
- }
- public function getMimeType($path) {
- if($this->isReadable($path)) {
- return \OC_Helper::getMimeType($this->datadir . $path);
- }else{
- return false;
+ public function copy($path1, $path2) {
+ if ($this->is_dir($path2)) {
+ if (!$this->file_exists($path2)) {
+ $this->mkdir($path2);
+ }
+ $source = substr($path1, strrpos($path1, '/') + 1);
+ $path2 .= $source;
+ }
+ return copy($this->datadir . $path1, $this->datadir . $path2);
}
- }
- private function delTree($dir) {
- $dirRelative=$dir;
- $dir=$this->datadir.$dir;
- if (!file_exists($dir)) return true;
- if (!is_dir($dir) || is_link($dir)) return unlink($dir);
- foreach (scandir($dir) as $item) {
- if ($item == '.' || $item == '..') continue;
- if(is_file($dir.'/'.$item)) {
- if(unlink($dir.'/'.$item)) {
+ public function fopen($path, $mode) {
+ if ($return = fopen($this->datadir . $path, $mode)) {
+ switch ($mode) {
+ case 'r':
+ break;
+ case 'r+':
+ case 'w+':
+ case 'x+':
+ case 'a+':
+ break;
+ case 'w':
+ case 'x':
+ case 'a':
+ break;
}
- }elseif(is_dir($dir.'/'.$item)) {
- if (!$this->delTree($dirRelative. "/" . $item)) {
- return false;
- };
}
+ return $return;
}
- if($return=rmdir($dir)) {
+
+ public function getMimeType($path) {
+ if ($this->isReadable($path)) {
+ return \OC_Helper::getMimeType($this->datadir . $path);
+ } else {
+ return false;
+ }
}
- return $return;
- }
- private static function getFileSizeFromOS($fullPath) {
- $name = strtolower(php_uname('s'));
- // Windows OS: we use COM to access the filesystem
- if (strpos($name, 'win') !== false) {
- if (class_exists('COM')) {
- $fsobj = new \COM("Scripting.FileSystemObject");
- $f = $fsobj->GetFile($fullPath);
- return $f->Size;
+ private function delTree($dir) {
+ $dirRelative = $dir;
+ $dir = $this->datadir . $dir;
+ if (!file_exists($dir)) return true;
+ if (!is_dir($dir) || is_link($dir)) return unlink($dir);
+ foreach (scandir($dir) as $item) {
+ if ($item == '.' || $item == '..') continue;
+ if (is_file($dir . '/' . $item)) {
+ if (unlink($dir . '/' . $item)) {
+ }
+ } elseif (is_dir($dir . '/' . $item)) {
+ if (!$this->delTree($dirRelative . "/" . $item)) {
+ return false;
+ };
+ }
}
- } else if (strpos($name, 'bsd') !== false) {
- if (\OC_Helper::is_function_enabled('exec')) {
- return (float)exec('stat -f %z ' . escapeshellarg($fullPath));
+ if ($return = rmdir($dir)) {
}
- } else if (strpos($name, 'linux') !== false) {
- if (\OC_Helper::is_function_enabled('exec')) {
- return (float)exec('stat -c %s ' . escapeshellarg($fullPath));
+ return $return;
+ }
+
+ private static function getFileSizeFromOS($fullPath) {
+ $name = strtolower(php_uname('s'));
+ // Windows OS: we use COM to access the filesystem
+ if (strpos($name, 'win') !== false) {
+ if (class_exists('COM')) {
+ $fsobj = new \COM("Scripting.FileSystemObject");
+ $f = $fsobj->GetFile($fullPath);
+ return $f->Size;
+ }
+ } else if (strpos($name, 'bsd') !== false) {
+ if (\OC_Helper::is_function_enabled('exec')) {
+ return (float)exec('stat -f %z ' . escapeshellarg($fullPath));
+ }
+ } else if (strpos($name, 'linux') !== false) {
+ if (\OC_Helper::is_function_enabled('exec')) {
+ return (float)exec('stat -c %s ' . escapeshellarg($fullPath));
+ }
+ } else {
+ \OC_Log::write('core',
+ 'Unable to determine file size of "' . $fullPath . '". Unknown OS: ' . $name,
+ \OC_Log::ERROR);
}
- } else {
- \OC_Log::write('core',
- 'Unable to determine file size of "'.$fullPath.'". Unknown OS: '.$name,
- \OC_Log::ERROR);
+
+ return 0;
}
- return 0;
- }
+ public function hash($path, $type, $raw = false) {
+ return hash_file($type, $this->datadir . $path, $raw);
+ }
- public function hash($path, $type, $raw=false) {
- return hash_file($type, $this->datadir.$path, $raw);
- }
+ public function free_space($path) {
+ $space = @disk_free_space($this->datadir . $path);
+ if ($space === false) {
+ return \OC\Files\FREE_SPACE_UNKNOWN;
+ }
+ return $space;
+ }
- public function free_space($path) {
- $space = @disk_free_space($this->datadir.$path);
- if($space === false){
- return \OC\Files\FREE_SPACE_UNKNOWN;
+ public function search($query) {
+ return $this->searchInDir($query);
}
- return $space;
- }
- public function search($query) {
- return $this->searchInDir($query);
- }
- public function getLocalFile($path) {
- return $this->datadir.$path;
- }
- public function getLocalFolder($path) {
- return $this->datadir.$path;
- }
+ public function getLocalFile($path) {
+ return $this->datadir . $path;
+ }
- protected function searchInDir($query, $dir='') {
- $files=array();
- foreach (scandir($this->datadir.$dir) as $item) {
- if ($item == '.' || $item == '..') continue;
- if(strstr(strtolower($item), strtolower($query))!==false) {
- $files[]=$dir.'/'.$item;
- }
- if(is_dir($this->datadir.$dir.'/'.$item)) {
- $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item));
+ public function getLocalFolder($path) {
+ return $this->datadir . $path;
+ }
+
+ protected function searchInDir($query, $dir = '') {
+ $files = array();
+ foreach (scandir($this->datadir . $dir) as $item) {
+ if ($item == '.' || $item == '..') continue;
+ if (strstr(strtolower($item), strtolower($query)) !== false) {
+ $files[] = $dir . '/' . $item;
+ }
+ if (is_dir($this->datadir . $dir . '/' . $item)) {
+ $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
+ }
}
+ return $files;
}
- return $files;
- }
- /**
- * check if a file or folder has been updated since $time
- * @param string $path
- * @param int $time
- * @return bool
- */
- public function hasUpdated($path, $time) {
- return $this->filemtime($path)>$time;
+ /**
+ * check if a file or folder has been updated since $time
+ *
+ * @param string $path
+ * @param int $time
+ * @return bool
+ */
+ public function hasUpdated($path, $time) {
+ return $this->filemtime($path) > $time;
+ }
}
}
-}
diff --git a/lib/files/storage/mappedlocal.php b/lib/files/storage/mappedlocal.php
index ba3fcdc5c9e..cf5d9b3ef4f 100644
--- a/lib/files/storage/mappedlocal.php
+++ b/lib/files/storage/mappedlocal.php
@@ -34,10 +34,30 @@ class MappedLocal extends \OC\Files\Storage\Common{
return @mkdir($this->buildPath($path));
}
public function rmdir($path) {
- if ($result = @rmdir($this->buildPath($path))) {
- $this->cleanMapper($path);
+ try {
+ $it = new \RecursiveIteratorIterator(
+ new \RecursiveDirectoryIterator($this->buildPath($path)),
+ \RecursiveIteratorIterator::CHILD_FIRST
+ );
+ foreach ($it as $file) {
+ /**
+ * @var \SplFileInfo $file
+ */
+ if (in_array($file->getBasename(), array('.', '..'))) {
+ continue;
+ } elseif ($file->isDir()) {
+ rmdir($file->getPathname());
+ } elseif ($file->isFile() || $file->isLink()) {
+ unlink($file->getPathname());
+ }
+ }
+ if ($result = @rmdir($this->buildPath($path))) {
+ $this->cleanMapper($path);
+ }
+ return $result;
+ } catch (\UnexpectedValueException $e) {
+ return false;
}
- return $result;
}
public function opendir($path) {
$files = array('.', '..');
diff --git a/lib/files/storage/storage.php b/lib/files/storage/storage.php
index 2cc835236ba..c96caebf4af 100644
--- a/lib/files/storage/storage.php
+++ b/lib/files/storage/storage.php
@@ -10,73 +10,328 @@ namespace OC\Files\Storage;
/**
* Provide a common interface to all different storage options
+ *
+ * All paths passed to the storage are relative to the storage and should NOT have a leading slash.
*/
-interface Storage{
+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);
- public function file_put_contents($path,$data);
+
+ /**
+ * 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);
- public function rename($path1,$path2);
- public function copy($path1,$path2);
- public function fopen($path,$mode);
+
+ /**
+ * 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);
- public function hash($type,$path,$raw = false);
+
+ /**
+ * see http://php.net/manual/en/function.hash.php
+ *
+ * @param string $type
+ * @param string $path
+ * @param bool $raw
+ * @return string
+ */
+ public function hash($type, $path, $raw = false);
+
+ /**
+ * see http://php.net/manual/en/function.free_space.php
+ *
+ * @param string $path
+ * @return int
+ */
public function free_space($path);
+
+ /**
+ * search for occurrences of $query in file names
+ *
+ * @param string $query
+ * @return array
+ */
public function search($query);
- public function touch($path, $mtime=null);
- public function getLocalFile($path);// get a path to a local version of the file, whether the original file is local or remote
- public function getLocalFolder($path);// get a path to a local version of the folder, whether the original file is local or remote
+
+ /**
+ * 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);
+ public function hasUpdated($path, $time);
/**
+ * get a cache instance for the storage
+ *
* @param string $path
* @return \OC\Files\Cache\Cache
*/
- public function getCache($path='');
+ public function getCache($path = '');
+
/**
+ * get a scanner instance for the storage
+ *
* @param string $path
* @return \OC\Files\Cache\Scanner
*/
- public function getScanner($path='');
+ public function getScanner($path = '');
+
+ /**
+ * get the user id of the owner of a file or folder
+ *
+ * @param string $path
+ * @return string
+ */
public function getOwner($path);
/**
+ * get a permissions cache instance for the cache
+ *
* @param string $path
* @return \OC\Files\Cache\Permissions
*/
- public function getPermissionsCache($path='');
+ public function getPermissionsCache($path = '');
/**
+ * get a watcher instance for the cache
+ *
* @param string $path
* @return \OC\Files\Cache\Watcher
*/
- public function getWatcher($path='');
+ public function getWatcher($path = '');
+
+ /**
+ * @return \OC\Files\Cache\Storage
+ */
+ public function getStorageCache();
/**
* get the ETag for a file or folder
diff --git a/lib/files/storage/wrapper/wrapper.php b/lib/files/storage/wrapper/wrapper.php
new file mode 100644
index 00000000000..4feb0520f12
--- /dev/null
+++ b/lib/files/storage/wrapper/wrapper.php
@@ -0,0 +1,427 @@
+<?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\Storage\Wrapper;
+
+class Wrapper implements \OC\Files\Storage\Storage {
+ /**
+ * @var \OC\Files\Storage\Storage $storage
+ */
+ protected $storage;
+
+ /**
+ * @param array $parameters
+ */
+ public function __construct($parameters) {
+ $this->storage = $parameters['storage'];
+ }
+
+ /**
+ * @return \OC\Files\Storage\Storage
+ */
+ public function getWrapperStorage() {
+ return $this->storage;
+ }
+
+ /**
+ * Get the identifier for the storage,
+ * the returned id should be the same for every storage object that is created with the same parameters
+ * and two storage objects with the same id should refer to two storages that display the same files.
+ *
+ * @return string
+ */
+ public function getId() {
+ return $this->storage->getId();
+ }
+
+ /**
+ * see http://php.net/manual/en/function.mkdir.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function mkdir($path) {
+ return $this->storage->mkdir($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.rmdir.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function rmdir($path) {
+ return $this->storage->rmdir($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.opendir.php
+ *
+ * @param string $path
+ * @return resource
+ */
+ public function opendir($path) {
+ return $this->storage->opendir($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.is_dir.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function is_dir($path) {
+ return $this->storage->is_dir($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.is_file.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function is_file($path) {
+ return $this->storage->is_file($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.stat.php
+ * only the following keys are required in the result: size and mtime
+ *
+ * @param string $path
+ * @return array
+ */
+ public function stat($path) {
+ return $this->storage->stat($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.filetype.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function filetype($path) {
+ return $this->storage->filetype($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.filesize.php
+ * The result for filesize when called on a folder is required to be 0
+ *
+ * @param string $path
+ * @return int
+ */
+ public function filesize($path) {
+ return $this->storage->filesize($path);
+ }
+
+ /**
+ * check if a file can be created in $path
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isCreatable($path) {
+ return $this->storage->isCreatable($path);
+ }
+
+ /**
+ * check if a file can be read
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isReadable($path) {
+ return $this->storage->isReadable($path);
+ }
+
+ /**
+ * check if a file can be written to
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isUpdatable($path) {
+ return $this->storage->isUpdatable($path);
+ }
+
+ /**
+ * check if a file can be deleted
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isDeletable($path) {
+ return $this->storage->isDeletable($path);
+ }
+
+ /**
+ * check if a file can be shared
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isSharable($path) {
+ return $this->storage->isSharable($path);
+ }
+
+ /**
+ * get the full permissions of a path.
+ * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
+ *
+ * @param string $path
+ * @return int
+ */
+ public function getPermissions($path) {
+ return $this->storage->getPermissions($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.file_exists.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function file_exists($path) {
+ return $this->storage->file_exists($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.filemtime.php
+ *
+ * @param string $path
+ * @return int
+ */
+ public function filemtime($path) {
+ return $this->storage->filemtime($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.file_get_contents.php
+ *
+ * @param string $path
+ * @return string
+ */
+ public function file_get_contents($path) {
+ return $this->storage->file_get_contents($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.file_put_contents.php
+ *
+ * @param string $path
+ * @param string $data
+ * @return bool
+ */
+ public function file_put_contents($path, $data) {
+ return $this->storage->file_put_contents($path, $data);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.unlink.php
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function unlink($path) {
+ return $this->storage->unlink($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.rename.php
+ *
+ * @param string $path1
+ * @param string $path2
+ * @return bool
+ */
+ public function rename($path1, $path2) {
+ return $this->storage->rename($path1, $path2);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.copy.php
+ *
+ * @param string $path1
+ * @param string $path2
+ * @return bool
+ */
+ public function copy($path1, $path2) {
+ return $this->storage->copy($path1, $path2);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.fopen.php
+ *
+ * @param string $path
+ * @param string $mode
+ * @return resource
+ */
+ public function fopen($path, $mode) {
+ return $this->storage->fopen($path, $mode);
+ }
+
+ /**
+ * get the mimetype for a file or folder
+ * The mimetype for a folder is required to be "httpd/unix-directory"
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getMimeType($path) {
+ return $this->storage->getMimeType($path);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.hash.php
+ *
+ * @param string $type
+ * @param string $path
+ * @param bool $raw
+ * @return string
+ */
+ public function hash($type, $path, $raw = false) {
+ return $this->storage->hash($type, $path, $raw);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.free_space.php
+ *
+ * @param string $path
+ * @return int
+ */
+ public function free_space($path) {
+ return $this->storage->free_space($path);
+ }
+
+ /**
+ * search for occurrences of $query in file names
+ *
+ * @param string $query
+ * @return array
+ */
+ public function search($query) {
+ return $this->storage->search($query);
+ }
+
+ /**
+ * see http://php.net/manual/en/function.touch.php
+ * If the backend does not support the operation, false should be returned
+ *
+ * @param string $path
+ * @param int $mtime
+ * @return bool
+ */
+ public function touch($path, $mtime = null) {
+ return $this->storage->touch($path, $mtime);
+ }
+
+ /**
+ * get the path to a local version of the file.
+ * The local version of the file can be temporary and doesn't have to be persistent across requests
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getLocalFile($path) {
+ return $this->storage->getLocalFile($path);
+ }
+
+ /**
+ * get the path to a local version of the folder.
+ * The local version of the folder can be temporary and doesn't have to be persistent across requests
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getLocalFolder($path) {
+ return $this->storage->getLocalFolder($path);
+ }
+
+ /**
+ * check if a file or folder has been updated since $time
+ *
+ * @param string $path
+ * @param int $time
+ * @return bool
+ *
+ * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
+ * returning true for other changes in the folder is optional
+ */
+ public function hasUpdated($path, $time) {
+ return $this->storage->hasUpdated($path, $time);
+ }
+
+ /**
+ * get a cache instance for the storage
+ *
+ * @param string $path
+ * @return \OC\Files\Cache\Cache
+ */
+ public function getCache($path = '') {
+ return $this->storage->getCache($path);
+ }
+
+ /**
+ * get a scanner instance for the storage
+ *
+ * @param string $path
+ * @return \OC\Files\Cache\Scanner
+ */
+ public function getScanner($path = '') {
+ return $this->storage->getScanner($path);
+ }
+
+
+ /**
+ * get the user id of the owner of a file or folder
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getOwner($path) {
+ return $this->storage->getOwner($path);
+ }
+
+ /**
+ * get a permissions cache instance for the cache
+ *
+ * @param string $path
+ * @return \OC\Files\Cache\Permissions
+ */
+ public function getPermissionsCache($path = '') {
+ return $this->storage->getPermissions($path);
+ }
+
+ /**
+ * get a watcher instance for the cache
+ *
+ * @param string $path
+ * @return \OC\Files\Cache\Watcher
+ */
+ public function getWatcher($path = '') {
+ return $this->storage->getWatcher($path);
+ }
+
+ /**
+ * @return \OC\Files\Cache\Storage
+ */
+ public function getStorageCache() {
+ return $this->storage->getStorageCache();
+ }
+
+ /**
+ * get the ETag for a file or folder
+ *
+ * @param string $path
+ * @return string
+ */
+ public function getETag($path) {
+ return $this->storage->getETag($path);
+ }
+}
diff --git a/lib/files/stream/staticstream.php b/lib/files/stream/staticstream.php
index 7725a6a5a04..45b1a7a81f8 100644
--- a/lib/files/stream/staticstream.php
+++ b/lib/files/stream/staticstream.php
@@ -9,6 +9,8 @@
namespace OC\Files\Stream;
class StaticStream {
+ const MODE_FILE = 0100000;
+
public $context;
protected static $data = array();
@@ -26,6 +28,10 @@ class StaticStream {
public function stream_flush() {
}
+ public static function clear() {
+ self::$data = array();
+ }
+
public function stream_open($path, $mode, $options, &$opened_path) {
switch ($mode[0]) {
case 'r':
@@ -94,36 +100,7 @@ class StaticStream {
}
public function stream_stat() {
- $size = strlen(self::$data[$this->path]);
- $time = time();
- return array(
- 0 => 0,
- 'dev' => 0,
- 1 => 0,
- 'ino' => 0,
- 2 => 0777,
- 'mode' => 0777,
- 3 => 1,
- 'nlink' => 1,
- 4 => 0,
- 'uid' => 0,
- 5 => 0,
- 'gid' => 0,
- 6 => '',
- 'rdev' => '',
- 7 => $size,
- 'size' => $size,
- 8 => $time,
- 'atime' => $time,
- 9 => $time,
- 'mtime' => $time,
- 10 => $time,
- 'ctime' => $time,
- 11 => -1,
- 'blksize' => -1,
- 12 => -1,
- 'blocks' => -1,
- );
+ return $this->url_stat($this->path);
}
public function stream_tell() {
@@ -157,34 +134,22 @@ class StaticStream {
if (isset(self::$data[$path])) {
$size = strlen(self::$data[$path]);
$time = time();
- return array(
- 0 => 0,
+ $data = array(
'dev' => 0,
- 1 => 0,
'ino' => 0,
- 2 => 0777,
- 'mode' => 0777,
- 3 => 1,
+ 'mode' => self::MODE_FILE | 0777,
'nlink' => 1,
- 4 => 0,
'uid' => 0,
- 5 => 0,
'gid' => 0,
- 6 => '',
'rdev' => '',
- 7 => $size,
'size' => $size,
- 8 => $time,
'atime' => $time,
- 9 => $time,
'mtime' => $time,
- 10 => $time,
'ctime' => $time,
- 11 => -1,
'blksize' => -1,
- 12 => -1,
'blocks' => -1,
);
+ return array_values($data) + $data;
}
return false;
}
diff --git a/lib/files/view.php b/lib/files/view.php
index 19f33ad64a2..c9727fe4984 100644
--- a/lib/files/view.php
+++ b/lib/files/view.php
@@ -245,14 +245,17 @@ class View {
if (!is_null($mtime) and !is_numeric($mtime)) {
$mtime = strtotime($mtime);
}
-
+
$hooks = array('touch');
-
+
if (!$this->file_exists($path)) {
$hooks[] = 'write';
}
-
- return $this->basicOperation('touch', $path, $hooks, $mtime);
+ $result = $this->basicOperation('touch', $path, $hooks, $mtime);
+ if (!$result) { //if native touch fails, we emulate it by changing the mtime in the cache
+ $this->putFileInfo($path, array('mtime' => $mtime));
+ }
+ return true;
}
public function file_get_contents($path) {
@@ -263,11 +266,13 @@ class View {
if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
if (\OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data)
- && Filesystem::isValidPath($path)) {
+ and Filesystem::isValidPath($path)
+ and !Filesystem::isFileBlacklisted($path)
+ ) {
$path = $this->getRelativePath($absolutePath);
$exists = $this->file_exists($path);
$run = true;
- if ($this->fakeRoot == Filesystem::getRoot()) {
+ if ($this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path)) {
if (!$exists) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
@@ -295,7 +300,7 @@ class View {
list ($count, $result) = \OC_Helper::streamCopy($data, $target);
fclose($target);
fclose($data);
- if ($this->fakeRoot == Filesystem::getRoot()) {
+ if ($this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path) && $result !== false) {
if (!$exists) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
@@ -335,8 +340,12 @@ class View {
$postFix2 = (substr($path2, -1, 1) === '/') ? '/' : '';
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
- if (\OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2)
- and Filesystem::isValidPath($path2)) {
+ if (
+ \OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2)
+ and Filesystem::isValidPath($path2)
+ and Filesystem::isValidPath($path1)
+ and !Filesystem::isFileBlacklisted($path2)
+ ) {
$path1 = $this->getRelativePath($absolutePath1);
$path2 = $this->getRelativePath($absolutePath2);
@@ -344,7 +353,16 @@ class View {
return false;
}
$run = true;
- if ($this->fakeRoot == Filesystem::getRoot()) {
+ if ($this->fakeRoot == Filesystem::getRoot() && (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_run => &$run
+ )
+ );
+ } elseif ($this->fakeRoot == Filesystem::getRoot()) {
\OC_Hook::emit(
Filesystem::CLASSNAME, Filesystem::signal_rename,
array(
@@ -362,17 +380,43 @@ class View {
list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
if ($storage) {
$result = $storage->rename($internalPath1, $internalPath2);
+ \OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2);
} else {
$result = false;
}
} else {
- $source = $this->fopen($path1 . $postFix1, 'r');
- $target = $this->fopen($path2 . $postFix2, 'w');
- list($count, $result) = \OC_Helper::streamCopy($source, $target);
- list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
- $storage1->unlink($internalPath1);
+ if ($this->is_dir($path1)) {
+ $result = $this->copy($path1, $path2);
+ if ($result === true) {
+ list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
+ $result = $storage1->deleteAll($internalPath1);
+ }
+ } else {
+ $source = $this->fopen($path1 . $postFix1, 'r');
+ $target = $this->fopen($path2 . $postFix2, 'w');
+ list($count, $result) = \OC_Helper::streamCopy($source, $target);
+
+ // close open handle - especially $source is necessary because unlink below will
+ // throw an exception on windows because the file is locked
+ fclose($source);
+ fclose($target);
+
+ if ($result !== false) {
+ list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
+ $storage1->unlink($internalPath1);
+ }
+ }
}
- if ($this->fakeRoot == Filesystem::getRoot()) {
+ if ($this->fakeRoot == Filesystem::getRoot() && (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,
+ )
+ );
+ } elseif ($this->fakeRoot == Filesystem::getRoot() && $result !== false) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_rename,
@@ -396,7 +440,12 @@ class View {
$postFix2 = (substr($path2, -1, 1) === '/') ? '/' : '';
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
- if (\OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and Filesystem::isValidPath($path2)) {
+ if (
+ \OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2)
+ and Filesystem::isValidPath($path2)
+ and Filesystem::isValidPath($path1)
+ and !Filesystem::isFileBlacklisted($path2)
+ ) {
$path1 = $this->getRelativePath($absolutePath1);
$path2 = $this->getRelativePath($absolutePath2);
@@ -448,11 +497,20 @@ class View {
$result = false;
}
} else {
- $source = $this->fopen($path1 . $postFix1, 'r');
- $target = $this->fopen($path2 . $postFix2, 'w');
- list($count, $result) = \OC_Helper::streamCopy($source, $target);
+ if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) {
+ $result = $this->mkdir($path2);
+ while ($file = readdir($dh)) {
+ if (!Filesystem::isIgnoredDir($file)) {
+ $result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file);
+ }
+ }
+ } else {
+ $source = $this->fopen($path1 . $postFix1, 'r');
+ $target = $this->fopen($path2 . $postFix2, 'w');
+ list($count, $result) = \OC_Helper::streamCopy($source, $target);
+ }
}
- if ($this->fakeRoot == Filesystem::getRoot()) {
+ if ($this->fakeRoot == Filesystem::getRoot() && $result !== false) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_copy,
@@ -598,7 +656,10 @@ class View {
private function basicOperation($operation, $path, $hooks = array(), $extraParam = null) {
$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
- if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) and Filesystem::isValidPath($path)) {
+ if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam)
+ and Filesystem::isValidPath($path)
+ and !Filesystem::isFileBlacklisted($path)
+ ) {
$path = $this->getRelativePath($absolutePath);
if ($path == null) {
return false;
@@ -613,7 +674,7 @@ class View {
$result = $storage->$operation($internalPath);
}
$result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result);
- if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot()) {
+ if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot() && $result !== false) {
if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
$this->runHooks($hooks, $path, true);
}
@@ -627,7 +688,7 @@ class View {
private function runHooks($hooks, $path, $post = false) {
$prefix = ($post) ? 'post_' : '';
$run = true;
- if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot()) {
+ if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path)) {
foreach ($hooks as $hook) {
if ($hook != 'read') {
\OC_Hook::emit(
@@ -711,7 +772,7 @@ class View {
if ($subStorage) {
$subCache = $subStorage->getCache('');
$rootEntry = $subCache->get('');
- $data['size'] += $rootEntry['size'];
+ $data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0;
}
}
}
@@ -724,6 +785,9 @@ class View {
$data['permissions'] = $permissions;
}
}
+
+ $data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data);
+
return $data;
}
@@ -731,6 +795,7 @@ class View {
* get the content of a directory
*
* @param string $directory path under datadirectory
+ * @param string $mimetype_filter limit returned content to this mimetype or mimepart
* @return array
*/
public function getDirectoryContent($directory, $mimetype_filter = '') {
@@ -758,18 +823,18 @@ class View {
}
$files = $cache->getFolderContents($internalPath); //TODO: mimetype_filter
+ $permissions = $permissionsCache->getDirectoryPermissions($cache->getId($internalPath), $user);
$ids = array();
foreach ($files as $i => $file) {
$files[$i]['type'] = $file['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
$ids[] = $file['fileid'];
- $permissions = $permissionsCache->get($file['fileid'], $user);
- if ($permissions === -1) {
- $permissions = $storage->getPermissions($file['path']);
- $permissionsCache->set($file['fileid'], $user, $permissions);
+ if (!isset($permissions[$file['fileid']])) {
+ $permissions[$file['fileid']] = $storage->getPermissions($file['path']);
+ $permissionsCache->set($file['fileid'], $user, $permissions[$file['fileid']]);
}
- $files[$i]['permissions'] = $permissions;
+ $files[$i]['permissions'] = $permissions[$file['fileid']];
}
//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
@@ -930,11 +995,11 @@ class View {
}
/**
- * Get the owner for a file or folder
- *
- * @param string $path
- * @return string
- */
+ * Get the owner for a file or folder
+ *
+ * @param string $path
+ * @return string
+ */
public function getOwner($path) {
return $this->basicOperation('getOwner', $path);
}
@@ -968,7 +1033,7 @@ class View {
*/
public function getPath($id) {
list($storage, $internalPath) = Cache\Cache::getById($id);
- $mounts = Mount::findByStorageId($storage);
+ $mounts = Filesystem::getMountByStorageId($storage);
foreach ($mounts as $mount) {
/**
* @var \OC\Files\Mount $mount
diff --git a/lib/helper.php b/lib/helper.php
index 41985ca57a7..1860a55fc8f 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -27,6 +27,7 @@
class OC_Helper {
private static $mimetypes=array();
private static $tmpFiles=array();
+ private static $mimetypeIcons = array();
/**
* @brief Creates an url using a defined route
@@ -159,7 +160,7 @@ class OC_Helper {
*/
public static function imagePath( $app, $image ) {
// Read the selected theme from the config file
- $theme=OC_Config::getValue( "theme" );
+ $theme = OC_Util::getTheme();
// Check if the app is in the app folder
if( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/img/$image" )) {
@@ -187,31 +188,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');
- if(isset($alias[$mimetype])) {
- $mimetype=$alias[$mimetype];
+ public static function mimetypeIcon($mimetype) {
+ $alias = array('application/xml' => 'code/xml');
+ if (isset($alias[$mimetype])) {
+ $mimetype = $alias[$mimetype];
+ }
+ if (isset(self::$mimetypeIcons[$mimetype])) {
+ return self::$mimetypeIcons[$mimetype];
}
// Replace slash and backslash with a minus
- $mimetype = str_replace( "/", "-", $mimetype );
- $mimetype = str_replace( "\\", "-", $mimetype );
+ $icon = str_replace('/', '-', $mimetype);
+ $icon = str_replace( '\\', '-', $icon);
// Is it a dir?
- if( $mimetype == "dir" ) {
- return OC::$WEBROOT."/core/img/filetypes/folder.png";
+ if ($mimetype === 'dir') {
+ self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/folder.png';
+ return OC::$WEBROOT.'/core/img/filetypes/folder.png';
}
// Icon exists?
- if( file_exists( OC::$SERVERROOT."/core/img/filetypes/$mimetype.png" )) {
- return OC::$WEBROOT."/core/img/filetypes/$mimetype.png";
- }
- //try only the first part of the filetype
- $mimetype=substr($mimetype, 0, strpos($mimetype, '-'));
- if( file_exists( OC::$SERVERROOT."/core/img/filetypes/$mimetype.png" )) {
- return OC::$WEBROOT."/core/img/filetypes/$mimetype.png";
+ if (file_exists(OC::$SERVERROOT.'/core/img/filetypes/'.$icon.'.png')) {
+ self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/'.$icon.'.png';
+ return OC::$WEBROOT.'/core/img/filetypes/'.$icon.'.png';
}
- else{
- return OC::$WEBROOT."/core/img/filetypes/file.png";
+
+ // Try only the first part of the filetype
+ $mimePart = substr($icon, 0, strpos($icon, '-'));
+ if (file_exists(OC::$SERVERROOT.'/core/img/filetypes/'.$mimePart.'.png')) {
+ self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/'.$mimePart.'.png';
+ return OC::$WEBROOT.'/core/img/filetypes/'.$mimePart.'.png';
+ } else {
+ self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/file.png';
+ return OC::$WEBROOT.'/core/img/filetypes/file.png';
}
}
@@ -356,6 +364,26 @@ class OC_Helper {
}
/**
+ * Try to guess the mimetype based on filename
+ *
+ * @param string $path
+ * @return string
+ */
+ static public function getFileNameMimeType($path){
+ if(strpos($path, '.')) {
+ //try to guess the type by the file extension
+ if(!self::$mimetypes || self::$mimetypes != include 'mimetypes.list.php') {
+ self::$mimetypes=include 'mimetypes.list.php';
+ }
+ $extension=strtolower(strrchr(basename($path), "."));
+ $extension=substr($extension, 1);//remove leading .
+ return (isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream';
+ }else{
+ return 'application/octet-stream';
+ }
+ }
+
+ /**
* get the mimetype form a local file
* @param string $path
* @return string
@@ -369,17 +397,7 @@ class OC_Helper {
return "httpd/unix-directory";
}
- if(strpos($path, '.')) {
- //try to guess the type by the file extension
- if(!self::$mimetypes || self::$mimetypes != include 'mimetypes.list.php') {
- self::$mimetypes=include 'mimetypes.list.php';
- }
- $extension=strtolower(strrchr(basename($path), "."));
- $extension=substr($extension, 1);//remove leading .
- $mimeType=(isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream';
- }else{
- $mimeType='application/octet-stream';
- }
+ $mimeType = self::getFileNameMimeType($path);
if($mimeType=='application/octet-stream' and function_exists('finfo_open')
and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)) {
@@ -541,13 +559,15 @@ class OC_Helper {
}
/**
- * create a temporary file with an unique filename. It will not be deleted
- * automatically
- * @param string $postfix
- * @return string
+ * move a file to oc-noclean temp dir
+ * @param string $filename
+ * @return mixed
*
*/
- public static function tmpFileNoClean($postfix='') {
+ public static function moveToNoClean($filename='') {
+ if ($filename == '') {
+ return false;
+ }
$tmpDirNoClean=get_temp_dir().'/oc-noclean/';
if (!file_exists($tmpDirNoClean) || !is_dir($tmpDirNoClean)) {
if (file_exists($tmpDirNoClean)) {
@@ -555,10 +575,12 @@ class OC_Helper {
}
mkdir($tmpDirNoClean);
}
- $file=$tmpDirNoClean.md5(time().rand()).$postfix;
- $fh=fopen($file, 'w');
- fclose($fh);
- return $file;
+ $newname=$tmpDirNoClean.basename($filename);
+ if (rename($filename, $newname)) {
+ return $newname;
+ } else {
+ return false;
+ }
}
/**
@@ -597,7 +619,7 @@ class OC_Helper {
}
/**
- * remove all files created by self::tmpFileNoClean
+ * remove all files in PHP /oc-noclean temp dir
*/
public static function cleanTmpNoClean() {
$tmpDirNoCleanFile=get_temp_dir().'/oc-noclean/';
@@ -764,9 +786,15 @@ class OC_Helper {
public static function maxUploadFilesize($dir) {
$upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
$post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size'));
- $maxUploadFilesize = min($upload_max_filesize, $post_max_size);
-
$freeSpace = \OC\Files\Filesystem::free_space($dir);
+ if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
+ $maxUploadFilesize = \OC\Files\FREE_SPACE_UNLIMITED;
+ } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
+ $maxUploadFilesize = max($upload_max_filesize, $post_max_size); //only the non 0 value counts
+ } else {
+ $maxUploadFilesize = min($upload_max_filesize, $post_max_size);
+ }
+
if($freeSpace !== \OC\Files\FREE_SPACE_UNKNOWN){
$freeSpace = max($freeSpace, 0);
@@ -806,11 +834,19 @@ class OC_Helper {
$used = 0;
}
$free = \OC\Files\Filesystem::free_space();
- $total = $free + $used;
+ if ($free >= 0){
+ $total = $free + $used;
+ } else {
+ $total = $free; //either unknown or unlimited
+ }
if ($total == 0) {
$total = 1; // prevent division by zero
}
- $relative = round(($used / $total) * 10000) / 100;
+ if ($total >= 0){
+ $relative = round(($used / $total) * 10000) / 100;
+ } else {
+ $relative = 0;
+ }
return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
}
diff --git a/lib/hintexception.php b/lib/hintexception.php
new file mode 100644
index 00000000000..3934ae2a4c2
--- /dev/null
+++ b/lib/hintexception.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 OC;
+
+class HintException extends \Exception {
+
+ private $hint;
+
+ public function __construct($message, $hint = '', $code = 0, Exception $previous = null) {
+ $this->hint = $hint;
+ parent::__construct($message, $code, $previous);
+ }
+
+ public function __toString() {
+ return __CLASS__ . ": [{$this->code}]: {$this->message} ({$this->hint})\n";
+ }
+
+ public function getHint() {
+ return $this->hint;
+ }
+}
diff --git a/lib/hooks/basicemitter.php b/lib/hooks/basicemitter.php
new file mode 100644
index 00000000000..9ffe1af2314
--- /dev/null
+++ b/lib/hooks/basicemitter.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\Hooks;
+
+abstract class BasicEmitter implements Emitter {
+
+ /**
+ * @var (callable[])[] $listeners
+ */
+ protected $listeners = array();
+
+ /**
+ * @param string $scope
+ * @param string $method
+ * @param callable $callback
+ */
+ public function listen($scope, $method, $callback) {
+ $eventName = $scope . '::' . $method;
+ if (!isset($this->listeners[$eventName])) {
+ $this->listeners[$eventName] = array();
+ }
+ if (array_search($callback, $this->listeners[$eventName]) === false) {
+ $this->listeners[$eventName][] = $callback;
+ }
+ }
+
+ /**
+ * @param string $scope optional
+ * @param string $method optional
+ * @param callable $callback optional
+ */
+ public function removeListener($scope = null, $method = null, $callback = null) {
+ $names = array();
+ $allNames = array_keys($this->listeners);
+ if ($scope and $method) {
+ $name = $scope . '::' . $method;
+ if (isset($this->listeners[$name])) {
+ $names[] = $name;
+ }
+ } elseif ($scope) {
+ foreach ($allNames as $name) {
+ $parts = explode('::', $name, 2);
+ if ($parts[0] == $scope) {
+ $names[] = $name;
+ }
+ }
+ } elseif ($method) {
+ foreach ($allNames as $name) {
+ $parts = explode('::', $name, 2);
+ if ($parts[1] == $method) {
+ $names[] = $name;
+ }
+ }
+ } else {
+ $names = $allNames;
+ }
+
+ foreach ($names as $name) {
+ if ($callback) {
+ $index = array_search($callback, $this->listeners[$name]);
+ if ($index !== false) {
+ unset($this->listeners[$name][$index]);
+ }
+ } else {
+ $this->listeners[$name] = array();
+ }
+ }
+ }
+
+ /**
+ * @param string $scope
+ * @param string $method
+ * @param array $arguments optional
+ */
+ protected function emit($scope, $method, $arguments = array()) {
+ $eventName = $scope . '::' . $method;
+ if (isset($this->listeners[$eventName])) {
+ foreach ($this->listeners[$eventName] as $callback) {
+ call_user_func_array($callback, $arguments);
+ }
+ }
+ }
+}
diff --git a/lib/hooks/emitter.php b/lib/hooks/emitter.php
new file mode 100644
index 00000000000..8e9074bad67
--- /dev/null
+++ b/lib/hooks/emitter.php
@@ -0,0 +1,32 @@
+<?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\Hooks;
+
+/**
+ * Class Emitter
+ *
+ * interface for all classes that are able to emit events
+ *
+ * @package OC\Hooks
+ */
+interface Emitter {
+ /**
+ * @param string $scope
+ * @param string $method
+ * @param callable $callback
+ */
+ public function listen($scope, $method, $callback);
+
+ /**
+ * @param string $scope optional
+ * @param string $method optional
+ * @param callable $callback optional
+ */
+ public function removeListener($scope = null, $method = null, $callback = null);
+}
diff --git a/lib/hooks/forwardingemitter.php b/lib/hooks/forwardingemitter.php
new file mode 100644
index 00000000000..1aacc4012e0
--- /dev/null
+++ b/lib/hooks/forwardingemitter.php
@@ -0,0 +1,50 @@
+<?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\Hooks;
+
+/**
+ * Class ForwardingEmitter
+ *
+ * allows forwarding all listen calls to other emitters
+ *
+ * @package OC\Hooks
+ */
+abstract class ForwardingEmitter extends BasicEmitter {
+ /**
+ * @var \OC\Hooks\Emitter[] array
+ */
+ private $forwardEmitters = array();
+
+ /**
+ * @param string $scope
+ * @param string $method
+ * @param callable $callback
+ */
+ public function listen($scope, $method, $callback) {
+ parent::listen($scope, $method, $callback);
+ foreach ($this->forwardEmitters as $emitter) {
+ $emitter->listen($scope, $method, $callback);
+ }
+ }
+
+ /**
+ * @param \OC\Hooks\Emitter $emitter
+ */
+ protected function forward($emitter) {
+ $this->forwardEmitters[] = $emitter;
+
+ //forward all previously connected hooks
+ foreach ($this->listeners as $key => $listeners) {
+ list($scope, $method) = explode('::', $key, 2);
+ foreach ($listeners as $listener) {
+ $emitter->listen($scope, $method, $listener);
+ }
+ }
+ }
+}
diff --git a/lib/hooks/legacyemitter.php b/lib/hooks/legacyemitter.php
new file mode 100644
index 00000000000..a2d16ace9a7
--- /dev/null
+++ b/lib/hooks/legacyemitter.php
@@ -0,0 +1,16 @@
+<?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\Hooks;
+
+abstract class LegacyEmitter extends BasicEmitter {
+ protected function emit($scope, $method, $arguments = array()) {
+ \OC_Hook::emit($scope, $method, $arguments);
+ parent::emit($scope, $method, $arguments);
+ }
+}
diff --git a/lib/hooks/publicemitter.php b/lib/hooks/publicemitter.php
new file mode 100644
index 00000000000..e2371713ac3
--- /dev/null
+++ b/lib/hooks/publicemitter.php
@@ -0,0 +1,20 @@
+<?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\Hooks;
+
+class PublicEmitter extends BasicEmitter {
+ /**
+ * @param string $scope
+ * @param string $method
+ * @param array $arguments optional
+ */
+ public function emit($scope, $method, $arguments = array()) {
+ parent::emit($scope, $method, $arguments);
+ }
+}
diff --git a/lib/installer.php b/lib/installer.php
index 251d115b76c..49ba4492632 100644
--- a/lib/installer.php
+++ b/lib/installer.php
@@ -134,8 +134,10 @@ class OC_Installer{
}
// check if the app is compatible with this version of ownCloud
- $version=OC_Util::getVersion();
- if(!isset($info['require']) or ($version[0]>$info['require'])) {
+ if(
+ !isset($info['require'])
+ or !OC_App::isAppVersionCompatible(OC_Util::getVersion(), $info['require'])
+ ) {
OC_Log::write('core',
'App can\'t be installed because it is not compatible with this version of ownCloud',
OC_Log::ERROR);
diff --git a/lib/json.php b/lib/json.php
index f929e958957..6ba0b13806b 100644
--- a/lib/json.php
+++ b/lib/json.php
@@ -14,7 +14,7 @@ class OC_JSON{
public static function setContentTypeHeader($type='application/json') {
if (!self::$send_content_type_header) {
// We send json data
- header( 'Content-Type: '.$type );
+ header( 'Content-Type: '.$type . '; charset=utf-8');
self::$send_content_type_header = true;
}
}
diff --git a/lib/l10n.php b/lib/l10n.php
index 1e07a9b9557..d35ce5fed14 100644
--- a/lib/l10n.php
+++ b/lib/l10n.php
@@ -122,9 +122,21 @@ class OC_L10N{
)
&& file_exists($i18ndir.$lang.'.php')) {
// Include the file, save the data from $CONFIG
- include strip_tags($i18ndir).strip_tags($lang).'.php';
+ $transFile = strip_tags($i18ndir).strip_tags($lang).'.php';
+ include $transFile;
if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)) {
$this->translations = $TRANSLATIONS;
+ //merge with translations from theme
+ $theme = OC_Config::getValue( "theme" );
+ if (!is_null($theme)) {
+ $transFile = OC::$SERVERROOT.'/themes/'.$theme.substr($transFile, strlen(OC::$SERVERROOT));
+ if (file_exists($transFile)) {
+ include $transFile;
+ if (isset($TRANSLATIONS) && is_array($TRANSLATIONS)) {
+ $this->translations = array_merge($this->translations, $TRANSLATIONS);
+ }
+ }
+ }
}
}
@@ -298,10 +310,16 @@ class OC_L10N{
$temp = explode(';', $i);
$temp[0] = str_replace('-', '_', $temp[0]);
if( ($key = array_search($temp[0], $available)) !== false) {
+ if (is_null($app)) {
+ self::$language = $available[$key];
+ }
return $available[$key];
}
foreach($available as $l) {
if ( $temp[0] == substr($l, 0, 2) ) {
+ if (is_null($app)) {
+ self::$language = $l;
+ }
return $l;
}
}
diff --git a/lib/l10n/af_ZA.php b/lib/l10n/af_ZA.php
index 38e91288fbe..de32778026f 100644
--- a/lib/l10n/af_ZA.php
+++ b/lib/l10n/af_ZA.php
@@ -4,5 +4,6 @@
"Settings" => "Instellings",
"Users" => "Gebruikers",
"Apps" => "Toepassings",
-"Admin" => "Admin"
+"Admin" => "Admin",
+"web services under your control" => "webdienste onder jou beheer"
);
diff --git a/lib/l10n/ar.php b/lib/l10n/ar.php
index 77e02dd77b1..107b27a1fc8 100644
--- a/lib/l10n/ar.php
+++ b/lib/l10n/ar.php
@@ -1,12 +1,52 @@
<?php $TRANSLATIONS = array(
"Help" => "المساعدة",
"Personal" => "شخصي",
-"Settings" => "تعديلات",
+"Settings" => "إعدادات",
"Users" => "المستخدمين",
+"Apps" => "التطبيقات",
+"Admin" => "المدير",
+"web services under your control" => "خدمات الشبكة تحت سيطرتك",
+"ZIP download is turned off." => "تحميل ملفات ZIP متوقف",
+"Files need to be downloaded one by one." => "الملفات بحاجة الى ان يتم تحميلها واحد تلو الاخر",
+"Back to Files" => "العودة الى الملفات",
+"Selected files too large to generate zip file." => "الملفات المحددة كبيرة جدا ليتم ضغطها في ملف zip",
+"couldn't be determined" => "تعذّر تحديده",
+"Application is not enabled" => "التطبيق غير مفعّل",
"Authentication error" => "لم يتم التأكد من الشخصية بنجاح",
+"Token expired. Please reload page." => "انتهت صلاحية الكلمة , يرجى اعادة تحميل الصفحة",
"Files" => "الملفات",
"Text" => "معلومات إضافية",
+"Images" => "صور",
+"%s enter the database username." => "%s ادخل اسم المستخدم الخاص بقاعدة البيانات.",
+"%s enter the database name." => "%s ادخل اسم فاعدة البيانات",
+"%s you may not use dots in the database name" => "%s لا يسمح لك باستخدام نقطه (.) في اسم قاعدة البيانات",
+"MS SQL username and/or password not valid: %s" => "اسم المستخدم و/أو كلمة المرور لنظام MS SQL غير صحيح : %s",
+"You need to enter either an existing account or the administrator." => "انت بحاجة لكتابة اسم مستخدم موجود أو حساب المدير.",
+"MySQL username and/or password not valid" => "اسم المستخدم و/أو كلمة المرور لنظام MySQL غير صحيح",
+"DB Error: \"%s\"" => "خطأ في قواعد البيانات : \"%s\"",
+"Offending command was: \"%s\"" => "الأمر المخالف كان : \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "أسم المستخدم '%s'@'localhost' الخاص بـ MySQL موجود مسبقا",
+"Drop this user from MySQL" => "احذف اسم المستخدم هذا من الـ MySQL",
+"MySQL user '%s'@'%%' already exists" => "أسم المستخدم '%s'@'%%' الخاص بـ MySQL موجود مسبقا",
+"Drop this user from MySQL." => "احذف اسم المستخدم هذا من الـ MySQL.",
+"Oracle username and/or password not valid" => "اسم المستخدم و/أو كلمة المرور لنظام Oracle غير صحيح",
+"Offending command was: \"%s\", name: %s, password: %s" => "الأمر المخالف كان : \"%s\", اسم المستخدم : %s, كلمة المرور: %s",
+"PostgreSQL username and/or password not valid" => "اسم المستخدم / أو كلمة المرور الخاصة بـPostgreSQL غير صحيحة",
+"Set an admin username." => "اعداد اسم مستخدم للمدير",
+"Set an admin password." => "اعداد كلمة مرور للمدير",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "اعدادات خادمك غير صحيحة بشكل تسمح لك بمزامنة ملفاتك وذلك بسبب أن واجهة WebDAV تبدو معطلة",
+"Please double check the <a href='%s'>installation guides</a>." => "الرجاء التحقق من <a href='%s'>دليل التنصيب</a>.",
"seconds ago" => "منذ ثواني",
"1 minute ago" => "منذ دقيقة",
-"today" => "اليوم"
+"%d minutes ago" => "%d دقيقة مضت",
+"1 hour ago" => "قبل ساعة مضت",
+"%d hours ago" => "%d ساعة مضت",
+"today" => "اليوم",
+"yesterday" => "يوم أمس",
+"%d days ago" => "%d يوم مضى",
+"last month" => "الشهر الماضي",
+"%d months ago" => "%d شهر مضت",
+"last year" => "السنةالماضية",
+"years ago" => "سنة مضت",
+"Could not find category \"%s\"" => "تعذر العثور على المجلد \"%s\""
);
diff --git a/lib/l10n/bg_BG.php b/lib/l10n/bg_BG.php
index d32e2aadfc5..e23112c8302 100644
--- a/lib/l10n/bg_BG.php
+++ b/lib/l10n/bg_BG.php
@@ -5,6 +5,7 @@
"Users" => "Потребители",
"Apps" => "Приложения",
"Admin" => "Админ",
+"web services under your control" => "уеб услуги под Ваш контрол",
"ZIP download is turned off." => "Изтеглянето като ZIP е изключено.",
"Files need to be downloaded one by one." => "Файловете трябва да се изтеглят един по един.",
"Back to Files" => "Назад към файловете",
@@ -16,22 +17,25 @@
"Files" => "Файлове",
"Text" => "Текст",
"Images" => "Снимки",
-"Set an admin username." => "Въведете потребителско име за администратор.",
-"Set an admin password." => "Въведете парола за администратор.",
-"Specify a data folder." => "Укажете папка за данни",
"%s enter the database username." => "%s въведете потребителско име за базата с данни.",
"%s enter the database name." => "%s въведете име на базата с данни.",
"%s you may not use dots in the database name" => "%s, не можете да ползвате точки в името на базата от данни",
-"PostgreSQL username and/or password not valid" => "Невалидно PostgreSQL потребителско име и/или парола",
+"MS SQL username and/or password not valid: %s" => "Невалидно MS SQL потребителско име и/или парола: %s",
"You need to enter either an existing account or the administrator." => "Необходимо е да влезете в всъществуващ акаунт или като администратора",
-"Oracle username and/or password not valid" => "Невалидно Oracle потребителско име и/или парола",
"MySQL username and/or password not valid" => "Невалидно MySQL потребителско име и/или парола",
"DB Error: \"%s\"" => "Грешка в базата от данни: \"%s\"",
+"Offending command was: \"%s\"" => "Проблемната команда беше: \"%s\"",
"MySQL user '%s'@'localhost' exists already." => "MySQL потребителят '%s'@'localhost' вече съществува",
"Drop this user from MySQL" => "Изтриване на потребителя от MySQL",
"MySQL user '%s'@'%%' already exists" => "MySQL потребителят '%s'@'%%' вече съществува.",
"Drop this user from MySQL." => "Изтриване на потребителя от MySQL.",
-"MS SQL username and/or password not valid: %s" => "Невалидно MS SQL потребителско име и/или парола: %s",
+"Oracle connection could not be established" => "Oracle връзка не можа да се осъществи",
+"Oracle username and/or password not valid" => "Невалидно Oracle потребителско име и/или парола",
+"Offending command was: \"%s\", name: %s, password: %s" => "Проблемната команда беше: \"%s\", име: %s, парола: %s",
+"PostgreSQL username and/or password not valid" => "Невалидно PostgreSQL потребителско име и/или парола",
+"Set an admin username." => "Въведете потребителско име за администратор.",
+"Set an admin password." => "Въведете парола за администратор.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Вашият web сървър все още не е удачно настроен да позволява синхронизация на файлове, защото WebDAV интерфейсът изглежда не работи.",
"Please double check the <a href='%s'>installation guides</a>." => "Моля направете повторна справка с <a href='%s'>ръководството за инсталиране</a>.",
"seconds ago" => "преди секунди",
"1 minute ago" => "преди 1 минута",
@@ -45,8 +49,5 @@
"%d months ago" => "преди %d месеца",
"last year" => "последната година",
"years ago" => "последните години",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s е налична. Получете <a href=\"%s\">повече информация</a>",
-"up to date" => "е актуална",
-"updates check is disabled" => "проверката за обновления е изключена",
"Could not find category \"%s\"" => "Невъзможно откриване на категорията \"%s\""
);
diff --git a/lib/l10n/bn_BD.php b/lib/l10n/bn_BD.php
index cb6ff4455a9..ab1d9b94d0d 100644
--- a/lib/l10n/bn_BD.php
+++ b/lib/l10n/bn_BD.php
@@ -2,9 +2,10 @@
"Help" => "সহায়িকা",
"Personal" => "ব্যক্তিগত",
"Settings" => "নিয়ামকসমূহ",
-"Users" => "ব্যভহারকারী",
+"Users" => "ব্যবহারকারী",
"Apps" => "অ্যাপ",
-"Admin" => "প্রশাসক",
+"Admin" => "প্রশাসন",
+"web services under your control" => "ওয়েব সার্ভিস আপনার হাতের মুঠোয়",
"ZIP download is turned off." => "ZIP ডাউনলোড বন্ধ করা আছে।",
"Files need to be downloaded one by one." => "ফাইলগুলো একে একে ডাউনলোড করা আবশ্যক।",
"Back to Files" => "ফাইলে ফিরে চল",
@@ -13,6 +14,7 @@
"Authentication error" => "অনুমোদন ঘটিত সমস্যা",
"Token expired. Please reload page." => "টোকেন মেয়াদোত্তীর্ণ। দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।",
"Files" => "ফাইল",
+"Text" => "টেক্সট",
"seconds ago" => "সেকেন্ড পূর্বে",
"1 minute ago" => "১ মিনিট পূর্বে",
"%d minutes ago" => "%d মিনিট পূর্বে",
@@ -22,8 +24,5 @@
"%d days ago" => "%d দিন পূর্বে",
"last month" => "গত মাস",
"last year" => "গত বছর",
-"years ago" => "বছর পূর্বে",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s এখন সুলভ। <a href=\"%s\">আরও জানুন</a>",
-"up to date" => "সর্বশেষ",
-"updates check is disabled" => "পরিবর্ধন পরীক্ষণ করা বন্ধ রাখা হয়েছে"
+"years ago" => "বছর পূর্বে"
);
diff --git a/lib/l10n/ca.php b/lib/l10n/ca.php
index 108bb5c09be..93f7fa5f7bc 100644
--- a/lib/l10n/ca.php
+++ b/lib/l10n/ca.php
@@ -5,6 +5,7 @@
"Users" => "Usuaris",
"Apps" => "Aplicacions",
"Admin" => "Administració",
+"web services under your control" => "controleu els vostres serveis web",
"ZIP download is turned off." => "La baixada en ZIP està desactivada.",
"Files need to be downloaded one by one." => "Els fitxers s'han de baixar d'un en un.",
"Back to Files" => "Torna a Fitxers",
@@ -16,16 +17,11 @@
"Files" => "Fitxers",
"Text" => "Text",
"Images" => "Imatges",
-"Set an admin username." => "Establiu un nom d'usuari per l'administrador.",
-"Set an admin password." => "Establiu una contrasenya per l'administrador.",
-"Specify a data folder." => "Especifiqueu una carpeta de dades.",
"%s enter the database username." => "%s escriviu el nom d'usuari de la base de dades.",
"%s enter the database name." => "%s escriviu el nom de la base de dades.",
"%s you may not use dots in the database name" => "%s no podeu usar punts en el nom de la base de dades",
-"%s set the database host." => "%s establiu l'ordinador central de la base de dades.",
-"PostgreSQL username and/or password not valid" => "Nom d'usuari i/o contrasenya PostgreSQL no vàlids",
+"MS SQL username and/or password not valid: %s" => "Nom d'usuari i/o contrasenya MS SQL no vàlids: %s",
"You need to enter either an existing account or the administrator." => "Heu d'escriure un compte existent o el d'administrador.",
-"Oracle username and/or password not valid" => "Nom d'usuari i/o contrasenya Oracle no vàlids",
"MySQL username and/or password not valid" => "Nom d'usuari i/o contrasenya MySQL no vàlids",
"DB Error: \"%s\"" => "Error DB: \"%s\"",
"Offending command was: \"%s\"" => "L'ordre en conflicte és: \"%s\"",
@@ -33,8 +29,12 @@
"Drop this user from MySQL" => "Elimina aquest usuari de MySQL",
"MySQL user '%s'@'%%' already exists" => "L'usuari MySQL '%s'@'%%' ja existeix",
"Drop this user from MySQL." => "Elimina aquest usuari de MySQL.",
+"Oracle connection could not be established" => "No s'ha pogut establir la connexió Oracle",
+"Oracle username and/or password not valid" => "Nom d'usuari i/o contrasenya Oracle no vàlids",
"Offending command was: \"%s\", name: %s, password: %s" => "L'ordre en conflicte és: \"%s\", nom: %s, contrasenya: %s",
-"MS SQL username and/or password not valid: %s" => "Nom d'usuari i/o contrasenya MS SQL no vàlids: %s",
+"PostgreSQL username and/or password not valid" => "Nom d'usuari i/o contrasenya PostgreSQL no vàlids",
+"Set an admin username." => "Establiu un nom d'usuari per l'administrador.",
+"Set an admin password." => "Establiu una contrasenya per l'administrador.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "El servidor web no està configurat correctament per permetre la sincronització de fitxers perquè la interfície WebDAV sembla no funcionar correctament.",
"Please double check the <a href='%s'>installation guides</a>." => "Comproveu les <a href='%s'>guies d'instal·lació</a>.",
"seconds ago" => "segons enrere",
@@ -48,9 +48,6 @@
"last month" => "el mes passat",
"%d months ago" => "fa %d mesos",
"last year" => "l'any passat",
-"years ago" => "fa anys",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s està disponible. Obtén <a href=\"%s\">més informació</a>",
-"up to date" => "actualitzat",
-"updates check is disabled" => "la comprovació d'actualitzacions està desactivada",
+"years ago" => "anys enrere",
"Could not find category \"%s\"" => "No s'ha trobat la categoria \"%s\""
);
diff --git a/lib/l10n/cs_CZ.php b/lib/l10n/cs_CZ.php
index d9ec3d82cf7..917f383bb89 100644
--- a/lib/l10n/cs_CZ.php
+++ b/lib/l10n/cs_CZ.php
@@ -5,6 +5,7 @@
"Users" => "Uživatelé",
"Apps" => "Aplikace",
"Admin" => "Administrace",
+"web services under your control" => "služby webu pod Vaší kontrolou",
"ZIP download is turned off." => "Stahování ZIPu je vypnuto.",
"Files need to be downloaded one by one." => "Soubory musí být stahovány jednotlivě.",
"Back to Files" => "Zpět k souborům",
@@ -16,16 +17,11 @@
"Files" => "Soubory",
"Text" => "Text",
"Images" => "Obrázky",
-"Set an admin username." => "Zadejte uživatelské jméno správce.",
-"Set an admin password." => "Zadejte heslo správce.",
-"Specify a data folder." => "Určete složku dat.",
"%s enter the database username." => "Zadejte uživatelské jméno %s databáze.",
"%s enter the database name." => "Zadejte název databáze pro %s databáze.",
"%s you may not use dots in the database name" => "V názvu databáze %s nesmíte používat tečky.",
-"%s set the database host." => "Zadejte název počítače s databází %s.",
-"PostgreSQL username and/or password not valid" => "Uživatelské jméno, či heslo PostgreSQL není platné",
+"MS SQL username and/or password not valid: %s" => "Uživatelské jméno, či heslo MSSQL není platné: %s",
"You need to enter either an existing account or the administrator." => "Musíte zadat existující účet, či správce.",
-"Oracle username and/or password not valid" => "Uživatelské jméno, či heslo Oracle není platné",
"MySQL username and/or password not valid" => "Uživatelské jméno, či heslo MySQL není platné",
"DB Error: \"%s\"" => "Chyba DB: \"%s\"",
"Offending command was: \"%s\"" => "Podezřelý příkaz byl: \"%s\"",
@@ -33,12 +29,16 @@
"Drop this user from MySQL" => "Zahodit uživatele z MySQL",
"MySQL user '%s'@'%%' already exists" => "Uživatel '%s'@'%%' již v MySQL existuje",
"Drop this user from MySQL." => "Zahodit uživatele z MySQL.",
+"Oracle connection could not be established" => "Spojení s Oracle nemohlo být navázáno",
+"Oracle username and/or password not valid" => "Uživatelské jméno, či heslo Oracle není platné",
"Offending command was: \"%s\", name: %s, password: %s" => "Podezřelý příkaz byl: \"%s\", jméno: %s, heslo: %s",
-"MS SQL username and/or password not valid: %s" => "Uživatelské jméno, či heslo MSSQL není platné: %s",
+"PostgreSQL username and/or password not valid" => "Uživatelské jméno, či heslo PostgreSQL není platné",
+"Set an admin username." => "Zadejte uživatelské jméno správce.",
+"Set an admin password." => "Zadejte heslo správce.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Váš webový server není správně nastaven pro umožnění synchronizace, protože rozhraní WebDAV je rozbité.",
"Please double check the <a href='%s'>installation guides</a>." => "Zkonzultujte, prosím, <a href='%s'>průvodce instalací</a>.",
-"seconds ago" => "před vteřinami",
-"1 minute ago" => "před 1 minutou",
+"seconds ago" => "před pár vteřinami",
+"1 minute ago" => "před minutou",
"%d minutes ago" => "před %d minutami",
"1 hour ago" => "před hodinou",
"%d hours ago" => "před %d hodinami",
@@ -47,10 +47,7 @@
"%d days ago" => "před %d dny",
"last month" => "minulý měsíc",
"%d months ago" => "Před %d měsíci",
-"last year" => "loni",
+"last year" => "minulý rok",
"years ago" => "před lety",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s je dostupná. Získat <a href=\"%s\">více informací</a>",
-"up to date" => "aktuální",
-"updates check is disabled" => "kontrola aktualizací je vypnuta",
"Could not find category \"%s\"" => "Nelze nalézt kategorii \"%s\""
);
diff --git a/lib/l10n/cy_GB.php b/lib/l10n/cy_GB.php
new file mode 100644
index 00000000000..27140ba6dbb
--- /dev/null
+++ b/lib/l10n/cy_GB.php
@@ -0,0 +1,52 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Cymorth",
+"Personal" => "Personol",
+"Settings" => "Gosodiadau",
+"Users" => "Defnyddwyr",
+"Apps" => "Pecynnau",
+"Admin" => "Gweinyddu",
+"web services under your control" => "gwasanaethau gwe a reolir gennych",
+"ZIP download is turned off." => "Mae llwytho ZIP wedi ei ddiffodd.",
+"Files need to be downloaded one by one." => "Mae angen llwytho ffeiliau i lawr fesul un.",
+"Back to Files" => "Nôl i Ffeiliau",
+"Selected files too large to generate zip file." => "Mae'r ffeiliau ddewiswyd yn rhy fawr i gynhyrchu ffeil zip.",
+"couldn't be determined" => "methwyd pennu",
+"Application is not enabled" => "Nid yw'r pecyn wedi'i alluogi",
+"Authentication error" => "Gwall dilysu",
+"Token expired. Please reload page." => "Tocyn wedi dod i ben. Ail-lwythwch y dudalen.",
+"Files" => "Ffeiliau",
+"Text" => "Testun",
+"Images" => "Delweddau",
+"%s enter the database username." => "%s rhowch enw defnyddiwr y gronfa ddata.",
+"%s enter the database name." => "%s rhowch enw'r gronfa ddata.",
+"%s you may not use dots in the database name" => "%s does dim hawl defnyddio dot yn enw'r gronfa ddata",
+"MS SQL username and/or password not valid: %s" => "Enw a/neu gyfrinair MS SQL annilys: %s",
+"You need to enter either an existing account or the administrator." => "Rhaid i chi naill ai gyflwyno cyfrif presennol neu'r gweinyddwr.",
+"MySQL username and/or password not valid" => "Enw a/neu gyfrinair MySQL annilys",
+"DB Error: \"%s\"" => "Gwall DB: \"%s\"",
+"Offending command was: \"%s\"" => "Y gorchymyn wnaeth beri tramgwydd oedd: \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "Defnyddiwr MySQL '%s'@'localhost' yn bodoli eisoes.",
+"Drop this user from MySQL" => "Gollwng y defnyddiwr hwn o MySQL",
+"MySQL user '%s'@'%%' already exists" => "Defnyddiwr MySQL '%s'@'%%' eisoes yn bodoli",
+"Drop this user from MySQL." => "Gollwng y defnyddiwr hwn o MySQL.",
+"Oracle username and/or password not valid" => "Enw a/neu gyfrinair Oracle annilys",
+"Offending command was: \"%s\", name: %s, password: %s" => "Y gorchymyn wnaeth beri tramgwydd oedd: \"%s\", enw: %s, cyfrinair: %s",
+"PostgreSQL username and/or password not valid" => "Enw a/neu gyfrinair PostgreSQL annilys",
+"Set an admin username." => "Creu enw defnyddiwr i'r gweinyddwr.",
+"Set an admin password." => "Gosod cyfrinair y gweinyddwr.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Nid yw eich gweinydd wedi'i gyflunio eto i ganiatáu cydweddu ffeiliau oherwydd bod y rhyngwyneb WebDAV wedi torri.",
+"Please double check the <a href='%s'>installation guides</a>." => "Gwiriwch y <a href='%s'>canllawiau gosod</a> eto.",
+"seconds ago" => "eiliad yn ôl",
+"1 minute ago" => "1 munud yn ôl",
+"%d minutes ago" => "%d munud yn ôl",
+"1 hour ago" => "1 awr yn ôl",
+"%d hours ago" => "%d awr yn ôl",
+"today" => "heddiw",
+"yesterday" => "ddoe",
+"%d days ago" => "%d diwrnod yn ôl",
+"last month" => "mis diwethaf",
+"%d months ago" => "%d mis yn ôl",
+"last year" => "y llynedd",
+"years ago" => "blwyddyn yn ôl",
+"Could not find category \"%s\"" => "Methu canfod categori \"%s\""
+);
diff --git a/lib/l10n/da.php b/lib/l10n/da.php
index 38ccbbe8e21..5f11453bcdd 100644
--- a/lib/l10n/da.php
+++ b/lib/l10n/da.php
@@ -1,10 +1,11 @@
<?php $TRANSLATIONS = array(
"Help" => "Hjælp",
-"Personal" => "Personlig",
+"Personal" => "Personligt",
"Settings" => "Indstillinger",
"Users" => "Brugere",
"Apps" => "Apps",
"Admin" => "Admin",
+"web services under your control" => "Webtjenester under din kontrol",
"ZIP download is turned off." => "ZIP-download er slået fra.",
"Files need to be downloaded one by one." => "Filer skal downloades en for en.",
"Back to Files" => "Tilbage til Filer",
@@ -16,16 +17,11 @@
"Files" => "Filer",
"Text" => "SMS",
"Images" => "Billeder",
-"Set an admin username." => "Angiv et admin brugernavn.",
-"Set an admin password." => "Angiv et admin kodeord.",
-"Specify a data folder." => "Specificer en data mappe.",
"%s enter the database username." => "%s indtast database brugernavnet.",
"%s enter the database name." => "%s indtast database navnet.",
"%s you may not use dots in the database name" => "%s du må ikke bruge punktummer i databasenavnet.",
-"%s set the database host." => "%s sæt database værten.",
-"PostgreSQL username and/or password not valid" => "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.",
+"MS SQL username and/or password not valid: %s" => "MS SQL brugernavn og/eller adgangskode ikke er gyldigt: %s",
"You need to enter either an existing account or the administrator." => "Du bliver nødt til at indtaste en eksisterende bruger eller en administrator.",
-"Oracle username and/or password not valid" => "Oracle brugernavn og/eller kodeord er ikke gyldigt.",
"MySQL username and/or password not valid" => "MySQL brugernavn og/eller kodeord er ikke gyldigt.",
"DB Error: \"%s\"" => "Databasefejl: \"%s\"",
"Offending command was: \"%s\"" => "Fejlende kommando var: \"%s\"",
@@ -33,8 +29,12 @@
"Drop this user from MySQL" => "Slet denne bruger fra MySQL",
"MySQL user '%s'@'%%' already exists" => "MySQL brugeren '%s'@'%%' eksisterer allerede.",
"Drop this user from MySQL." => "Slet denne bruger fra MySQL",
+"Oracle connection could not be established" => "Oracle forbindelsen kunne ikke etableres",
+"Oracle username and/or password not valid" => "Oracle brugernavn og/eller kodeord er ikke gyldigt.",
"Offending command was: \"%s\", name: %s, password: %s" => "Fejlende kommando var: \"%s\", navn: %s, password: %s",
-"MS SQL username and/or password not valid: %s" => "MS SQL brugernavn og/eller adgangskode ikke er gyldigt: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.",
+"Set an admin username." => "Angiv et admin brugernavn.",
+"Set an admin password." => "Angiv et admin kodeord.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din webserver er endnu ikke sat op til at tillade fil synkronisering fordi WebDAV grænsefladen virker ødelagt.",
"Please double check the <a href='%s'>installation guides</a>." => "Dobbelttjek venligst <a href='%s'>installations vejledningerne</a>.",
"seconds ago" => "sekunder siden",
@@ -42,15 +42,12 @@
"%d minutes ago" => "%d minutter siden",
"1 hour ago" => "1 time siden",
"%d hours ago" => "%d timer siden",
-"today" => "I dag",
-"yesterday" => "I går",
+"today" => "i dag",
+"yesterday" => "i går",
"%d days ago" => "%d dage siden",
-"last month" => "Sidste måned",
+"last month" => "sidste måned",
"%d months ago" => "%d måneder siden",
-"last year" => "Sidste år",
+"last year" => "sidste år",
"years ago" => "år siden",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s er tilgængelig. Få <a href=\"%s\">mere information</a>",
-"up to date" => "opdateret",
-"updates check is disabled" => "Check for opdateringer er deaktiveret",
"Could not find category \"%s\"" => "Kunne ikke finde kategorien \"%s\""
);
diff --git a/lib/l10n/de.php b/lib/l10n/de.php
index 3c2069d4637..4ef02402b9b 100644
--- a/lib/l10n/de.php
+++ b/lib/l10n/de.php
@@ -4,28 +4,24 @@
"Settings" => "Einstellungen",
"Users" => "Benutzer",
"Apps" => "Apps",
-"Admin" => "Administrator",
+"Admin" => "Administration",
+"web services under your control" => "Web-Services unter Deiner Kontrolle",
"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.",
"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.",
"Back to Files" => "Zurück zu \"Dateien\"",
"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.",
"couldn't be determined" => "konnte nicht festgestellt werden",
"Application is not enabled" => "Die Anwendung ist nicht aktiviert",
-"Authentication error" => "Authentifizierungs-Fehler",
+"Authentication error" => "Fehler bei der Anmeldung",
"Token expired. Please reload page." => "Token abgelaufen. Bitte lade die Seite neu.",
"Files" => "Dateien",
"Text" => "Text",
"Images" => "Bilder",
-"Set an admin username." => "Setze Administrator Benutzername.",
-"Set an admin password." => "Setze Administrator Passwort",
-"Specify a data folder." => "Datei-Verzeichnis angeben.",
"%s enter the database username." => "%s gib den Datenbank-Benutzernamen an.",
"%s enter the database name." => "%s gib den Datenbank-Namen an.",
"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten",
-"%s set the database host." => "%s setze den Datenbank-Host",
-"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig",
+"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Password ungültig: %s",
"You need to enter either an existing account or the administrator." => "Du musst entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.",
-"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig",
"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig",
"DB Error: \"%s\"" => "DB Fehler: \"%s\"",
"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"",
@@ -33,12 +29,16 @@
"Drop this user from MySQL" => "Lösche diesen Benutzer von MySQL",
"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits",
"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.",
+"Oracle connection could not be established" => "Es konnte keine Verbindung zur Oracle-Datenbank hergestellt werden",
+"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig",
"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s",
-"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Password ungültig: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig",
+"Set an admin username." => "Setze Administrator Benutzername.",
+"Set an admin password." => "Setze Administrator Passwort",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Dein Web-Server ist noch nicht für Datei-Synchronisation bereit, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
-"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfe die <a href='%s'>Instalationsanleitungen</a>.",
+"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfe die <a href='%s'>Installationsanleitungen</a>.",
"seconds ago" => "Gerade eben",
-"1 minute ago" => "Vor einer Minute",
+"1 minute ago" => "vor einer Minute",
"%d minutes ago" => "Vor %d Minuten",
"1 hour ago" => "Vor einer Stunde",
"%d hours ago" => "Vor %d Stunden",
@@ -49,8 +49,5 @@
"%d months ago" => "Vor %d Monaten",
"last year" => "Letztes Jahr",
"years ago" => "Vor Jahren",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s ist verfügbar. <a href=\"%s\">Weitere Informationen</a>",
-"up to date" => "aktuell",
-"updates check is disabled" => "Die Update-Überprüfung ist ausgeschaltet",
"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden."
);
diff --git a/lib/l10n/de_DE.php b/lib/l10n/de_DE.php
index 9978cdf8b31..823d423abcd 100644
--- a/lib/l10n/de_DE.php
+++ b/lib/l10n/de_DE.php
@@ -5,6 +5,7 @@
"Users" => "Benutzer",
"Apps" => "Apps",
"Admin" => "Administrator",
+"web services under your control" => "Web-Services unter Ihrer Kontrolle",
"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.",
"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.",
"Back to Files" => "Zurück zu \"Dateien\"",
@@ -16,16 +17,11 @@
"Files" => "Dateien",
"Text" => "Text",
"Images" => "Bilder",
-"Set an admin username." => "Setze Administrator Benutzername.",
-"Set an admin password." => "Setze Administrator Passwort",
-"Specify a data folder." => "Datei-Verzeichnis angeben",
"%s enter the database username." => "%s geben Sie den Datenbank-Benutzernamen an.",
"%s enter the database name." => "%s geben Sie den Datenbank-Namen an.",
"%s you may not use dots in the database name" => "%s Der Datenbank-Name darf keine Punkte enthalten",
-"%s set the database host." => "%s setze den Datenbank-Host",
-"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig",
+"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Passwort ungültig: %s",
"You need to enter either an existing account or the administrator." => "Sie müssen entweder ein existierendes Benutzerkonto oder das Administratoren-Konto angeben.",
-"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig",
"MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig",
"DB Error: \"%s\"" => "DB Fehler: \"%s\"",
"Offending command was: \"%s\"" => "Fehlerhafter Befehl war: \"%s\"",
@@ -33,12 +29,16 @@
"Drop this user from MySQL" => "Lösche diesen Benutzer aus MySQL",
"MySQL user '%s'@'%%' already exists" => "MySQL Benutzer '%s'@'%%' existiert bereits",
"Drop this user from MySQL." => "Lösche diesen Benutzer aus MySQL.",
+"Oracle connection could not be established" => "Die Oracle-Verbindung konnte nicht aufgebaut werden.",
+"Oracle username and/or password not valid" => "Oracle Benutzername und/oder Passwort ungültig",
"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s",
-"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Passwort ungültig: %s",
-"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ihr Web-Server ist noch nicht für Datei-Synchronisation bereit, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
-"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfen Sie die <a href='%s'>Instalationsanleitungen</a>.",
+"PostgreSQL username and/or password not valid" => "PostgreSQL Benutzername und/oder Passwort ungültig",
+"Set an admin username." => "Setze Administrator Benutzername.",
+"Set an admin password." => "Setze Administrator Passwort",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ihr Web-Server ist noch nicht für eine Datei-Synchronisation konfiguriert, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
+"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfen Sie die <a href='%s'>Installationsanleitungen</a>.",
"seconds ago" => "Gerade eben",
-"1 minute ago" => "Vor einer Minute",
+"1 minute ago" => "Vor 1 Minute",
"%d minutes ago" => "Vor %d Minuten",
"1 hour ago" => "Vor einer Stunde",
"%d hours ago" => "Vor %d Stunden",
@@ -49,8 +49,5 @@
"%d months ago" => "Vor %d Monaten",
"last year" => "Letztes Jahr",
"years ago" => "Vor Jahren",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s ist verfügbar. <a href=\"%s\">Weitere Informationen</a>",
-"up to date" => "aktuell",
-"updates check is disabled" => "Die Update-Überprüfung ist ausgeschaltet",
"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden."
);
diff --git a/lib/l10n/el.php b/lib/l10n/el.php
index c17a33dfee1..3e876aefdfe 100644
--- a/lib/l10n/el.php
+++ b/lib/l10n/el.php
@@ -5,6 +5,7 @@
"Users" => "Χρήστες",
"Apps" => "Εφαρμογές",
"Admin" => "Διαχειριστής",
+"web services under your control" => "υπηρεσίες δικτύου υπό τον έλεγχό σας",
"ZIP download is turned off." => "Η λήψη ZIP απενεργοποιήθηκε.",
"Files need to be downloaded one by one." => "Τα αρχεία πρέπει να ληφθούν ένα-ένα.",
"Back to Files" => "Πίσω στα Αρχεία",
@@ -16,21 +17,24 @@
"Files" => "Αρχεία",
"Text" => "Κείμενο",
"Images" => "Εικόνες",
-"Set an admin username." => "Εισάγετε όνομα χρήστη διαχειριστή.",
-"Set an admin password." => "Εισάγετε συνθηματικό διαχειριστή.",
-"Specify a data folder." => "Καθορίστε τον φάκελο δεδομένων.",
"%s enter the database username." => "%s εισάγετε το όνομα χρήστη της βάσης δεδομένων.",
"%s enter the database name." => "%s εισάγετε το όνομα της βάσης δεδομένων.",
"%s you may not use dots in the database name" => "%s μάλλον δεν χρησιμοποιείτε τελείες στο όνομα της βάσης δεδομένων",
-"PostgreSQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της PostgreSQL",
+"MS SQL username and/or password not valid: %s" => "Το όνομα χρήστη και/ή ο κωδικός της MS SQL δεν είναι έγκυρα: %s",
"You need to enter either an existing account or the administrator." => "Χρειάζεται να εισάγετε είτε έναν υπάρχον λογαριασμό ή του διαχειριστή.",
-"Oracle username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle",
"MySQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της MySQL",
"DB Error: \"%s\"" => "Σφάλμα Βάσης Δεδομένων: \"%s\"",
+"Offending command was: \"%s\"" => "Η εντολη παραβατικοτητας ηταν: \"%s\"",
"MySQL user '%s'@'localhost' exists already." => "Υπάρχει ήδη ο χρήστης '%s'@'localhost' της MySQL.",
"Drop this user from MySQL" => "Απόρριψη αυτού του χρήστη από την MySQL",
"MySQL user '%s'@'%%' already exists" => "Ο χρήστης '%s'@'%%' της MySQL υπάρχει ήδη",
"Drop this user from MySQL." => "Απόρριψη αυτού του χρήστη από την MySQL",
+"Oracle connection could not be established" => "Αδυναμία σύνδεσης Oracle",
+"Oracle username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle",
+"Offending command was: \"%s\", name: %s, password: %s" => "Η εντολη παραβατικοτητας ηταν: \"%s\", ονομα: %s, κωδικος: %s",
+"PostgreSQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της PostgreSQL",
+"Set an admin username." => "Εισάγετε όνομα χρήστη διαχειριστή.",
+"Set an admin password." => "Εισάγετε συνθηματικό διαχειριστή.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ο διακομιστής σας δεν έχει ρυθμιστεί κατάλληλα ώστε να επιτρέπει τον συγχρονισμό αρχείων γιατί η διεπαφή WebDAV πιθανόν να είναι κατεστραμμένη.",
"Please double check the <a href='%s'>installation guides</a>." => "Ελέγξτε ξανά τις <a href='%s'>οδηγίες εγκατάστασης</a>.",
"seconds ago" => "δευτερόλεπτα πριν",
@@ -39,14 +43,11 @@
"1 hour ago" => "1 ώρα πριν",
"%d hours ago" => "%d ώρες πριν",
"today" => "σήμερα",
-"yesterday" => "χθές",
+"yesterday" => "χτες",
"%d days ago" => "%d ημέρες πριν",
-"last month" => "τον προηγούμενο μήνα",
+"last month" => "τελευταίο μήνα",
"%d months ago" => "%d μήνες πριν",
-"last year" => "τον προηγούμενο χρόνο",
+"last year" => "τελευταίο χρόνο",
"years ago" => "χρόνια πριν",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s είναι διαθέσιμο. Δείτε <a href=\"%s\">περισσότερες πληροφορίες</a>",
-"up to date" => "ενημερωμένο",
-"updates check is disabled" => "ο έλεγχος ενημερώσεων είναι απενεργοποιημένος",
"Could not find category \"%s\"" => "Αδυναμία εύρεσης κατηγορίας \"%s\""
);
diff --git a/lib/l10n/en@pirate.php b/lib/l10n/en@pirate.php
new file mode 100644
index 00000000000..02ff0331e05
--- /dev/null
+++ b/lib/l10n/en@pirate.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"web services under your control" => "web services under your control"
+);
diff --git a/lib/l10n/eo.php b/lib/l10n/eo.php
index dac11ffe7e6..fd45f30c69b 100644
--- a/lib/l10n/eo.php
+++ b/lib/l10n/eo.php
@@ -5,6 +5,7 @@
"Users" => "Uzantoj",
"Apps" => "Aplikaĵoj",
"Admin" => "Administranto",
+"web services under your control" => "TTT-servoj regataj de vi",
"ZIP download is turned off." => "ZIP-elŝuto estas malkapabligita.",
"Files need to be downloaded one by one." => "Dosieroj devas elŝutiĝi unuope.",
"Back to Files" => "Reen al la dosieroj",
@@ -15,7 +16,24 @@
"Files" => "Dosieroj",
"Text" => "Teksto",
"Images" => "Bildoj",
-"seconds ago" => "sekundojn antaŭe",
+"%s enter the database username." => "%s enigu la uzantonomon de la datumbazo.",
+"%s enter the database name." => "%s enigu la nomon de la datumbazo.",
+"%s you may not use dots in the database name" => "%s vi ne povas uzi punktojn en la nomo de la datumbazo",
+"MS SQL username and/or password not valid: %s" => "La uzantonomo de MS SQL aŭ la pasvorto ne validas: %s",
+"MySQL username and/or password not valid" => "La uzantonomo de MySQL aŭ la pasvorto ne validas",
+"DB Error: \"%s\"" => "Datumbaza eraro: “%s”",
+"MySQL user '%s'@'localhost' exists already." => "La uzanto de MySQL “%s”@“localhost” jam ekzistas.",
+"Drop this user from MySQL" => "Forigi ĉi tiun uzanton el MySQL",
+"MySQL user '%s'@'%%' already exists" => "La uzanto de MySQL “%s”@“%%” jam ekzistas",
+"Drop this user from MySQL." => "Forigi ĉi tiun uzanton el MySQL.",
+"Oracle connection could not be established" => "Konekto al Oracle ne povas stariĝi",
+"Oracle username and/or password not valid" => "La uzantonomo de Oracle aŭ la pasvorto ne validas",
+"PostgreSQL username and/or password not valid" => "La uzantonomo de PostgreSQL aŭ la pasvorto ne validas",
+"Set an admin username." => "Starigi administran uzantonomon.",
+"Set an admin password." => "Starigi administran pasvorton.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Via TTT-servilo ankoraŭ ne ĝuste agordiĝis por permesi sinkronigi dosierojn ĉar la WebDAV-interfaco ŝajnas rompita.",
+"Please double check the <a href='%s'>installation guides</a>." => "Bonvolu duoble kontroli la <a href='%s'>gvidilon por instalo</a>.",
+"seconds ago" => "sekundoj antaŭe",
"1 minute ago" => "antaŭ 1 minuto",
"%d minutes ago" => "antaŭ %d minutoj",
"1 hour ago" => "antaŭ 1 horo",
@@ -23,12 +41,9 @@
"today" => "hodiaŭ",
"yesterday" => "hieraŭ",
"%d days ago" => "antaŭ %d tagoj",
-"last month" => "lasta monato",
+"last month" => "lastamonate",
"%d months ago" => "antaŭ %d monatoj",
-"last year" => "lasta jaro",
-"years ago" => "jarojn antaŭe",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s haveblas. Ekhavu <a href=\"%s\">pli da informo</a>",
-"up to date" => "ĝisdata",
-"updates check is disabled" => "ĝisdateckontrolo estas malkapabligita",
+"last year" => "lastajare",
+"years ago" => "jaroj antaŭe",
"Could not find category \"%s\"" => "Ne troviĝis kategorio “%s”"
);
diff --git a/lib/l10n/es.php b/lib/l10n/es.php
index 37b15a375c4..1f243a224e4 100644
--- a/lib/l10n/es.php
+++ b/lib/l10n/es.php
@@ -5,6 +5,7 @@
"Users" => "Usuarios",
"Apps" => "Aplicaciones",
"Admin" => "Administración",
+"web services under your control" => "Servicios web bajo su control",
"ZIP download is turned off." => "La descarga en ZIP está desactivada.",
"Files need to be downloaded one by one." => "Los archivos deben ser descargados uno por uno.",
"Back to Files" => "Volver a Archivos",
@@ -16,16 +17,11 @@
"Files" => "Archivos",
"Text" => "Texto",
"Images" => "Imágenes",
-"Set an admin username." => "Configurar un nombre de usuario del administrador",
-"Set an admin password." => "Configurar la contraseña del administrador.",
-"Specify a data folder." => "Especificar la carpeta de datos.",
"%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 set the database host." => "%s ingresar el host de la base de datos.",
-"PostgreSQL username and/or password not valid" => "Usuario y/o contraseña de PostgreSQL no válidos",
+"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.",
-"Oracle username and/or password not valid" => "Usuario y/o contraseña de Oracle no válidos",
"MySQL username and/or password not valid" => "Usuario y/o contraseña de MySQL no válidos",
"DB Error: \"%s\"" => "Error BD: \"%s\"",
"Offending command was: \"%s\"" => "Comando infractor: \"%s\"",
@@ -33,8 +29,12 @@
"Drop this user from MySQL" => "Eliminar este usuario de MySQL",
"MySQL user '%s'@'%%' already exists" => "Usuario MySQL '%s'@'%%' ya existe",
"Drop this user from MySQL." => "Eliminar este usuario de MySQL.",
+"Oracle connection could not be established" => "No se pudo establecer la conexión a Oracle",
+"Oracle username and/or password not valid" => "Usuario y/o contraseña de Oracle no válidos",
"Offending command was: \"%s\", name: %s, password: %s" => "Comando infractor: \"%s\", nombre: %s, contraseña: %s",
-"MS SQL username and/or password not valid: %s" => "Usuario y/o contraseña de MS SQL no válidos: %s",
+"PostgreSQL username and/or password not valid" => "Usuario y/o contraseña de PostgreSQL no válidos",
+"Set an admin username." => "Configurar un nombre de usuario del administrador",
+"Set an admin password." => "Configurar la contraseña del administrador.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Su servidor web aún no está configurado adecuadamente para permitir sincronización de archivos ya que la interfaz WebDAV parece no estar funcionando.",
"Please double check the <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",
@@ -45,12 +45,9 @@
"today" => "hoy",
"yesterday" => "ayer",
"%d days ago" => "hace %d días",
-"last month" => "este mes",
+"last month" => "mes pasado",
"%d months ago" => "Hace %d meses",
-"last year" => "este año",
+"last year" => "año pasado",
"years ago" => "hace años",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponible. Obtén <a href=\"%s\">más información</a>",
-"up to date" => "actualizado",
-"updates check is disabled" => "comprobar actualizaciones está desactivado",
"Could not find category \"%s\"" => "No puede encontrar la categoria \"%s\""
);
diff --git a/lib/l10n/es_AR.php b/lib/l10n/es_AR.php
index ff3d47285fc..e66771f7e74 100644
--- a/lib/l10n/es_AR.php
+++ b/lib/l10n/es_AR.php
@@ -1,31 +1,27 @@
<?php $TRANSLATIONS = array(
"Help" => "Ayuda",
"Personal" => "Personal",
-"Settings" => "Ajustes",
+"Settings" => "Configuración",
"Users" => "Usuarios",
"Apps" => "Aplicaciones",
"Admin" => "Administración",
+"web services under your control" => "servicios web que controlás",
"ZIP download is turned off." => "La descarga en ZIP está desactivada.",
"Files need to be downloaded one by one." => "Los archivos deben ser descargados de a uno.",
"Back to Files" => "Volver a archivos",
"Selected files too large to generate zip file." => "Los archivos seleccionados son demasiado grandes para generar el archivo zip.",
"couldn't be determined" => "no pudo ser determinado",
"Application is not enabled" => "La aplicación no está habilitada",
-"Authentication error" => "Error de autenticación",
+"Authentication error" => "Error al autenticar",
"Token expired. Please reload page." => "Token expirado. Por favor, recargá la página.",
"Files" => "Archivos",
"Text" => "Texto",
"Images" => "Imágenes",
-"Set an admin username." => "Configurar un nombre de administrador",
-"Set an admin password." => "Configurar una palabra clave de administrador",
-"Specify a data folder." => "Especificar un directorio de datos",
"%s enter the database username." => "%s Entre el Usuario de la Base de Datos",
"%s enter the database name." => "%s Entre el Nombre de la Base de Datos",
"%s you may not use dots in the database name" => "%s no puede usar puntos en el nombre de la Base de Datos",
-"%s set the database host." => "%s Especifique la dirección de la Base de Datos",
-"PostgreSQL username and/or password not valid" => "Nombre de usuario o contraseña de PostgradeSQL no válido.",
+"MS SQL username and/or password not valid: %s" => "Nombre de usuario y contraseña de MS SQL no son válidas: %s",
"You need to enter either an existing account or the administrator." => "Debe ingresar una cuenta existente o el administrador",
-"Oracle username and/or password not valid" => "El nombre de usuario y contraseña no son válidos",
"MySQL username and/or password not valid" => "Usuario y/o contraseña MySQL no válido",
"DB Error: \"%s\"" => "Error DB: \"%s\"",
"Offending command was: \"%s\"" => "El comando no comprendido es: \"%s\"",
@@ -33,11 +29,15 @@
"Drop this user from MySQL" => "Borrar este usuario de MySQL",
"MySQL user '%s'@'%%' already exists" => "Usuario MySQL '%s'@'%%' ya existente",
"Drop this user from MySQL." => "Borrar este usuario de MySQL",
+"Oracle connection could not be established" => "No fue posible establecer la conexión a Oracle",
+"Oracle username and/or password not valid" => "El nombre de usuario y contraseña no son válidos",
"Offending command was: \"%s\", name: %s, password: %s" => "El comando no comprendido es: \"%s\", nombre: \"%s\", contraseña: \"%s\"",
-"MS SQL username and/or password not valid: %s" => "Nombre de usuario y contraseña de MS SQL no son válidas: %s",
+"PostgreSQL username and/or password not valid" => "Nombre de usuario o contraseña de PostgradeSQL no válido.",
+"Set an admin username." => "Configurar un nombre de administrador",
+"Set an admin password." => "Configurar una palabra clave de administrador",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Tu servidor web no está configurado todavía para permitir sincronización de archivos porque la interfaz WebDAV parece no funcionar.",
"Please double check the <a href='%s'>installation guides</a>." => "Por favor, comprobá nuevamente la <a href='%s'>guía de instalación</a>.",
-"seconds ago" => "hace unos segundos",
+"seconds ago" => "segundos atrás",
"1 minute ago" => "hace 1 minuto",
"%d minutes ago" => "hace %d minutos",
"1 hour ago" => "1 hora atrás",
@@ -45,12 +45,9 @@
"today" => "hoy",
"yesterday" => "ayer",
"%d days ago" => "hace %d días",
-"last month" => "este mes",
+"last month" => "el mes pasado",
"%d months ago" => "%d meses atrás",
-"last year" => "este año",
-"years ago" => "hace años",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponible. Conseguí <a href=\"%s\">más información</a>",
-"up to date" => "actualizado",
-"updates check is disabled" => "comprobar actualizaciones está desactivado",
+"last year" => "el año pasado",
+"years ago" => "años atrás",
"Could not find category \"%s\"" => "No fue posible encontrar la categoría \"%s\""
);
diff --git a/lib/l10n/et_EE.php b/lib/l10n/et_EE.php
index cdcf762d9a6..4da2c36d6ac 100644
--- a/lib/l10n/et_EE.php
+++ b/lib/l10n/et_EE.php
@@ -5,22 +5,38 @@
"Users" => "Kasutajad",
"Apps" => "Rakendused",
"Admin" => "Admin",
+"web services under your control" => "veebitenused sinu kontrolli all",
"ZIP download is turned off." => "ZIP-ina allalaadimine on välja lülitatud.",
"Files need to be downloaded one by one." => "Failid tuleb alla laadida ükshaaval.",
"Back to Files" => "Tagasi failide juurde",
"Selected files too large to generate zip file." => "Valitud failid on ZIP-faili loomiseks liiga suured.",
+"couldn't be determined" => "ei suudetud tuvastada",
"Application is not enabled" => "Rakendus pole sisse lülitatud",
"Authentication error" => "Autentimise viga",
"Token expired. Please reload page." => "Kontrollkood aegus. Paelun lae leht uuesti.",
"Files" => "Failid",
"Text" => "Tekst",
"Images" => "Pildid",
-"Set an admin username." => "Määra admin kasutajanimi.",
-"Set an admin password." => "Määra admini parool.",
-"Specify a data folder." => "Määra andmete kaust.",
+"%s enter the database username." => "%s sisesta andmebaasi kasutajatunnus.",
+"%s enter the database name." => "%s sisesta andmebaasi nimi.",
+"%s you may not use dots in the database name" => "%s punktide kasutamine andmebaasi nimes pole lubatud",
+"MS SQL username and/or password not valid: %s" => "MS SQL kasutajatunnus ja/või parool pole õiged: %s",
+"You need to enter either an existing account or the administrator." => "Sisesta kas juba olemasolev konto või administrator.",
+"MySQL username and/or password not valid" => "MySQL kasutajatunnus ja/või parool pole õiged",
"DB Error: \"%s\"" => "Andmebaasi viga: \"%s\"",
+"Offending command was: \"%s\"" => "Tõrkuv käsk oli: \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "MySQL kasutaja '%s'@'localhost' on juba olemas.",
"Drop this user from MySQL" => "Kustuta see kasutaja MySQL-ist",
+"MySQL user '%s'@'%%' already exists" => "MySQL kasutaja '%s'@'%%' on juba olemas",
"Drop this user from MySQL." => "Kustuta see kasutaja MySQL-ist.",
+"Oracle connection could not be established" => "Ei suuda luua ühendust Oracle baasiga",
+"Oracle username and/or password not valid" => "Oracle kasutajatunnus ja/või parool pole õiged",
+"Offending command was: \"%s\", name: %s, password: %s" => "Tõrkuv käsk oli: \"%s\", nimi: %s, parool: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL kasutajatunnus ja/või parool pole õiged",
+"Set an admin username." => "Määra admin kasutajanimi.",
+"Set an admin password." => "Määra admini parool.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Veebiserveri ei ole veel korralikult seadistatud võimaldamaks failide sünkroniseerimist, kuna WebDAV liides näib olevat mittetoimiv.",
+"Please double check the <a href='%s'>installation guides</a>." => "Palun tutvu veelkord <a href='%s'>paigalduse juhenditega</a>.",
"seconds ago" => "sekundit tagasi",
"1 minute ago" => "1 minut tagasi",
"%d minutes ago" => "%d minutit tagasi",
@@ -29,11 +45,9 @@
"today" => "täna",
"yesterday" => "eile",
"%d days ago" => "%d päeva tagasi",
-"last month" => "eelmisel kuul",
+"last month" => "viimasel kuul",
"%d months ago" => "%d kuud tagasi",
-"last year" => "eelmisel aastal",
+"last year" => "viimasel aastal",
"years ago" => "aastat tagasi",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s on saadaval. Vaata <a href=\"%s\">lisainfot</a>",
-"up to date" => "ajakohane",
-"updates check is disabled" => "uuenduste kontrollimine on välja lülitatud"
+"Could not find category \"%s\"" => "Ei leia kategooriat \"%s\""
);
diff --git a/lib/l10n/eu.php b/lib/l10n/eu.php
index 36eb397e425..028ad0a631e 100644
--- a/lib/l10n/eu.php
+++ b/lib/l10n/eu.php
@@ -5,27 +5,23 @@
"Users" => "Erabiltzaileak",
"Apps" => "Aplikazioak",
"Admin" => "Admin",
+"web services under your control" => "web zerbitzuak zure kontrolpean",
"ZIP download is turned off." => "ZIP deskarga ez dago gaituta.",
"Files need to be downloaded one by one." => "Fitxategiak banan-banan deskargatu behar dira.",
"Back to Files" => "Itzuli fitxategietara",
"Selected files too large to generate zip file." => "Hautatuko fitxategiak oso handiak dira zip fitxategia sortzeko.",
"couldn't be determined" => "ezin izan da zehaztu",
"Application is not enabled" => "Aplikazioa ez dago gaituta",
-"Authentication error" => "Autentikazio errorea",
+"Authentication error" => "Autentifikazio errorea",
"Token expired. Please reload page." => "Tokena iraungitu da. Mesedez birkargatu orria.",
"Files" => "Fitxategiak",
"Text" => "Testua",
"Images" => "Irudiak",
-"Set an admin username." => "Ezarri administraziorako erabiltzaile izena.",
-"Set an admin password." => "Ezarri administraziorako pasahitza.",
-"Specify a data folder." => "Zehaztu data karpeta.",
"%s enter the database username." => "%s sartu datu basearen erabiltzaile izena.",
"%s enter the database name." => "%s sartu datu basearen izena.",
"%s you may not use dots in the database name" => "%s ezin duzu punturik erabili datu basearen izenean.",
-"%s set the database host." => "%s sartu datu basearen hostalaria.",
-"PostgreSQL username and/or password not valid" => "PostgreSQL erabiltzaile edota pasahitza ez dira egokiak.",
+"MS SQL username and/or password not valid: %s" => "MS SQL erabiltzaile izena edota pasahitza ez dira egokiak: %s",
"You need to enter either an existing account or the administrator." => "Existitzen den kontu bat edo administradorearena jarri behar duzu.",
-"Oracle username and/or password not valid" => "Oracle erabiltzaile edota pasahitza ez dira egokiak.",
"MySQL username and/or password not valid" => "MySQL erabiltzaile edota pasahitza ez dira egokiak.",
"DB Error: \"%s\"" => "DB errorea: \"%s\"",
"Offending command was: \"%s\"" => "Errorea komando honek sortu du: \"%s\"",
@@ -33,11 +29,14 @@
"Drop this user from MySQL" => "Ezabatu erabiltzaile hau MySQLtik",
"MySQL user '%s'@'%%' already exists" => "MySQL '%s'@'%%' erabiltzailea dagoeneko existitzen da",
"Drop this user from MySQL." => "Ezabatu erabiltzaile hau MySQLtik.",
+"Oracle username and/or password not valid" => "Oracle erabiltzaile edota pasahitza ez dira egokiak.",
"Offending command was: \"%s\", name: %s, password: %s" => "Errorea komando honek sortu du: \"%s\", izena: %s, pasahitza: %s",
-"MS SQL username and/or password not valid: %s" => "MS SQL erabiltzaile izena edota pasahitza ez dira egokiak: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL erabiltzaile edota pasahitza ez dira egokiak.",
+"Set an admin username." => "Ezarri administraziorako erabiltzaile izena.",
+"Set an admin password." => "Ezarri administraziorako pasahitza.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Zure web zerbitzaria ez dago oraindik ongi konfiguratuta fitxategien sinkronizazioa egiteko, WebDAV interfazea ongi ez dagoela dirudi.",
"Please double check the <a href='%s'>installation guides</a>." => "Mesedez begiratu <a href='%s'>instalazio gidak</a>.",
-"seconds ago" => "orain dela segundu batzuk",
+"seconds ago" => "segundu",
"1 minute ago" => "orain dela minutu 1",
"%d minutes ago" => "orain dela %d minutu",
"1 hour ago" => "orain dela ordu bat",
@@ -45,12 +44,9 @@
"today" => "gaur",
"yesterday" => "atzo",
"%d days ago" => "orain dela %d egun",
-"last month" => "joan den hilabetea",
+"last month" => "joan den hilabetean",
"%d months ago" => "orain dela %d hilabete",
-"last year" => "joan den urtea",
-"years ago" => "orain dela urte batzuk",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s eskuragarri dago. Lortu <a href=\"%s\">informazio gehiago</a>",
-"up to date" => "eguneratuta",
-"updates check is disabled" => "eguneraketen egiaztapena ez dago gaituta",
+"last year" => "joan den urtean",
+"years ago" => "urte",
"Could not find category \"%s\"" => "Ezin da \"%s\" kategoria aurkitu"
);
diff --git a/lib/l10n/fa.php b/lib/l10n/fa.php
index 282a8a56cdc..40a778e2126 100644
--- a/lib/l10n/fa.php
+++ b/lib/l10n/fa.php
@@ -5,16 +5,38 @@
"Users" => "کاربران",
"Apps" => " برنامه ها",
"Admin" => "مدیر",
+"web services under your control" => "سرویس های تحت وب در کنترل شما",
"ZIP download is turned off." => "دانلود به صورت فشرده غیر فعال است",
"Files need to be downloaded one by one." => "فایل ها باید به صورت یکی یکی دانلود شوند",
"Back to Files" => "بازگشت به فایل ها",
"Selected files too large to generate zip file." => "فایل های انتخاب شده بزرگتر از آن هستند که بتوان یک فایل فشرده تولید کرد",
+"couldn't be determined" => "نمیتواند مشخص شود",
"Application is not enabled" => "برنامه فعال نشده است",
"Authentication error" => "خطا در اعتبار سنجی",
+"Token expired. Please reload page." => "رمز منقضی شده است. لطفا دوباره صفحه را بارگذاری نمایید.",
"Files" => "پرونده‌ها",
"Text" => "متن",
"Images" => "تصاویر",
-"Specify a data folder." => "پوشه ای برای داده ها مشخص کنید.",
+"%s enter the database username." => "%s نام کاربری پایگاه داده را وارد نمایید.",
+"%s enter the database name." => "%s نام پایگاه داده را وارد نمایید.",
+"%s you may not use dots in the database name" => "%s شما نباید از نقطه در نام پایگاه داده استفاده نمایید.",
+"MS SQL username and/or password not valid: %s" => "نام کاربری و / یا رمزعبور MS SQL معتبر نیست: %s",
+"You need to enter either an existing account or the administrator." => "شما نیاز به وارد کردن یک حساب کاربری موجود یا حساب مدیریتی دارید.",
+"MySQL username and/or password not valid" => "نام کاربری و / یا رمزعبور MySQL معتبر نیست.",
+"DB Error: \"%s\"" => "خطای پایگاه داده: \"%s\"",
+"Offending command was: \"%s\"" => "دستور متخلف عبارت است از: \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "کاربرMySQL '%s'@'localhost' درحال حاضر موجود است.",
+"Drop this user from MySQL" => "این کاربر را از MySQL حذف نمایید.",
+"MySQL user '%s'@'%%' already exists" => "کاربر'%s'@'%%' MySQL در حال حاضر موجود است.",
+"Drop this user from MySQL." => "این کاربر را از MySQL حذف نمایید.",
+"Oracle connection could not be established" => "ارتباط اراکل نمیتواند برقرار باشد.",
+"Oracle username and/or password not valid" => "نام کاربری و / یا رمزعبور اراکل معتبر نیست.",
+"Offending command was: \"%s\", name: %s, password: %s" => "دستور متخلف عبارت است از: \"%s\"، نام: \"%s\"، رمزعبور:\"%s\"",
+"PostgreSQL username and/or password not valid" => "PostgreSQL نام کاربری و / یا رمزعبور معتبر نیست.",
+"Set an admin username." => "یک نام کاربری برای مدیر تنظیم نمایید.",
+"Set an admin password." => "یک رمزعبور برای مدیر تنظیم نمایید.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "احتمالاً وب سرور شما طوری تنظیم نشده است که اجازه ی همگام سازی فایلها را بدهد زیرا به نظر میرسد رابط WebDAV از کار افتاده است.",
+"Please double check the <a href='%s'>installation guides</a>." => "لطفاً دوباره <a href='%s'>راهنمای نصب</a>را بررسی کنید.",
"seconds ago" => "ثانیه‌ها پیش",
"1 minute ago" => "1 دقیقه پیش",
"%d minutes ago" => "%d دقیقه پیش",
diff --git a/lib/l10n/fi.php b/lib/l10n/fi.php
new file mode 100644
index 00000000000..daaddb25e48
--- /dev/null
+++ b/lib/l10n/fi.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"Settings" => "asetukset"
+);
diff --git a/lib/l10n/fi_FI.php b/lib/l10n/fi_FI.php
index 89a584d389d..75576c3034d 100644
--- a/lib/l10n/fi_FI.php
+++ b/lib/l10n/fi_FI.php
@@ -5,30 +5,33 @@
"Users" => "Käyttäjät",
"Apps" => "Sovellukset",
"Admin" => "Ylläpitäjä",
+"web services under your control" => "verkkopalvelut hallinnassasi",
"ZIP download is turned off." => "ZIP-lataus on poistettu käytöstä.",
"Files need to be downloaded one by one." => "Tiedostot on ladattava yksittäin.",
"Back to Files" => "Takaisin tiedostoihin",
"Selected files too large to generate zip file." => "Valitut tiedostot ovat liian suurikokoisia mahtuakseen zip-tiedostoon.",
"couldn't be determined" => "ei voitu määrittää",
"Application is not enabled" => "Sovellusta ei ole otettu käyttöön",
-"Authentication error" => "Todennusvirhe",
+"Authentication error" => "Tunnistautumisvirhe",
"Token expired. Please reload page." => "Valtuutus vanheni. Lataa sivu uudelleen.",
"Files" => "Tiedostot",
"Text" => "Teksti",
"Images" => "Kuvat",
-"Set an admin username." => "Aseta ylläpitäjän käyttäjätunnus.",
-"Set an admin password." => "Aseta ylläpitäjän salasana.",
-"Specify a data folder." => "Määritä datakansio.",
"%s enter the database username." => "%s anna tietokannan käyttäjätunnus.",
"%s enter the database name." => "%s anna tietokannan nimi.",
"%s you may not use dots in the database name" => "%s et voi käyttää pisteitä tietokannan nimessä",
-"PostgreSQL username and/or password not valid" => "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin",
-"Oracle username and/or password not valid" => "Oraclen käyttäjätunnus ja/tai salasana on väärin",
+"MS SQL username and/or password not valid: %s" => "MS SQL -käyttäjätunnus ja/tai -salasana on väärin: %s",
"MySQL username and/or password not valid" => "MySQL:n käyttäjätunnus ja/tai salasana on väärin",
"DB Error: \"%s\"" => "Tietokantavirhe: \"%s\"",
"MySQL user '%s'@'localhost' exists already." => "MySQL-käyttäjä '%s'@'localhost' on jo olemassa.",
+"Drop this user from MySQL" => "Pudota tämä käyttäjä MySQL:stä",
"MySQL user '%s'@'%%' already exists" => "MySQL-käyttäjä '%s'@'%%' on jo olemassa",
-"MS SQL username and/or password not valid: %s" => "MS SQL -käyttäjätunnus ja/tai -salasana on väärin: %s",
+"Drop this user from MySQL." => "Pudota tämä käyttäjä MySQL:stä.",
+"Oracle connection could not be established" => "Oracle-yhteyttä ei voitu muodostaa",
+"Oracle username and/or password not valid" => "Oraclen käyttäjätunnus ja/tai salasana on väärin",
+"PostgreSQL username and/or password not valid" => "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin",
+"Set an admin username." => "Aseta ylläpitäjän käyttäjätunnus.",
+"Set an admin password." => "Aseta ylläpitäjän salasana.",
"Please double check the <a href='%s'>installation guides</a>." => "Lue tarkasti <a href='%s'>asennusohjeet</a>.",
"seconds ago" => "sekuntia sitten",
"1 minute ago" => "1 minuutti sitten",
@@ -42,8 +45,5 @@
"%d months ago" => "%d kuukautta sitten",
"last year" => "viime vuonna",
"years ago" => "vuotta sitten",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s on saatavilla. Lue <a href=\"%s\">lisätietoja</a>",
-"up to date" => "ajan tasalla",
-"updates check is disabled" => "päivitysten tarkistus on pois käytöstä",
"Could not find category \"%s\"" => "Luokkaa \"%s\" ei löytynyt"
);
diff --git a/lib/l10n/fr.php b/lib/l10n/fr.php
index 9448502df6a..9f30b602696 100644
--- a/lib/l10n/fr.php
+++ b/lib/l10n/fr.php
@@ -5,6 +5,7 @@
"Users" => "Utilisateurs",
"Apps" => "Applications",
"Admin" => "Administration",
+"web services under your control" => "services web sous votre contrôle",
"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",
@@ -16,16 +17,11 @@
"Files" => "Fichiers",
"Text" => "Texte",
"Images" => "Images",
-"Set an admin username." => "Spécifiez un nom d'utilisateur pour l'administrateur.",
-"Set an admin password." => "Spécifiez un mot de passe administrateur.",
-"Specify a data folder." => "Spécifiez un répertoire pour les données.",
"%s enter the database username." => "%s entrez le nom d'utilisateur de la base de données.",
"%s enter the database name." => "%s entrez le nom de la base de données.",
"%s you may not use dots in the database name" => "%s vous nez pouvez pas utiliser de points dans le nom de la base de données",
-"%s set the database host." => "%s spécifiez l'hôte de la base de données.",
-"PostgreSQL username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL invalide",
+"MS SQL username and/or password not valid: %s" => "Le nom d'utilisateur et/ou le mot de passe de la base MS SQL est invalide : %s",
"You need to enter either an existing account or the administrator." => "Vous devez spécifier soit le nom d'un compte existant, soit celui de l'administrateur.",
-"Oracle username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base Oracle invalide",
"MySQL username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base MySQL invalide",
"DB Error: \"%s\"" => "Erreur de la base de données : \"%s\"",
"Offending command was: \"%s\"" => "La requête en cause est : \"%s\"",
@@ -33,12 +29,16 @@
"Drop this user from MySQL" => "Retirer cet utilisateur de la base MySQL",
"MySQL user '%s'@'%%' already exists" => "L'utilisateur MySQL '%s'@'%%' existe déjà",
"Drop this user from MySQL." => "Retirer cet utilisateur de la base MySQL.",
+"Oracle connection could not be established" => "La connexion Oracle ne peut pas être établie",
+"Oracle username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base Oracle invalide",
"Offending command was: \"%s\", name: %s, password: %s" => "La requête en cause est : \"%s\", nom : %s, mot de passe : %s",
-"MS SQL username and/or password not valid: %s" => "Le nom d'utilisateur et/ou le mot de passe de la base MS SQL est invalide : %s",
+"PostgreSQL username and/or password not valid" => "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL invalide",
+"Set an admin username." => "Spécifiez un nom d'utilisateur pour l'administrateur.",
+"Set an admin password." => "Spécifiez un mot de passe administrateur.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Votre serveur web, n'est pas correctement configuré pour permettre la synchronisation des fichiers, car l'interface WebDav ne fonctionne pas comme il faut.",
"Please double check the <a href='%s'>installation guides</a>." => "Veuillez vous référer au <a href='%s'>guide d'installation</a>.",
-"seconds ago" => "à l'instant",
-"1 minute ago" => "il y a 1 minute",
+"seconds ago" => "il y a quelques secondes",
+"1 minute ago" => "il y a une minute",
"%d minutes ago" => "il y a %d minutes",
"1 hour ago" => "Il y a une heure",
"%d hours ago" => "Il y a %d heures",
@@ -49,8 +49,5 @@
"%d months ago" => "Il y a %d mois",
"last year" => "l'année dernière",
"years ago" => "il y a plusieurs années",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s est disponible. Obtenez <a href=\"%s\">plus d'informations</a>",
-"up to date" => "À jour",
-"updates check is disabled" => "la vérification des mises à jour est désactivée",
"Could not find category \"%s\"" => "Impossible de trouver la catégorie \"%s\""
);
diff --git a/lib/l10n/gl.php b/lib/l10n/gl.php
index a11724fef43..351f18c7155 100644
--- a/lib/l10n/gl.php
+++ b/lib/l10n/gl.php
@@ -1,31 +1,27 @@
<?php $TRANSLATIONS = array(
"Help" => "Axuda",
"Personal" => "Persoal",
-"Settings" => "Configuracións",
+"Settings" => "Axustes",
"Users" => "Usuarios",
"Apps" => "Aplicativos",
"Admin" => "Administración",
+"web services under your control" => "servizos web baixo o seu control",
"ZIP download is turned off." => "As descargas ZIP están desactivadas.",
"Files need to be downloaded one by one." => "Os ficheiros necesitan seren descargados dun en un.",
"Back to Files" => "Volver aos ficheiros",
"Selected files too large to generate zip file." => "Os ficheiros seleccionados son demasiado grandes como para xerar un ficheiro zip.",
"couldn't be determined" => "non foi posíbel determinalo",
"Application is not enabled" => "O aplicativo non está activado",
-"Authentication error" => "Produciuse un erro na autenticación",
+"Authentication error" => "Produciuse un erro de autenticación",
"Token expired. Please reload page." => "Testemuña caducada. Recargue a páxina.",
"Files" => "Ficheiros",
"Text" => "Texto",
"Images" => "Imaxes",
-"Set an admin username." => "Estabeleza un nome de usuario administrador",
-"Set an admin password." => "Estabeleza un contrasinal de administrador",
-"Specify a data folder." => "Especifique un cartafol de datos.",
"%s enter the database username." => "%s introduza o nome de usuario da base de datos",
"%s enter the database name." => "%s introduza o nome da base de datos",
"%s you may not use dots in the database name" => "%s non se poden empregar puntos na base de datos",
-"%s set the database host." => "%s estabeleza o servidor da base de datos",
-"PostgreSQL username and/or password not valid" => "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto",
+"MS SQL username and/or password not valid: %s" => "Nome de usuario e/ou contrasinal de MS SQL incorrecto: %s",
"You need to enter either an existing account or the administrator." => "Deberá introducir unha conta existente ou o administrador.",
-"Oracle username and/or password not valid" => "Nome de usuario e/ou contrasinal de Oracle incorrecto",
"MySQL username and/or password not valid" => "Nome de usuario e/ou contrasinal de MySQL incorrecto",
"DB Error: \"%s\"" => "Produciuse un erro na base de datos: «%s»",
"Offending command was: \"%s\"" => "A orde ofensiva foi: «%s»",
@@ -33,8 +29,12 @@
"Drop this user from MySQL" => "Omitir este usuario de MySQL",
"MySQL user '%s'@'%%' already exists" => "O usuario MySQL «%s»@«%%» xa existe.",
"Drop this user from MySQL." => "Omitir este usuario de MySQL.",
+"Oracle connection could not be established" => "Non foi posíbel estabelecer a conexión con Oracle",
+"Oracle username and/or password not valid" => "Nome de usuario e/ou contrasinal de Oracle incorrecto",
"Offending command was: \"%s\", name: %s, password: %s" => "A orde ofensiva foi: «%s», nome: %s, contrasinal: %s",
-"MS SQL username and/or password not valid: %s" => "Nome de usuario e/ou contrasinal de MS SQL incorrecto: %s",
+"PostgreSQL username and/or password not valid" => "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto",
+"Set an admin username." => "Estabeleza un nome de usuario administrador",
+"Set an admin password." => "Estabeleza un contrasinal de administrador",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "O seu servidor web non está aínda configurado adecuadamente para permitir a sincronización de ficheiros xa que semella que a interface WebDAV non está a funcionar.",
"Please double check the <a href='%s'>installation guides</a>." => "Volva comprobar as <a href='%s'>guías de instalación</a>",
"seconds ago" => "segundos atrás",
@@ -49,8 +49,5 @@
"%d months ago" => "Vai %d meses",
"last year" => "último ano",
"years ago" => "anos atrás",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s está dispoñíbel. Obtéña <a href=\"%s\">máis información</a>",
-"up to date" => "actualizado",
-"updates check is disabled" => "a comprobación de actualizacións está desactivada",
"Could not find category \"%s\"" => "Non foi posíbel atopar a categoría «%s»"
);
diff --git a/lib/l10n/he.php b/lib/l10n/he.php
index 078a731afc0..2e011e342a0 100644
--- a/lib/l10n/he.php
+++ b/lib/l10n/he.php
@@ -5,6 +5,7 @@
"Users" => "משתמשים",
"Apps" => "יישומים",
"Admin" => "מנהל",
+"web services under your control" => "שירותי רשת תחת השליטה שלך",
"ZIP download is turned off." => "הורדת ZIP כבויה",
"Files need to be downloaded one by one." => "יש להוריד את הקבצים אחד אחרי השני.",
"Back to Files" => "חזרה לקבצים",
@@ -15,6 +16,8 @@
"Files" => "קבצים",
"Text" => "טקסט",
"Images" => "תמונות",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "שרת האינטרנט שלך אינו מוגדר לצורכי סנכרון קבצים עדיין כיוון שמנשק ה־WebDAV כנראה אינו תקין.",
+"Please double check the <a href='%s'>installation guides</a>." => "נא לעיין שוב ב<a href='%s'>מדריכי ההתקנה</a>.",
"seconds ago" => "שניות",
"1 minute ago" => "לפני דקה אחת",
"%d minutes ago" => "לפני %d דקות",
@@ -27,8 +30,5 @@
"%d months ago" => "לפני %d חודשים",
"last year" => "שנה שעברה",
"years ago" => "שנים",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s זמין. קבלת <a href=\"%s\">מידע נוסף</a>",
-"up to date" => "עדכני",
-"updates check is disabled" => "בדיקת עדכונים מנוטרלת",
"Could not find category \"%s\"" => "לא ניתן למצוא את הקטגוריה „%s“"
);
diff --git a/lib/l10n/hr.php b/lib/l10n/hr.php
index 62305c15711..41c34d3108c 100644
--- a/lib/l10n/hr.php
+++ b/lib/l10n/hr.php
@@ -3,6 +3,9 @@
"Personal" => "Osobno",
"Settings" => "Postavke",
"Users" => "Korisnici",
+"Apps" => "Aplikacije",
+"Admin" => "Administrator",
+"web services under your control" => "web usluge pod vašom kontrolom",
"Authentication error" => "Greška kod autorizacije",
"Files" => "Datoteke",
"Text" => "Tekst",
diff --git a/lib/l10n/hu_HU.php b/lib/l10n/hu_HU.php
index 537066c6fea..3aa04274fa3 100644
--- a/lib/l10n/hu_HU.php
+++ b/lib/l10n/hu_HU.php
@@ -5,27 +5,23 @@
"Users" => "Felhasználók",
"Apps" => "Alkalmazások",
"Admin" => "Adminsztráció",
+"web services under your control" => "webszolgáltatások saját kézben",
"ZIP download is turned off." => "A ZIP-letöltés nincs engedélyezve.",
"Files need to be downloaded one by one." => "A fájlokat egyenként kell letölteni.",
"Back to Files" => "Vissza a Fájlokhoz",
"Selected files too large to generate zip file." => "A kiválasztott fájlok túl nagyok a zip tömörítéshez.",
"couldn't be determined" => "nem határozható meg",
"Application is not enabled" => "Az alkalmazás nincs engedélyezve",
-"Authentication error" => "Hitelesítési hiba",
+"Authentication error" => "Azonosítási hiba",
"Token expired. Please reload page." => "A token lejárt. Frissítse az oldalt.",
"Files" => "Fájlok",
"Text" => "Szöveg",
"Images" => "Képek",
-"Set an admin username." => "Állítson be egy felhasználói nevet az adminisztrációhoz.",
-"Set an admin password." => "Állítson be egy jelszót az adminisztrációhoz.",
-"Specify a data folder." => "Adja meg az adatokat tartalmazó könyvtár nevét.",
"%s enter the database username." => "%s adja meg az adatbázist elérő felhasználó login nevét.",
"%s enter the database name." => "%s adja meg az adatbázis nevét.",
"%s you may not use dots in the database name" => "%s az adatbázis neve nem tartalmazhat pontot",
-"%s set the database host." => "%s adja meg az adatbázist szolgáltató számítógép nevét.",
-"PostgreSQL username and/or password not valid" => "A PostgreSQL felhasználói név és/vagy jelszó érvénytelen",
+"MS SQL username and/or password not valid: %s" => "Az MS SQL felhasználónév és/vagy jelszó érvénytelen: %s",
"You need to enter either an existing account or the administrator." => "Vagy egy létező felhasználó vagy az adminisztrátor bejelentkezési nevét kell megadnia",
-"Oracle username and/or password not valid" => "Az Oracle felhasználói név és/vagy jelszó érvénytelen",
"MySQL username and/or password not valid" => "A MySQL felhasználói név és/vagy jelszó érvénytelen",
"DB Error: \"%s\"" => "Adatbázis hiba: \"%s\"",
"Offending command was: \"%s\"" => "A hibát ez a parancs okozta: \"%s\"",
@@ -33,11 +29,15 @@
"Drop this user from MySQL" => "Törölje ezt a felhasználót a MySQL-ből",
"MySQL user '%s'@'%%' already exists" => "A '%s'@'%%' MySQL felhasználó már létezik",
"Drop this user from MySQL." => "Törölje ezt a felhasználót a MySQL-ből.",
+"Oracle connection could not be established" => "Az Oracle kapcsolat nem hozható létre",
+"Oracle username and/or password not valid" => "Az Oracle felhasználói név és/vagy jelszó érvénytelen",
"Offending command was: \"%s\", name: %s, password: %s" => "A hibát okozó parancs ez volt: \"%s\", login név: %s, jelszó: %s",
-"MS SQL username and/or password not valid: %s" => "Az MS SQL felhasználónév és/vagy jelszó érvénytelen: %s",
+"PostgreSQL username and/or password not valid" => "A PostgreSQL felhasználói név és/vagy jelszó érvénytelen",
+"Set an admin username." => "Állítson be egy felhasználói nevet az adminisztrációhoz.",
+"Set an admin password." => "Állítson be egy jelszót az adminisztrációhoz.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Az Ön webkiszolgálója nincs megfelelően beállítva az állományok szinkronizálásához, mert a WebDAV-elérés úgy tűnik, nem működik.",
"Please double check the <a href='%s'>installation guides</a>." => "Kérjük tüzetesen tanulmányozza át a <a href='%s'>telepítési útmutatót</a>.",
-"seconds ago" => "másodperce",
+"seconds ago" => "pár másodperce",
"1 minute ago" => "1 perce",
"%d minutes ago" => "%d perce",
"1 hour ago" => "1 órája",
@@ -48,9 +48,6 @@
"last month" => "múlt hónapban",
"%d months ago" => "%d hónapja",
"last year" => "tavaly",
-"years ago" => "éve",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s elérhető. <a href=\"%s\">További információ</a>.",
-"up to date" => "a legfrissebb változat",
-"updates check is disabled" => "A frissitések ellenőrzése nincs engedélyezve.",
+"years ago" => "több éve",
"Could not find category \"%s\"" => "Ez a kategória nem található: \"%s\""
);
diff --git a/lib/l10n/ia.php b/lib/l10n/ia.php
index 05b2c88e1ed..e5f6e3ddf58 100644
--- a/lib/l10n/ia.php
+++ b/lib/l10n/ia.php
@@ -3,6 +3,9 @@
"Personal" => "Personal",
"Settings" => "Configurationes",
"Users" => "Usatores",
+"Apps" => "Applicationes",
+"Admin" => "Administration",
+"web services under your control" => "servicios web sub tu controlo",
"Files" => "Files",
"Text" => "Texto"
);
diff --git a/lib/l10n/id.php b/lib/l10n/id.php
index 8f0e38123b6..c247651f0c9 100644
--- a/lib/l10n/id.php
+++ b/lib/l10n/id.php
@@ -1,34 +1,52 @@
<?php $TRANSLATIONS = array(
-"Help" => "bantu",
-"Personal" => "perseorangan",
-"Settings" => "pengaturan",
-"Users" => "pengguna",
-"Apps" => "aplikasi",
-"Admin" => "admin",
-"ZIP download is turned off." => "download ZIP sedang dimatikan",
-"Files need to be downloaded one by one." => "file harus di unduh satu persatu",
-"Back to Files" => "kembali ke daftar file",
-"Selected files too large to generate zip file." => "file yang dipilih terlalu besar untuk membuat file zip",
-"Application is not enabled" => "aplikasi tidak diaktifkan",
-"Authentication error" => "autentikasi bermasalah",
-"Token expired. Please reload page." => "token kadaluarsa.mohon perbaharui laman.",
+"Help" => "Bantuan",
+"Personal" => "Pribadi",
+"Settings" => "Setelan",
+"Users" => "Pengguna",
+"Apps" => "Aplikasi",
+"Admin" => "Admin",
+"web services under your control" => "layanan web dalam kontrol Anda",
+"ZIP download is turned off." => "Pengunduhan ZIP dimatikan.",
+"Files need to be downloaded one by one." => "Berkas harus diunduh satu persatu.",
+"Back to Files" => "Kembali ke Daftar Berkas",
+"Selected files too large to generate zip file." => "Berkas yang dipilih terlalu besar untuk dibuat berkas zip-nya.",
+"couldn't be determined" => "tidak dapat ditentukan",
+"Application is not enabled" => "Aplikasi tidak diaktifkan",
+"Authentication error" => "Galat saat autentikasi",
+"Token expired. Please reload page." => "Token kedaluwarsa. Silakan muat ulang halaman.",
"Files" => "Berkas",
-"Text" => "teks",
+"Text" => "Teks",
"Images" => "Gambar",
+"%s enter the database username." => "%s masukkan nama pengguna basis data.",
+"%s enter the database name." => "%s masukkan nama basis data.",
+"%s you may not use dots in the database name" => "%sAnda tidak boleh menggunakan karakter titik pada nama basis data",
+"MS SQL username and/or password not valid: %s" => "Nama pengguna dan/atau sandi MySQL tidak valid: %s",
+"You need to enter either an existing account or the administrator." => "Anda harus memasukkan akun yang sudah ada atau administrator.",
+"MySQL username and/or password not valid" => "Nama pengguna dan/atau sandi MySQL tidak valid",
+"DB Error: \"%s\"" => "Galat Basis Data: \"%s\"",
+"Offending command was: \"%s\"" => "Perintah yang bermasalah: \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "Pengguna MySQL '%s'@'localhost' sudah ada.",
+"Drop this user from MySQL" => "Hapus pengguna ini dari MySQL",
+"MySQL user '%s'@'%%' already exists" => "Pengguna MySQL '%s'@'%%' sudah ada.",
+"Drop this user from MySQL." => "Hapus pengguna ini dari MySQL.",
+"Oracle username and/or password not valid" => "Nama pengguna dan/atau sandi Oracle tidak valid",
+"Offending command was: \"%s\", name: %s, password: %s" => "Perintah yang bermasalah: \"%s\", nama pengguna: %s, sandi: %s",
+"PostgreSQL username and/or password not valid" => "Nama pengguna dan/atau sandi PostgreSQL tidak valid",
+"Set an admin username." => "Setel nama pengguna admin.",
+"Set an admin password." => "Setel sandi admin.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Web server Anda belum dikonfigurasikan dengan baik untuk mengizinkan sinkronisasi berkas karena tampaknya antarmuka WebDAV rusak.",
+"Please double check the <a href='%s'>installation guides</a>." => "Silakan periksa ulang <a href='%s'>panduan instalasi</a>.",
"seconds ago" => "beberapa detik yang lalu",
-"1 minute ago" => "1 menit lalu",
-"%d minutes ago" => "%d menit lalu",
+"1 minute ago" => "1 menit yang lalu",
+"%d minutes ago" => "%d menit yang lalu",
"1 hour ago" => "1 jam yang lalu",
"%d hours ago" => "%d jam yang lalu",
"today" => "hari ini",
"yesterday" => "kemarin",
-"%d days ago" => "%d hari lalu",
+"%d days ago" => "%d hari yang lalu",
"last month" => "bulan kemarin",
"%d months ago" => "%d bulan yang lalu",
"last year" => "tahun kemarin",
"years ago" => "beberapa tahun lalu",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s tersedia. dapatkan <a href=\"%s\"> info lebih lanjut</a>",
-"up to date" => "terbaru",
-"updates check is disabled" => "pengecekan pembaharuan sedang non-aktifkan",
"Could not find category \"%s\"" => "Tidak dapat menemukan kategori \"%s\""
);
diff --git a/lib/l10n/is.php b/lib/l10n/is.php
index 8fdb45a05cd..0f7a22fd13e 100644
--- a/lib/l10n/is.php
+++ b/lib/l10n/is.php
@@ -5,6 +5,7 @@
"Users" => "Notendur",
"Apps" => "Forrit",
"Admin" => "Stjórnun",
+"web services under your control" => "vefþjónusta undir þinni stjórn",
"ZIP download is turned off." => "Slökkt á ZIP niðurhali.",
"Files need to be downloaded one by one." => "Skrárnar verður að sækja eina og eina",
"Back to Files" => "Aftur í skrár",
@@ -27,8 +28,5 @@
"%d months ago" => "fyrir %d mánuðum",
"last year" => "síðasta ári",
"years ago" => "einhverjum árum",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s er í boði. Sækja <a href=\"%s\">meiri upplýsingar</a>",
-"up to date" => "nýjasta útgáfa",
-"updates check is disabled" => "uppfærslupróf er ekki virkjað",
"Could not find category \"%s\"" => "Fann ekki flokkinn \"%s\""
);
diff --git a/lib/l10n/it.php b/lib/l10n/it.php
index 297f1efde05..74483315ca0 100644
--- a/lib/l10n/it.php
+++ b/lib/l10n/it.php
@@ -5,6 +5,7 @@
"Users" => "Utenti",
"Apps" => "Applicazioni",
"Admin" => "Admin",
+"web services under your control" => "servizi web nelle tue mani",
"ZIP download is turned off." => "Lo scaricamento in formato ZIP è stato disabilitato.",
"Files need to be downloaded one by one." => "I file devono essere scaricati uno alla volta.",
"Back to Files" => "Torna ai file",
@@ -16,16 +17,11 @@
"Files" => "File",
"Text" => "Testo",
"Images" => "Immagini",
-"Set an admin username." => "Imposta un nome utente di amministrazione.",
-"Set an admin password." => "Imposta una password di amministrazione.",
-"Specify a data folder." => "Specifica una cartella dei dati.",
"%s enter the database username." => "%s digita il nome utente del database.",
"%s enter the database name." => "%s digita il nome del database.",
"%s you may not use dots in the database name" => "%s non dovresti utilizzare punti nel nome del database",
-"%s set the database host." => "%s imposta l'host del database.",
-"PostgreSQL username and/or password not valid" => "Nome utente e/o password di PostgreSQL non validi",
+"MS SQL username and/or password not valid: %s" => "Nome utente e/o password MS SQL non validi: %s",
"You need to enter either an existing account or the administrator." => "È necessario inserire un account esistente o l'amministratore.",
-"Oracle username and/or password not valid" => "Nome utente e/o password di Oracle non validi",
"MySQL username and/or password not valid" => "Nome utente e/o password di MySQL non validi",
"DB Error: \"%s\"" => "Errore DB: \"%s\"",
"Offending command was: \"%s\"" => "Il comando non consentito era: \"%s\"",
@@ -33,24 +29,25 @@
"Drop this user from MySQL" => "Elimina questo utente da MySQL",
"MySQL user '%s'@'%%' already exists" => "L'utente MySQL '%s'@'%%' esiste già",
"Drop this user from MySQL." => "Elimina questo utente da MySQL.",
+"Oracle connection could not be established" => "La connessione a Oracle non può essere stabilita",
+"Oracle username and/or password not valid" => "Nome utente e/o password di Oracle non validi",
"Offending command was: \"%s\", name: %s, password: %s" => "Il comando non consentito era: \"%s\", nome: %s, password: %s",
-"MS SQL username and/or password not valid: %s" => "Nome utente e/o password MS SQL non validi: %s",
+"PostgreSQL username and/or password not valid" => "Nome utente e/o password di PostgreSQL non validi",
+"Set an admin username." => "Imposta un nome utente di amministrazione.",
+"Set an admin password." => "Imposta una password di amministrazione.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Il tuo server web non è configurato correttamente per consentire la sincronizzazione dei file poiché l'interfaccia WebDAV sembra essere danneggiata.",
"Please double check the <a href='%s'>installation guides</a>." => "Leggi attentamente le <a href='%s'>guide d'installazione</a>.",
"seconds ago" => "secondi fa",
-"1 minute ago" => "1 minuto fa",
+"1 minute ago" => "Un minuto fa",
"%d minutes ago" => "%d minuti fa",
"1 hour ago" => "1 ora fa",
"%d hours ago" => "%d ore fa",
"today" => "oggi",
"yesterday" => "ieri",
"%d days ago" => "%d giorni fa",
-"last month" => "il mese scorso",
+"last month" => "mese scorso",
"%d months ago" => "%d mesi fa",
-"last year" => "l'anno scorso",
+"last year" => "anno scorso",
"years ago" => "anni fa",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s è disponibile. Ottieni <a href=\"%s\">ulteriori informazioni</a>",
-"up to date" => "aggiornato",
-"updates check is disabled" => "il controllo degli aggiornamenti è disabilitato",
"Could not find category \"%s\"" => "Impossibile trovare la categoria \"%s\""
);
diff --git a/lib/l10n/ja_JP.php b/lib/l10n/ja_JP.php
index 529eec3ac52..36d06d360b9 100644
--- a/lib/l10n/ja_JP.php
+++ b/lib/l10n/ja_JP.php
@@ -1,10 +1,11 @@
<?php $TRANSLATIONS = array(
"Help" => "ヘルプ",
-"Personal" => "個人設定",
+"Personal" => "個人",
"Settings" => "設定",
"Users" => "ユーザ",
"Apps" => "アプリ",
-"Admin" => "管理者",
+"Admin" => "管理",
+"web services under your control" => "管理下のウェブサービス",
"ZIP download is turned off." => "ZIPダウンロードは無効です。",
"Files need to be downloaded one by one." => "ファイルは1つずつダウンロードする必要があります。",
"Back to Files" => "ファイルに戻る",
@@ -16,16 +17,11 @@
"Files" => "ファイル",
"Text" => "TTY TDD",
"Images" => "画像",
-"Set an admin username." => "管理者のユーザ名を設定。",
-"Set an admin password." => "管理者のパスワードを設定。",
-"Specify a data folder." => "データフォルダを指定。",
"%s enter the database username." => "%s のデータベースのユーザ名を入力してください。",
"%s enter the database name." => "%s のデータベース名を入力してください。",
"%s you may not use dots in the database name" => "%s ではデータベース名にドットを利用できないかもしれません。",
-"%s set the database host." => "%s にデータベースホストを設定します。",
-"PostgreSQL username and/or password not valid" => "PostgreSQLのユーザ名もしくはパスワードは有効ではありません",
+"MS SQL username and/or password not valid: %s" => "MS SQL サーバーのユーザー名/パスワードが正しくありません: %s",
"You need to enter either an existing account or the administrator." => "既存のアカウントもしくは管理者のどちらかを入力する必要があります。",
-"Oracle username and/or password not valid" => "Oracleのユーザ名もしくはパスワードは有効ではありません",
"MySQL username and/or password not valid" => "MySQLのユーザ名もしくはパスワードは有効ではありません",
"DB Error: \"%s\"" => "DBエラー: \"%s\"",
"Offending command was: \"%s\"" => "違反コマンド: \"%s\"",
@@ -33,24 +29,25 @@
"Drop this user from MySQL" => "MySQLからこのユーザを削除",
"MySQL user '%s'@'%%' already exists" => "MySQLのユーザ '%s'@'%%' はすでに存在します。",
"Drop this user from MySQL." => "MySQLからこのユーザを削除する。",
+"Oracle connection could not be established" => "Oracleへの接続が確立できませんでした。",
+"Oracle username and/or password not valid" => "Oracleのユーザ名もしくはパスワードは有効ではありません",
"Offending command was: \"%s\", name: %s, password: %s" => "違反コマンド: \"%s\"、名前: %s、パスワード: %s",
-"MS SQL username and/or password not valid: %s" => "MS SQL サーバーのユーザー名/パスワードが正しくありません: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQLのユーザ名もしくはパスワードは有効ではありません",
+"Set an admin username." => "管理者のユーザ名を設定。",
+"Set an admin password." => "管理者のパスワードを設定。",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "WebDAVインタフェースが動作していないと考えられるため、あなたのWEBサーバはまだファイルの同期を許可するように適切な設定がされていません。",
"Please double check the <a href='%s'>installation guides</a>." => "<a href='%s'>インストールガイド</a>をよく確認してください。",
-"seconds ago" => "秒前",
-"1 minute ago" => "1分前",
+"seconds ago" => "数秒前",
+"1 minute ago" => "1 分前",
"%d minutes ago" => "%d 分前",
"1 hour ago" => "1 時間前",
"%d hours ago" => "%d 時間前",
"today" => "今日",
"yesterday" => "昨日",
"%d days ago" => "%d 日前",
-"last month" => "先月",
+"last month" => "一月前",
"%d months ago" => "%d 分前",
-"last year" => "昨年",
+"last year" => "一年前",
"years ago" => "年前",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s が利用可能です。<a href=\"%s\">詳細情報</a> を確認ください",
-"up to date" => "最新です",
-"updates check is disabled" => "更新チェックは無効です",
"Could not find category \"%s\"" => "カテゴリ \"%s\" が見つかりませんでした"
);
diff --git a/lib/l10n/ka_GE.php b/lib/l10n/ka_GE.php
index ff623827216..c6e77da2dac 100644
--- a/lib/l10n/ka_GE.php
+++ b/lib/l10n/ka_GE.php
@@ -5,16 +5,48 @@
"Users" => "მომხმარებელი",
"Apps" => "აპლიკაციები",
"Admin" => "ადმინისტრატორი",
+"web services under your control" => "web services under your control",
+"ZIP download is turned off." => "ZIP download–ი გათიშულია",
+"Files need to be downloaded one by one." => "ფაილები უნდა გადმოიტვირთოს სათითაოდ.",
+"Back to Files" => "უკან ფაილებში",
+"Selected files too large to generate zip file." => "არჩეული ფაილები ძალიან დიდია zip ფაილის გენერაციისთვის.",
+"couldn't be determined" => "ვერ განისაზღვრა",
+"Application is not enabled" => "აპლიკაცია არ არის აქტიური",
"Authentication error" => "ავთენტიფიკაციის შეცდომა",
+"Token expired. Please reload page." => "Token–ს ვადა გაუვიდა. გთხოვთ განაახლოთ გვერდი.",
"Files" => "ფაილები",
"Text" => "ტექსტი",
+"Images" => "სურათები",
+"%s enter the database username." => "%s შეიყვანეთ ბაზის იუზერნეიმი.",
+"%s enter the database name." => "%s შეიყვანეთ ბაზის სახელი.",
+"%s you may not use dots in the database name" => "%s არ მიუთითოთ წერტილი ბაზის სახელში",
+"MS SQL username and/or password not valid: %s" => "MS SQL მომხმარებელი და/ან პაროლი არ არის მართებული: %s",
+"You need to enter either an existing account or the administrator." => "თქვენ უნდა შეიყვანოთ არსებული მომხმარებელის სახელი ან ადმინისტრატორი.",
+"MySQL username and/or password not valid" => "MySQL იუზერნეიმი და/ან პაროლი არ არის სწორი",
+"DB Error: \"%s\"" => "DB შეცდომა: \"%s\"",
+"Offending command was: \"%s\"" => "Offending ბრძანება იყო: \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "MySQL მომხმარებელი '%s'@'localhost' უკვე არსებობს.",
+"Drop this user from MySQL" => "წაშალე ეს მომხამრებელი MySQL–იდან",
+"MySQL user '%s'@'%%' already exists" => "MySQL მომხმარებელი '%s'@'%%' უკვე არსებობს",
+"Drop this user from MySQL." => "წაშალე ეს მომხამრებელი MySQL–იდან",
+"Oracle username and/or password not valid" => "Oracle იუზერნეიმი და/ან პაროლი არ არის სწორი",
+"Offending command was: \"%s\", name: %s, password: %s" => "Offending ბრძანება იყო: \"%s\", სახელი: %s, პაროლი: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL იუზერნეიმი და/ან პაროლი არ არის სწორი",
+"Set an admin username." => "დააყენეთ ადმინისტრატორის სახელი.",
+"Set an admin password." => "დააყენეთ ადმინისტრატორის პაროლი.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "თქვენი web სერვერი არ არის კონფიგურირებული ფაილ სინქრონიზაციისთვის, რადგან WebDAV ინტერფეისი შეიძლება იყოს გატეხილი.",
+"Please double check the <a href='%s'>installation guides</a>." => "გთხოვთ გადაათვალიეროთ <a href='%s'>ინსტალაციის გზამკვლევი</a>.",
"seconds ago" => "წამის წინ",
"1 minute ago" => "1 წუთის წინ",
+"%d minutes ago" => "%d წუთის წინ",
+"1 hour ago" => "1 საათის წინ",
+"%d hours ago" => "%d საათის წინ",
"today" => "დღეს",
"yesterday" => "გუშინ",
+"%d days ago" => "%d დღის წინ",
"last month" => "გასულ თვეში",
+"%d months ago" => "%d თვის წინ",
"last year" => "ბოლო წელს",
"years ago" => "წლის წინ",
-"up to date" => "განახლებულია",
-"updates check is disabled" => "განახლების ძებნა გათიშულია"
+"Could not find category \"%s\"" => "\"%s\" კატეგორიის მოძებნა ვერ მოხერხდა"
);
diff --git a/lib/l10n/ko.php b/lib/l10n/ko.php
index 859657f46b4..31245ea96f2 100644
--- a/lib/l10n/ko.php
+++ b/lib/l10n/ko.php
@@ -5,6 +5,7 @@
"Users" => "사용자",
"Apps" => "앱",
"Admin" => "관리자",
+"web services under your control" => "내가 관리하는 웹 서비스",
"ZIP download is turned off." => "ZIP 다운로드가 비활성화되었습니다.",
"Files need to be downloaded one by one." => "파일을 개별적으로 다운로드해야 합니다.",
"Back to Files" => "파일로 돌아가기",
@@ -16,6 +17,8 @@
"Files" => "파일",
"Text" => "텍스트",
"Images" => "그림",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "WebDAV 인터페이스가 제대로 작동하지 않습니다. 웹 서버에서 파일 동기화를 사용할 수 있도록 설정이 제대로 되지 않은 것 같습니다.",
+"Please double check the <a href='%s'>installation guides</a>." => "<a href='%s'>설치 가이드</a>를 다시 한 번 확인하십시오.",
"seconds ago" => "초 전",
"1 minute ago" => "1분 전",
"%d minutes ago" => "%d분 전",
@@ -28,8 +31,5 @@
"%d months ago" => "%d개월 전",
"last year" => "작년",
"years ago" => "년 전",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s을(를) 사용할 수 있습니다. <a href=\"%s\">자세한 정보 보기</a>",
-"up to date" => "최신",
-"updates check is disabled" => "업데이트 확인이 비활성화됨",
"Could not find category \"%s\"" => "분류 \"%s\"을(를) 찾을 수 없습니다."
);
diff --git a/lib/l10n/ku_IQ.php b/lib/l10n/ku_IQ.php
index f89871f23c9..6d7461a1685 100644
--- a/lib/l10n/ku_IQ.php
+++ b/lib/l10n/ku_IQ.php
@@ -1,5 +1,8 @@
<?php $TRANSLATIONS = array(
"Help" => "یارمەتی",
"Settings" => "ده‌ستكاری",
-"Users" => "به‌كارهێنه‌ر"
+"Users" => "به‌كارهێنه‌ر",
+"Apps" => "به‌رنامه‌كان",
+"Admin" => "به‌ڕێوه‌به‌ری سه‌ره‌كی",
+"web services under your control" => "ڕاژه‌ی وێب له‌ژێر چاودێریت دایه"
);
diff --git a/lib/l10n/lb.php b/lib/l10n/lb.php
index 06e8b2ca094..867b0a37409 100644
--- a/lib/l10n/lb.php
+++ b/lib/l10n/lb.php
@@ -2,10 +2,18 @@
"Help" => "Hëllef",
"Personal" => "Perséinlech",
"Settings" => "Astellungen",
+"Users" => "Benotzer",
+"Apps" => "Applikatiounen",
+"Admin" => "Admin",
+"web services under your control" => "Web-Servicer ënnert denger Kontroll",
"Authentication error" => "Authentifikatioun's Fehler",
"Files" => "Dateien",
"Text" => "SMS",
+"seconds ago" => "Sekonnen hir",
+"1 minute ago" => "1 Minutt hir",
"1 hour ago" => "vrun 1 Stonn",
+"today" => "haut",
+"yesterday" => "gëschter",
"last month" => "Läschte Mount",
"last year" => "Läscht Joer",
"years ago" => "Joren hier"
diff --git a/lib/l10n/lt_LT.php b/lib/l10n/lt_LT.php
index b84c155633b..5e3a0482033 100644
--- a/lib/l10n/lt_LT.php
+++ b/lib/l10n/lt_LT.php
@@ -5,6 +5,7 @@
"Users" => "Vartotojai",
"Apps" => "Programos",
"Admin" => "Administravimas",
+"web services under your control" => "jūsų valdomos web paslaugos",
"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",
@@ -14,16 +15,17 @@
"Token expired. Please reload page." => "Sesija baigėsi. Prašome perkrauti puslapį.",
"Files" => "Failai",
"Text" => "Žinučių",
-"seconds ago" => "prieš kelias sekundes",
-"1 minute ago" => "prieš 1 minutę",
+"Images" => "Paveikslėliai",
+"seconds ago" => "prieš sekundę",
+"1 minute ago" => "Prieš 1 minutę",
"%d minutes ago" => "prieš %d minučių",
+"1 hour ago" => "prieš 1 valandą",
+"%d hours ago" => "prieš %d valandų",
"today" => "šiandien",
"yesterday" => "vakar",
"%d days ago" => "prieš %d dienų",
-"last month" => "praėjusį mėnesį",
-"last year" => "pereitais metais",
-"years ago" => "prieš metus",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s yra galimas. Platesnė <a href=\"%s\">informacija čia</a>",
-"up to date" => "pilnai atnaujinta",
-"updates check is disabled" => "atnaujinimų tikrinimas išjungtas"
+"last month" => "praeitą mėnesį",
+"%d months ago" => "prieš %d mėnesių",
+"last year" => "praeitais metais",
+"years ago" => "prieš metus"
);
diff --git a/lib/l10n/lv.php b/lib/l10n/lv.php
index c73d306ca0a..662f4d5b245 100644
--- a/lib/l10n/lv.php
+++ b/lib/l10n/lv.php
@@ -5,6 +5,7 @@
"Users" => "Lietotāji",
"Apps" => "Lietotnes",
"Admin" => "Administratori",
+"web services under your control" => "tīmekļa servisi tavā varā",
"ZIP download is turned off." => "ZIP lejupielādēšana ir izslēgta.",
"Files need to be downloaded one by one." => "Datnes var lejupielādēt tikai katru atsevišķi.",
"Back to Files" => "Atpakaļ pie datnēm",
@@ -16,16 +17,11 @@
"Files" => "Datnes",
"Text" => "Teksts",
"Images" => "Attēli",
-"Set an admin username." => "Iestatiet administratora lietotājvārdu.",
-"Set an admin password." => "Iestatiet administratora paroli.",
-"Specify a data folder." => "Norādiet datu mapi.",
"%s enter the database username." => "%s ievadiet datubāzes lietotājvārdu.",
"%s enter the database name." => "%s ievadiet datubāzes nosaukumu.",
"%s you may not use dots in the database name" => "%s datubāžu nosaukumos nedrīkst izmantot punktus",
-"%s set the database host." => "%s iestatiet datubāžu serveri.",
-"PostgreSQL username and/or password not valid" => "Nav derīga PostgreSQL parole un/vai lietotājvārds",
+"MS SQL username and/or password not valid: %s" => "Nav derīga MySQL parole un/vai lietotājvārds — %s",
"You need to enter either an existing account or the administrator." => "Jums jāievada vai nu esošs vai administratora konts.",
-"Oracle username and/or password not valid" => "Nav derīga Oracle parole un/vai lietotājvārds",
"MySQL username and/or password not valid" => "Nav derīga MySQL parole un/vai lietotājvārds",
"DB Error: \"%s\"" => "DB kļūda — “%s”",
"Offending command was: \"%s\"" => "Vainīgā komanda bija “%s”",
@@ -33,8 +29,11 @@
"Drop this user from MySQL" => "Izmest šo lietotāju no MySQL",
"MySQL user '%s'@'%%' already exists" => "MySQL lietotājs '%s'@'%%' jau eksistē",
"Drop this user from MySQL." => "Izmest šo lietotāju no MySQL.",
+"Oracle username and/or password not valid" => "Nav derīga Oracle parole un/vai lietotājvārds",
"Offending command was: \"%s\", name: %s, password: %s" => "Vainīgā komanda bija \"%s\", vārds: %s, parole: %s",
-"MS SQL username and/or password not valid: %s" => "Nav derīga MySQL parole un/vai lietotājvārds — %s",
+"PostgreSQL username and/or password not valid" => "Nav derīga PostgreSQL parole un/vai lietotājvārds",
+"Set an admin username." => "Iestatiet administratora lietotājvārdu.",
+"Set an admin password." => "Iestatiet administratora paroli.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Jūsu serveris vēl nav pareizi iestatīts, lai ļautu sinhronizēt datnes, jo izskatās, ka WebDAV saskarne ir salauzta.",
"Please double check the <a href='%s'>installation guides</a>." => "Lūdzu, vēlreiz pārbaudiet <a href='%s'>instalēšanas palīdzību</a>.",
"seconds ago" => "sekundes atpakaļ",
@@ -49,8 +48,5 @@
"%d months ago" => "pirms %d mēnešiem",
"last year" => "gājušajā gadā",
"years ago" => "gadus atpakaļ",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s ir pieejams. Iegūt <a href=\"%s\">vairāk informācijas</a>",
-"up to date" => "ir aktuāls",
-"updates check is disabled" => "atjauninājumu pārbaude ir deaktivēta",
"Could not find category \"%s\"" => "Nevarēja atrast kategoriju “%s”"
);
diff --git a/lib/l10n/mk.php b/lib/l10n/mk.php
index 5b3efffb22a..30fa9ab73c1 100644
--- a/lib/l10n/mk.php
+++ b/lib/l10n/mk.php
@@ -1,10 +1,11 @@
<?php $TRANSLATIONS = array(
"Help" => "Помош",
"Personal" => "Лично",
-"Settings" => "Параметри",
+"Settings" => "Подесувања",
"Users" => "Корисници",
"Apps" => "Аппликации",
"Admin" => "Админ",
+"web services under your control" => "веб сервиси под Ваша контрола",
"ZIP download is turned off." => "Преземање во ZIP е исклучено",
"Files need to be downloaded one by one." => "Датотеките треба да се симнат една по една.",
"Back to Files" => "Назад кон датотеки",
@@ -27,8 +28,5 @@
"%d months ago" => "пред %d месеци",
"last year" => "минатата година",
"years ago" => "пред години",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s е достапно. Земи <a href=\"%s\">повеќе информации</a>",
-"up to date" => "ажурно",
-"updates check is disabled" => "проверката за ажурирања е оневозможена",
"Could not find category \"%s\"" => "Не можам да најдам категорија „%s“"
);
diff --git a/lib/l10n/ms_MY.php b/lib/l10n/ms_MY.php
index 5afee1cb5a8..a2930597971 100644
--- a/lib/l10n/ms_MY.php
+++ b/lib/l10n/ms_MY.php
@@ -3,6 +3,9 @@
"Personal" => "Peribadi",
"Settings" => "Tetapan",
"Users" => "Pengguna",
+"Apps" => "Aplikasi",
+"Admin" => "Admin",
+"web services under your control" => "Perkhidmatan web di bawah kawalan anda",
"Authentication error" => "Ralat pengesahan",
"Files" => "Fail-fail",
"Text" => "Teks"
diff --git a/lib/l10n/my_MM.php b/lib/l10n/my_MM.php
index d725a06a3a9..f214a1ed794 100644
--- a/lib/l10n/my_MM.php
+++ b/lib/l10n/my_MM.php
@@ -3,6 +3,7 @@
"Users" => "သုံးစွဲသူ",
"Apps" => "Apps",
"Admin" => "အက်ဒမင်",
+"web services under your control" => "သင်၏ထိန်းချုပ်မှု့အောက်တွင်ရှိသော Web services",
"ZIP download is turned off." => "ZIP ဒေါင်းလုတ်ကိုပိတ်ထားသည်",
"Files need to be downloaded one by one." => "ဖိုင်များသည် တစ်ခုပြီး တစ်ခုဒေါင်းလုတ်ချရန်လိုအပ်သည်",
"Back to Files" => "ဖိုင်သို့ပြန်သွားမည်",
@@ -24,8 +25,5 @@
"%d months ago" => "%d လအရင်က",
"last year" => "မနှစ်က",
"years ago" => "နှစ် အရင်က",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s ကိုရရှိနိုင်ပါပြီ။ <a href=\"%s\">နောက်ထပ်အချက်အလက်များ</a>ရယူပါ။",
-"up to date" => "နောက်ဆုံးပေါ်",
-"updates check is disabled" => "နောက်ဆုံးပေါ်စစ်ဆေးခြင်းကိုပိတ်ထားသည်",
"Could not find category \"%s\"" => "\"%s\"ခေါင်းစဉ်ကို ရှာမတွေ့ပါ"
);
diff --git a/lib/l10n/nb_NO.php b/lib/l10n/nb_NO.php
index 01144672caa..ab2d4f91920 100644
--- a/lib/l10n/nb_NO.php
+++ b/lib/l10n/nb_NO.php
@@ -5,16 +5,19 @@
"Users" => "Brukere",
"Apps" => "Apper",
"Admin" => "Admin",
+"web services under your control" => "web tjenester du kontrollerer",
"ZIP download is turned off." => "ZIP-nedlasting av avslått",
"Files need to be downloaded one by one." => "Filene må lastes ned en om gangen",
"Back to Files" => "Tilbake til filer",
"Selected files too large to generate zip file." => "De valgte filene er for store til å kunne generere ZIP-fil",
"Application is not enabled" => "Applikasjon er ikke påslått",
-"Authentication error" => "Autentiseringsfeil",
+"Authentication error" => "Autentikasjonsfeil",
"Token expired. Please reload page." => "Symbol utløpt. Vennligst last inn siden på nytt.",
"Files" => "Filer",
"Text" => "Tekst",
"Images" => "Bilder",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din nettservev er ikke konfigurert korrekt for filsynkronisering. WebDAV ser ut til å ikke funkere.",
+"Please double check the <a href='%s'>installation guides</a>." => "Vennligst dobbelsjekk <a href='%s'>installasjonsguiden</a>.",
"seconds ago" => "sekunder siden",
"1 minute ago" => "1 minutt siden",
"%d minutes ago" => "%d minutter siden",
@@ -25,10 +28,7 @@
"%d days ago" => "%d dager siden",
"last month" => "forrige måned",
"%d months ago" => "%d måneder siden",
-"last year" => "i fjor",
+"last year" => "forrige år",
"years ago" => "år siden",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s er tilgjengelig. Få <a href=\"%s\">mer informasjon</a>",
-"up to date" => "oppdatert",
-"updates check is disabled" => "versjonssjekk er avslått",
"Could not find category \"%s\"" => "Kunne ikke finne kategori \"%s\""
);
diff --git a/lib/l10n/nl.php b/lib/l10n/nl.php
index e26a663e9cc..de80d1b5d56 100644
--- a/lib/l10n/nl.php
+++ b/lib/l10n/nl.php
@@ -5,6 +5,7 @@
"Users" => "Gebruikers",
"Apps" => "Apps",
"Admin" => "Beheerder",
+"web services under your control" => "Webdiensten in eigen beheer",
"ZIP download is turned off." => "ZIP download is uitgeschakeld.",
"Files need to be downloaded one by one." => "Bestanden moeten één voor één worden gedownload.",
"Back to Files" => "Terug naar bestanden",
@@ -16,16 +17,11 @@
"Files" => "Bestanden",
"Text" => "Tekst",
"Images" => "Afbeeldingen",
-"Set an admin username." => "Stel de gebruikersnaam van de beheerder in.",
-"Set an admin password." => "Stel een beheerderswachtwoord in.",
-"Specify a data folder." => "Geef een datamap op.",
"%s enter the database username." => "%s opgeven database gebruikersnaam.",
"%s enter the database name." => "%s opgeven databasenaam.",
"%s you may not use dots in the database name" => "%s er mogen geen puntjes in de databasenaam voorkomen",
-"%s set the database host." => "%s instellen databaseservernaam.",
-"PostgreSQL username and/or password not valid" => "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig",
+"MS SQL username and/or password not valid: %s" => "MS SQL gebruikersnaam en/of wachtwoord niet geldig: %s",
"You need to enter either an existing account or the administrator." => "Geef of een bestaand account op of het beheerdersaccount.",
-"Oracle username and/or password not valid" => "Oracle gebruikersnaam en/of wachtwoord ongeldig",
"MySQL username and/or password not valid" => "MySQL gebruikersnaam en/of wachtwoord ongeldig",
"DB Error: \"%s\"" => "DB Fout: \"%s\"",
"Offending command was: \"%s\"" => "Onjuiste commande was: \"%s\"",
@@ -33,10 +29,14 @@
"Drop this user from MySQL" => "Verwijder deze gebruiker uit MySQL",
"MySQL user '%s'@'%%' already exists" => "MySQL gebruiker '%s'@'%%' bestaat al",
"Drop this user from MySQL." => "Verwijder deze gebruiker uit MySQL.",
+"Oracle connection could not be established" => "Er kon geen verbinding met Oracle worden bereikt",
+"Oracle username and/or password not valid" => "Oracle gebruikersnaam en/of wachtwoord ongeldig",
"Offending command was: \"%s\", name: %s, password: %s" => "Onjuiste commando was: \"%s\", naam: %s, wachtwoord: %s",
-"MS SQL username and/or password not valid: %s" => "MS SQL gebruikersnaam en/of wachtwoord niet geldig: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig",
+"Set an admin username." => "Stel de gebruikersnaam van de beheerder in.",
+"Set an admin password." => "Stel een beheerderswachtwoord in.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Uw webserver is nog niet goed ingesteld voor bestandssynchronisatie omdat de WebDAV interface verbroken lijkt.",
-"Please double check the <a href='%s'>installation guides</a>." => "Conntroleer de <a href='%s'>installatie handleiding</a> goed.",
+"Please double check the <a href='%s'>installation guides</a>." => "Controleer de <a href='%s'>installatiehandleiding</a> goed.",
"seconds ago" => "seconden geleden",
"1 minute ago" => "1 minuut geleden",
"%d minutes ago" => "%d minuten geleden",
@@ -49,8 +49,5 @@
"%d months ago" => "%d maanden geleden",
"last year" => "vorig jaar",
"years ago" => "jaar geleden",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s is beschikbaar. Verkrijg <a href=\"%s\">meer informatie</a>",
-"up to date" => "bijgewerkt",
-"updates check is disabled" => "Meest recente versie controle is uitgeschakeld",
"Could not find category \"%s\"" => "Kon categorie \"%s\" niet vinden"
);
diff --git a/lib/l10n/nn_NO.php b/lib/l10n/nn_NO.php
index faf7440320a..c1739398109 100644
--- a/lib/l10n/nn_NO.php
+++ b/lib/l10n/nn_NO.php
@@ -3,7 +3,20 @@
"Personal" => "Personleg",
"Settings" => "Innstillingar",
"Users" => "Brukarar",
+"Apps" => "Program",
+"Admin" => "Administrer",
+"web services under your control" => "Vev tjenester under din kontroll",
"Authentication error" => "Feil i autentisering",
"Files" => "Filer",
-"Text" => "Tekst"
+"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>.",
+"seconds ago" => "sekund sidan",
+"1 minute ago" => "1 minutt sidan",
+"1 hour ago" => "1 time sidan",
+"today" => "i dag",
+"yesterday" => "i går",
+"last month" => "førre månad",
+"last year" => "i fjor",
+"years ago" => "år sidan"
);
diff --git a/lib/l10n/oc.php b/lib/l10n/oc.php
index 89161393380..a72da90790a 100644
--- a/lib/l10n/oc.php
+++ b/lib/l10n/oc.php
@@ -5,6 +5,7 @@
"Users" => "Usancièrs",
"Apps" => "Apps",
"Admin" => "Admin",
+"web services under your control" => "Services web jos ton contraròtle",
"ZIP download is turned off." => "Avalcargar los ZIP es inactiu.",
"Files need to be downloaded one by one." => "Los fichièrs devan èsser avalcargats un per un.",
"Back to Files" => "Torna cap als fichièrs",
@@ -18,7 +19,5 @@
"%d days ago" => "%d jorns a",
"last month" => "mes passat",
"last year" => "an passat",
-"years ago" => "ans a",
-"up to date" => "a jorn",
-"updates check is disabled" => "la verificacion de mesa a jorn es inactiva"
+"years ago" => "ans a"
);
diff --git a/lib/l10n/pl.php b/lib/l10n/pl.php
index 9a1a5e836c9..bbca1913b70 100644
--- a/lib/l10n/pl.php
+++ b/lib/l10n/pl.php
@@ -5,6 +5,7 @@
"Users" => "Użytkownicy",
"Apps" => "Aplikacje",
"Admin" => "Administrator",
+"web services under your control" => "Kontrolowane serwisy",
"ZIP download is turned off." => "Pobieranie ZIP jest wyłączone.",
"Files need to be downloaded one by one." => "Pliki muszą zostać pobrane pojedynczo.",
"Back to Files" => "Wróć do plików",
@@ -16,16 +17,11 @@
"Files" => "Pliki",
"Text" => "Połączenie tekstowe",
"Images" => "Obrazy",
-"Set an admin username." => "Ustaw nazwę administratora.",
-"Set an admin password." => "Ustaw hasło administratora.",
-"Specify a data folder." => "Określ folder danych.",
"%s enter the database username." => "%s wpisz nazwę użytkownika do bazy",
"%s enter the database name." => "%s wpisz nazwę bazy.",
"%s you may not use dots in the database name" => "%s nie można używać kropki w nazwie bazy danych",
-"%s set the database host." => "%s ustaw hosta bazy danych.",
-"PostgreSQL username and/or password not valid" => "PostgreSQL: Nazwa użytkownika i/lub hasło jest niepoprawne",
+"MS SQL username and/or password not valid: %s" => "Nazwa i/lub hasło serwera MS SQL jest niepoprawne: %s.",
"You need to enter either an existing account or the administrator." => "Należy wprowadzić istniejące konto użytkownika lub administratora.",
-"Oracle username and/or password not valid" => "Oracle: Nazwa użytkownika i/lub hasło jest niepoprawne",
"MySQL username and/or password not valid" => "MySQL: Nazwa użytkownika i/lub hasło jest niepoprawne",
"DB Error: \"%s\"" => "Błąd DB: \"%s\"",
"Offending command was: \"%s\"" => "Niepoprawna komenda: \"%s\"",
@@ -33,24 +29,25 @@
"Drop this user from MySQL" => "Usuń tego użytkownika z MySQL",
"MySQL user '%s'@'%%' already exists" => "Użytkownik MySQL '%s'@'%%t' już istnieje",
"Drop this user from MySQL." => "Usuń tego użytkownika z MySQL.",
+"Oracle connection could not be established" => "Nie można ustanowić połączenia z bazą Oracle",
+"Oracle username and/or password not valid" => "Oracle: Nazwa użytkownika i/lub hasło jest niepoprawne",
"Offending command was: \"%s\", name: %s, password: %s" => "Niepoprawne polecania: \"%s\", nazwa: %s, hasło: %s",
-"MS SQL username and/or password not valid: %s" => "Nazwa i/lub hasło serwera MS SQL jest niepoprawne: %s.",
-"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serwer www nie jest jeszcze poprawnie ustawiony, aby umożliwić synchronizację plików, ponieważ interfejs WebDAV wydaje się być uszkodzony. Sprawdź ustawienia serwera.",
-"Please double check the <a href='%s'>installation guides</a>." => "Proszę sprawdź ponownie <a href='%s'>przewodnik instalacji</a>.",
+"PostgreSQL username and/or password not valid" => "PostgreSQL: Nazwa użytkownika i/lub hasło jest niepoprawne",
+"Set an admin username." => "Ustaw nazwę administratora.",
+"Set an admin password." => "Ustaw hasło administratora.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serwer internetowy nie jest jeszcze poprawnie skonfigurowany, aby umożliwić synchronizację plików, ponieważ interfejs WebDAV wydaje się być uszkodzony.",
+"Please double check the <a href='%s'>installation guides</a>." => "Sprawdź ponownie <a href='%s'>przewodniki instalacji</a>.",
"seconds ago" => "sekund temu",
"1 minute ago" => "1 minutę temu",
"%d minutes ago" => "%d minut temu",
-"1 hour ago" => "1 godzine temu",
+"1 hour ago" => "1 godzinę temu",
"%d hours ago" => "%d godzin temu",
-"today" => "dzisiaj",
+"today" => "dziś",
"yesterday" => "wczoraj",
"%d days ago" => "%d dni temu",
-"last month" => "ostatni miesiąc",
+"last month" => "w zeszłym miesiącu",
"%d months ago" => "%d miesiecy temu",
-"last year" => "ostatni rok",
+"last year" => "w zeszłym roku",
"years ago" => "lat temu",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s jest dostępna. Uzyskaj <a href=\"%s\">więcej informacji</a>",
-"up to date" => "Aktualne",
-"updates check is disabled" => "wybór aktualizacji jest wyłączony",
"Could not find category \"%s\"" => "Nie można odnaleźć kategorii \"%s\""
);
diff --git a/lib/l10n/pt_BR.php b/lib/l10n/pt_BR.php
index d4f410d8885..029331fdec8 100644
--- a/lib/l10n/pt_BR.php
+++ b/lib/l10n/pt_BR.php
@@ -5,6 +5,7 @@
"Users" => "Usuários",
"Apps" => "Aplicações",
"Admin" => "Admin",
+"web services under your control" => "serviços web sob seu controle",
"ZIP download is turned off." => "Download ZIP está desligado.",
"Files need to be downloaded one by one." => "Arquivos precisam ser baixados um de cada vez.",
"Back to Files" => "Voltar para Arquivos",
@@ -16,16 +17,11 @@
"Files" => "Arquivos",
"Text" => "Texto",
"Images" => "Imagens",
-"Set an admin username." => "Defina um nome de usuário de administrador.",
-"Set an admin password." => "Defina uma senha de administrador.",
-"Specify a data folder." => "Especifique uma pasta de dados.",
"%s enter the database username." => "%s insira o nome de usuário do banco de dados.",
"%s enter the database name." => "%s insira o nome do banco de dados.",
"%s you may not use dots in the database name" => "%s você não pode usar pontos no nome do banco de dados",
-"%s set the database host." => "%s defina o host do banco de dados.",
-"PostgreSQL username and/or password not valid" => "Nome de usuário e/ou senha PostgreSQL inválido(s)",
+"MS SQL username and/or password not valid: %s" => "Nome de usuário e/ou senha MS SQL inválido(s): %s",
"You need to enter either an existing account or the administrator." => "Você precisa inserir uma conta existente ou o administrador.",
-"Oracle username and/or password not valid" => "Nome de usuário e/ou senha Oracle inválido(s)",
"MySQL username and/or password not valid" => "Nome de usuário e/ou senha MySQL inválido(s)",
"DB Error: \"%s\"" => "Erro no BD: \"%s\"",
"Offending command was: \"%s\"" => "Comando ofensivo era: \"%s\"",
@@ -33,8 +29,12 @@
"Drop this user from MySQL" => "Derrubar este usuário do MySQL",
"MySQL user '%s'@'%%' already exists" => "Usuário MySQL '%s'@'%%' já existe",
"Drop this user from MySQL." => "Derrube este usuário do MySQL.",
+"Oracle connection could not be established" => "Conexão Oracle não pode ser estabelecida",
+"Oracle username and/or password not valid" => "Nome de usuário e/ou senha Oracle inválido(s)",
"Offending command was: \"%s\", name: %s, password: %s" => "Comando ofensivo era: \"%s\", nome: %s, senha: %s",
-"MS SQL username and/or password not valid: %s" => "Nome de usuário e/ou senha MS SQL inválido(s): %s",
+"PostgreSQL username and/or password not valid" => "Nome de usuário e/ou senha PostgreSQL inválido(s)",
+"Set an admin username." => "Defina um nome de usuário de administrador.",
+"Set an admin password." => "Defina uma senha de administrador.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Seu servidor web não está configurado corretamente para permitir sincronização de arquivos porque a interface WebDAV parece estar quebrada.",
"Please double check the <a href='%s'>installation guides</a>." => "Por favor, confira os <a href='%s'>guias de instalação</a>.",
"seconds ago" => "segundos atrás",
@@ -49,8 +49,5 @@
"%d months ago" => "%d meses atrás",
"last year" => "último ano",
"years ago" => "anos atrás",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponível. Obtenha <a href=\"%s\">mais informações</a>",
-"up to date" => "atualizado",
-"updates check is disabled" => "checagens de atualização estão desativadas",
"Could not find category \"%s\"" => "Impossível localizar categoria \"%s\""
);
diff --git a/lib/l10n/pt_PT.php b/lib/l10n/pt_PT.php
index 2c813f5b07c..7480026e920 100644
--- a/lib/l10n/pt_PT.php
+++ b/lib/l10n/pt_PT.php
@@ -5,6 +5,7 @@
"Users" => "Utilizadores",
"Apps" => "Aplicações",
"Admin" => "Admin",
+"web services under your control" => "serviços web sob o seu controlo",
"ZIP download is turned off." => "Descarregamento em ZIP está desligado.",
"Files need to be downloaded one by one." => "Os ficheiros precisam de ser descarregados um por um.",
"Back to Files" => "Voltar a Ficheiros",
@@ -16,16 +17,11 @@
"Files" => "Ficheiros",
"Text" => "Texto",
"Images" => "Imagens",
-"Set an admin username." => "Definir um nome de utilizador de administrador",
-"Set an admin password." => "Definiar uma password de administrador",
-"Specify a data folder." => "Especificar a pasta para os dados.",
"%s enter the database username." => "%s introduza o nome de utilizador da base de dados",
"%s enter the database name." => "%s introduza o nome da base de dados",
"%s you may not use dots in the database name" => "%s não é permitido utilizar pontos (.) no nome da base de dados",
-"%s set the database host." => "%s defina o servidor da base de dados (geralmente localhost)",
-"PostgreSQL username and/or password not valid" => "Nome de utilizador/password do PostgreSQL inválido",
+"MS SQL username and/or password not valid: %s" => "Nome de utilizador/password do MySQL é inválido: %s",
"You need to enter either an existing account or the administrator." => "Precisa de introduzir uma conta existente ou de administrador",
-"Oracle username and/or password not valid" => "Nome de utilizador/password do Oracle inválida",
"MySQL username and/or password not valid" => "Nome de utilizador/password do MySQL inválida",
"DB Error: \"%s\"" => "Erro na BD: \"%s\"",
"Offending command was: \"%s\"" => "O comando gerador de erro foi: \"%s\"",
@@ -33,24 +29,25 @@
"Drop this user from MySQL" => "Eliminar este utilizador do MySQL",
"MySQL user '%s'@'%%' already exists" => "O utilizador '%s'@'%%' do MySQL já existe",
"Drop this user from MySQL." => "Eliminar este utilizador do MySQL",
+"Oracle connection could not be established" => "Não foi possível estabelecer a ligação Oracle",
+"Oracle username and/or password not valid" => "Nome de utilizador/password do Oracle inválida",
"Offending command was: \"%s\", name: %s, password: %s" => "O comando gerador de erro foi: \"%s\", nome: %s, password: %s",
-"MS SQL username and/or password not valid: %s" => "Nome de utilizador/password do MySQL é inválido: %s",
+"PostgreSQL username and/or password not valid" => "Nome de utilizador/password do PostgreSQL inválido",
+"Set an admin username." => "Definir um nome de utilizador de administrador",
+"Set an admin password." => "Definiar uma password de administrador",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "O seu servidor web não está configurado correctamente para autorizar sincronização de ficheiros, pois o interface WebDAV parece estar com problemas.",
"Please double check the <a href='%s'>installation guides</a>." => "Por favor verifique <a href='%s'>installation guides</a>.",
-"seconds ago" => "há alguns segundos",
-"1 minute ago" => "há 1 minuto",
+"seconds ago" => "Minutos atrás",
+"1 minute ago" => "Há 1 minuto",
"%d minutes ago" => "há %d minutos",
"1 hour ago" => "Há 1 horas",
"%d hours ago" => "Há %d horas",
"today" => "hoje",
"yesterday" => "ontem",
"%d days ago" => "há %d dias",
-"last month" => "mês passado",
+"last month" => "ultímo mês",
"%d months ago" => "Há %d meses atrás",
"last year" => "ano passado",
-"years ago" => "há anos",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponível. Obtenha <a href=\"%s\">mais informação</a>",
-"up to date" => "actualizado",
-"updates check is disabled" => "a verificação de actualizações está desligada",
+"years ago" => "anos atrás",
"Could not find category \"%s\"" => "Não foi encontrado a categoria \"%s\""
);
diff --git a/lib/l10n/ro.php b/lib/l10n/ro.php
index 3f8e59cdac2..5a34e9571e5 100644
--- a/lib/l10n/ro.php
+++ b/lib/l10n/ro.php
@@ -5,6 +5,7 @@
"Users" => "Utilizatori",
"Apps" => "Aplicații",
"Admin" => "Admin",
+"web services under your control" => "servicii web controlate de tine",
"ZIP download is turned off." => "Descărcarea ZIP este dezactivată.",
"Files need to be downloaded one by one." => "Fișierele trebuie descărcate unul câte unul.",
"Back to Files" => "Înapoi la fișiere",
@@ -16,6 +17,8 @@
"Files" => "Fișiere",
"Text" => "Text",
"Images" => "Imagini",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serverul de web nu este încă setat corespunzător pentru a permite sincronizarea fișierelor deoarece interfața WebDAV pare a fi întreruptă.",
+"Please double check the <a href='%s'>installation guides</a>." => "Vă rugăm să verificați <a href='%s'>ghiduri de instalare</ a>.",
"seconds ago" => "secunde în urmă",
"1 minute ago" => "1 minut în urmă",
"%d minutes ago" => "%d minute în urmă",
@@ -28,8 +31,5 @@
"%d months ago" => "%d luni in urma",
"last year" => "ultimul an",
"years ago" => "ani în urmă",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s este disponibil. Vezi <a href=\"%s\">mai multe informații</a>",
-"up to date" => "la zi",
-"updates check is disabled" => "verificarea după actualizări este dezactivată",
"Could not find category \"%s\"" => "Cloud nu a gasit categoria \"%s\""
);
diff --git a/lib/l10n/ru.php b/lib/l10n/ru.php
index 25a88d5efc2..052b0487c6c 100644
--- a/lib/l10n/ru.php
+++ b/lib/l10n/ru.php
@@ -1,10 +1,11 @@
<?php $TRANSLATIONS = array(
"Help" => "Помощь",
"Personal" => "Личное",
-"Settings" => "Настройки",
+"Settings" => "Конфигурация",
"Users" => "Пользователи",
"Apps" => "Приложения",
"Admin" => "Admin",
+"web services under your control" => "веб-сервисы под вашим управлением",
"ZIP download is turned off." => "ZIP-скачивание отключено.",
"Files need to be downloaded one by one." => "Файлы должны быть загружены по одному.",
"Back to Files" => "Назад к файлам",
@@ -16,16 +17,11 @@
"Files" => "Файлы",
"Text" => "Текст",
"Images" => "Изображения",
-"Set an admin username." => "Установить имя пользователя для admin.",
-"Set an admin password." => "становит пароль для admin.",
-"Specify a data folder." => "Указать папку данных.",
"%s enter the database username." => "%s введите имя пользователя базы данных.",
"%s enter the database name." => "%s введите имя базы данных.",
"%s you may not use dots in the database name" => "%s Вы не можете использовать точки в имени базы данных",
-"%s set the database host." => "%s задайте хост базы данных.",
-"PostgreSQL username and/or password not valid" => "Неверное имя пользователя и/или пароль PostgreSQL",
+"MS SQL username and/or password not valid: %s" => "Имя пользователя и/или пароль MS SQL не подходит: %s",
"You need to enter either an existing account or the administrator." => "Вы должны войти или в существующий аккаунт или под администратором.",
-"Oracle username and/or password not valid" => "Неверное имя пользователя и/или пароль Oracle",
"MySQL username and/or password not valid" => "Неверное имя пользователя и/или пароль MySQL",
"DB Error: \"%s\"" => "Ошибка БД: \"%s\"",
"Offending command was: \"%s\"" => "Вызываемая команда была: \"%s\"",
@@ -33,11 +29,15 @@
"Drop this user from MySQL" => "Удалить этого пользователя из MySQL",
"MySQL user '%s'@'%%' already exists" => "Пользователь MySQL '%s'@'%%' уже существует",
"Drop this user from MySQL." => "Удалить этого пользователя из MySQL.",
+"Oracle connection could not be established" => "соединение с Oracle не может быть установлено",
+"Oracle username and/or password not valid" => "Неверное имя пользователя и/или пароль Oracle",
"Offending command was: \"%s\", name: %s, password: %s" => "Вызываемая команда была: \"%s\", имя: %s, пароль: %s",
-"MS SQL username and/or password not valid: %s" => "Имя пользователя и/или пароль MS SQL не подходит: %s",
+"PostgreSQL username and/or password not valid" => "Неверное имя пользователя и/или пароль PostgreSQL",
+"Set an admin username." => "Установить имя пользователя для admin.",
+"Set an admin password." => "становит пароль для admin.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш веб сервер до сих пор не настроен правильно для возможности синхронизации файлов, похоже что проблема в неисправности интерфейса WebDAV.",
"Please double check the <a href='%s'>installation guides</a>." => "Пожалуйста, дважды просмотрите <a href='%s'>инструкции по установке</a>.",
-"seconds ago" => "менее минуты",
+"seconds ago" => "несколько секунд назад",
"1 minute ago" => "1 минуту назад",
"%d minutes ago" => "%d минут назад",
"1 hour ago" => "час назад",
@@ -48,9 +48,6 @@
"last month" => "в прошлом месяце",
"%d months ago" => "%d месяцев назад",
"last year" => "в прошлом году",
-"years ago" => "годы назад",
-"%s is available. Get <a href=\"%s\">more information</a>" => "Возможно обновление до %s. <a href=\"%s\">Подробнее</a>",
-"up to date" => "актуальная версия",
-"updates check is disabled" => "проверка обновлений отключена",
+"years ago" => "несколько лет назад",
"Could not find category \"%s\"" => "Категория \"%s\" не найдена"
);
diff --git a/lib/l10n/ru_RU.php b/lib/l10n/ru_RU.php
index de770563662..7639a3cc97e 100644
--- a/lib/l10n/ru_RU.php
+++ b/lib/l10n/ru_RU.php
@@ -1,37 +1,4 @@
<?php $TRANSLATIONS = array(
-"Help" => "Помощь",
-"Personal" => "Персональный",
"Settings" => "Настройки",
-"Users" => "Пользователи",
-"Apps" => "Приложения",
-"Admin" => "Админ",
-"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-архива.",
-"couldn't be determined" => "не может быть определено",
-"Application is not enabled" => "Приложение не запущено",
-"Authentication error" => "Ошибка аутентификации",
-"Token expired. Please reload page." => "Маркер истек. Пожалуйста, перезагрузите страницу.",
-"Files" => "Файлы",
-"Text" => "Текст",
-"Images" => "Изображения",
-"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш веб сервер ещё не достаточно точно настроен для возможности синхронизации, т.к. похоже, что интерфейс WebDAV сломан.",
-"Please double check the <a href='%s'>installation guides</a>." => "Пожалуйста проверте дважды <a href='%s'>гиды по установке</a>.",
-"seconds ago" => "секунд назад",
-"1 minute ago" => "1 минуту назад",
-"%d minutes ago" => "%d минут назад",
-"1 hour ago" => "1 час назад",
-"%d hours ago" => "%d часов назад",
-"today" => "сегодня",
-"yesterday" => "вчера",
-"%d days ago" => "%d дней назад",
-"last month" => "в прошлом месяце",
-"%d months ago" => "%d месяцев назад",
-"last year" => "в прошлом году",
-"years ago" => "год назад",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s доступно. Получите <a href=\"%s\">more information</a>",
-"up to date" => "до настоящего времени",
-"updates check is disabled" => "Проверка обновлений отключена",
-"Could not find category \"%s\"" => "Не удалось найти категорию \"%s\""
+"Text" => "Текст"
);
diff --git a/lib/l10n/si_LK.php b/lib/l10n/si_LK.php
index 25624acf705..49ded7026e0 100644
--- a/lib/l10n/si_LK.php
+++ b/lib/l10n/si_LK.php
@@ -5,12 +5,13 @@
"Users" => "පරිශීලකයන්",
"Apps" => "යෙදුම්",
"Admin" => "පරිපාලක",
+"web services under your control" => "ඔබට පාලනය කළ හැකි වෙබ් සේවාවන්",
"ZIP download is turned off." => "ZIP භාගත කිරීම් අක්‍රියයි",
"Files need to be downloaded one by one." => "ගොනු එකින් එක භාගත යුතුයි",
"Back to Files" => "ගොනු වෙතට නැවත යන්න",
"Selected files too large to generate zip file." => "තෝරාගත් ගොනු ZIP ගොනුවක් තැනීමට විශාල වැඩිය.",
"Application is not enabled" => "යෙදුම සක්‍රිය කර නොමැත",
-"Authentication error" => "සත්‍යාපනය කිරීමේ දෝශයක්",
+"Authentication error" => "සත්‍යාපන දෝෂයක්",
"Token expired. Please reload page." => "ටෝකනය කල් ඉකුත් වී ඇත. පිටුව නැවුම් කරන්න",
"Files" => "ගොනු",
"Text" => "පෙළ",
@@ -23,8 +24,5 @@
"%d days ago" => "%d දිනකට පෙර",
"last month" => "පෙර මාසයේ",
"last year" => "පෙර අවුරුද්දේ",
-"years ago" => "අවුරුදු කීපයකට පෙර",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s යොදාගත හැක. <a href=\"%s\">තව විස්තර</a> ලබාගන්න",
-"up to date" => "යාවත්කාලීනයි",
-"updates check is disabled" => "යාවත්කාලීන බව පරීක්ෂණය අක්‍රියයි"
+"years ago" => "අවුරුදු කීපයකට පෙර"
);
diff --git a/lib/l10n/sk_SK.php b/lib/l10n/sk_SK.php
index 8c9ce61622c..64ad1e540f3 100644
--- a/lib/l10n/sk_SK.php
+++ b/lib/l10n/sk_SK.php
@@ -5,6 +5,7 @@
"Users" => "Používatelia",
"Apps" => "Aplikácie",
"Admin" => "Administrátor",
+"web services under your control" => "webové služby pod Vašou kontrolou",
"ZIP download is turned off." => "Sťahovanie súborov ZIP je vypnuté.",
"Files need to be downloaded one by one." => "Súbory musia byť nahrávané jeden za druhým.",
"Back to Files" => "Späť na súbory",
@@ -16,16 +17,11 @@
"Files" => "Súbory",
"Text" => "Text",
"Images" => "Obrázky",
-"Set an admin username." => "Zadajte používateľské meno administrátora.",
-"Set an admin password." => "Zadajte heslo administrátora.",
-"Specify a data folder." => "Zadajte priečinok pre dáta.",
"%s enter the database username." => "Zadajte používateľské meno %s databázy..",
"%s enter the database name." => "Zadajte názov databázy pre %s databázy.",
"%s you may not use dots in the database name" => "V názve databázy %s nemôžete používať bodky",
-"%s set the database host." => "Zadajte názov počítača s databázou %s.",
-"PostgreSQL username and/or password not valid" => "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné",
+"MS SQL username and/or password not valid: %s" => "Používateľské meno, alebo heslo MS SQL nie je platné: %s",
"You need to enter either an existing account or the administrator." => "Musíte zadať jestvujúci účet alebo administrátora.",
-"Oracle username and/or password not valid" => "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné",
"MySQL username and/or password not valid" => "Používateľské meno a/alebo heslo pre MySQL databázu je neplatné",
"DB Error: \"%s\"" => "Chyba DB: \"%s\"",
"Offending command was: \"%s\"" => "Podozrivý príkaz bol: \"%s\"",
@@ -33,12 +29,16 @@
"Drop this user from MySQL" => "Zahodiť používateľa z MySQL.",
"MySQL user '%s'@'%%' already exists" => "Používateľ '%s'@'%%' už v MySQL existuje",
"Drop this user from MySQL." => "Zahodiť používateľa z MySQL.",
+"Oracle connection could not be established" => "Nie je možné pripojiť sa k Oracle",
+"Oracle username and/or password not valid" => "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné",
"Offending command was: \"%s\", name: %s, password: %s" => "Podozrivý príkaz bol: \"%s\", meno: %s, heslo: %s",
-"MS SQL username and/or password not valid: %s" => "Používateľské meno, alebo heslo MS SQL nie je platné: %s",
+"PostgreSQL username and/or password not valid" => "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné",
+"Set an admin username." => "Zadajte používateľské meno administrátora.",
+"Set an admin password." => "Zadajte heslo administrátora.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Váš webový server nie je správne nastavený na synchronizáciu, pretože rozhranie WebDAV je poškodené.",
"Please double check the <a href='%s'>installation guides</a>." => "Prosím skontrolujte <a href='%s'>inštalačnú príručku</a>.",
"seconds ago" => "pred sekundami",
-"1 minute ago" => "pred 1 minútou",
+"1 minute ago" => "pred minútou",
"%d minutes ago" => "pred %d minútami",
"1 hour ago" => "Pred 1 hodinou",
"%d hours ago" => "Pred %d hodinami.",
@@ -49,8 +49,5 @@
"%d months ago" => "Pred %d mesiacmi.",
"last year" => "minulý rok",
"years ago" => "pred rokmi",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s je dostupné. Získať <a href=\"%s\">pre viac informácií</a>",
-"up to date" => "aktuálny",
-"updates check is disabled" => "sledovanie aktualizácií je vypnuté",
"Could not find category \"%s\"" => "Nemožno nájsť danú kategóriu \"%s\""
);
diff --git a/lib/l10n/sl.php b/lib/l10n/sl.php
index c0363031979..a5b4decd61a 100644
--- a/lib/l10n/sl.php
+++ b/lib/l10n/sl.php
@@ -5,36 +5,36 @@
"Users" => "Uporabniki",
"Apps" => "Programi",
"Admin" => "Skrbništvo",
+"web services under your control" => "spletne storitve pod vašim nadzorom",
"ZIP download is turned off." => "Prejemanje datotek v paketu ZIP je onemogočeno.",
"Files need to be downloaded one by one." => "Datoteke je mogoče prejeti le posamično.",
"Back to Files" => "Nazaj na datoteke",
"Selected files too large to generate zip file." => "Izbrane datoteke so prevelike za ustvarjanje datoteke arhiva zip.",
"couldn't be determined" => "ni mogoče določiti",
"Application is not enabled" => "Program ni omogočen",
-"Authentication error" => "Napaka overitve",
+"Authentication error" => "Napaka pri overjanju",
"Token expired. Please reload page." => "Žeton je potekel. Stran je treba ponovno naložiti.",
"Files" => "Datoteke",
"Text" => "Besedilo",
"Images" => "Slike",
-"Set an admin username." => "Nastavi uporabniško ime skrbnika.",
-"Set an admin password." => "Nastavi geslo skrbnika.",
-"Specify a data folder." => "Določi podatkovno mapo.",
"%s enter the database username." => "%s - vnos uporabniškega imena podatkovne zbirke.",
"%s enter the database name." => "%s - vnos imena podatkovne zbirke.",
-"%s you may not use dots in the database name" => "%s - v imenu podatkovne zbirke ni dovoljeno vpisati pik.",
-"%s set the database host." => "%s - vnos gostitelja podatkovne zbirke.",
-"PostgreSQL username and/or password not valid" => "Uporabniško ime ali geslo PostgreSQL ni pravilno",
+"%s you may not use dots in the database name" => "%s - v imenu podatkovne zbirke ni dovoljeno uporabljati pik.",
+"MS SQL username and/or password not valid: %s" => "Uporabniško ime ali geslo MS SQL ni veljavno: %s",
"You need to enter either an existing account or the administrator." => "Prijaviti se je treba v obstoječi ali pa skrbniški račun.",
-"Oracle username and/or password not valid" => "Uporabniško ime ali geslo Oracle ni pravilno",
-"MySQL username and/or password not valid" => "Uporabniško ime ali geslo MySQL ni pravilno",
+"MySQL username and/or password not valid" => "Uporabniško ime ali geslo MySQL ni veljavno",
"DB Error: \"%s\"" => "Napaka podatkovne zbirke: \"%s\"",
"Offending command was: \"%s\"" => "Napačni ukaz je: \"%s\"",
"MySQL user '%s'@'localhost' exists already." => "Uporabnik MySQL '%s'@'localhost' že obstaja.",
"Drop this user from MySQL" => "Odstrani uporabnika s podatkovne zbirke MySQL",
"MySQL user '%s'@'%%' already exists" => "Uporabnik MySQL '%s'@'%%' že obstaja.",
"Drop this user from MySQL." => "Odstrani uporabnika s podatkovne zbirke MySQL",
+"Oracle connection could not be established" => "Povezava z bazo Oracle ni uspela.",
+"Oracle username and/or password not valid" => "Uporabniško ime ali geslo Oracle ni veljavno",
"Offending command was: \"%s\", name: %s, password: %s" => "Napačni ukaz je: \"%s\", ime: %s, geslo: %s",
-"MS SQL username and/or password not valid: %s" => "Uporabniško ime ali geslo MS SQL ni pravilno: %s",
+"PostgreSQL username and/or password not valid" => "Uporabniško ime ali geslo PostgreSQL ni veljavno",
+"Set an admin username." => "Nastavi uporabniško ime skrbnika.",
+"Set an admin password." => "Nastavi geslo skrbnika.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Spletni stražnik še ni ustrezno nastavljen in ne omogoča usklajevanja, saj je nastavitev WebDAV okvarjena.",
"Please double check the <a href='%s'>installation guides</a>." => "Preverite <a href='%s'>navodila namestitve</a>.",
"seconds ago" => "pred nekaj sekundami",
@@ -45,12 +45,9 @@
"today" => "danes",
"yesterday" => "včeraj",
"%d days ago" => "pred %d dnevi",
-"last month" => "prejšnji mesec",
+"last month" => "zadnji mesec",
"%d months ago" => "Pred %d meseci",
"last year" => "lansko leto",
-"years ago" => "pred nekaj leti",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s je na voljo. <a href=\"%s\">Več podrobnosti.</a>",
-"up to date" => "posodobljeno",
-"updates check is disabled" => "preverjanje za posodobitve je onemogočeno",
+"years ago" => "let nazaj",
"Could not find category \"%s\"" => "Kategorije \"%s\" ni mogoče najti."
);
diff --git a/lib/l10n/sq.php b/lib/l10n/sq.php
new file mode 100644
index 00000000000..df5e2a31743
--- /dev/null
+++ b/lib/l10n/sq.php
@@ -0,0 +1,52 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Ndihmë",
+"Personal" => "Personale",
+"Settings" => "Parametra",
+"Users" => "Përdoruesit",
+"Apps" => "App",
+"Admin" => "Admin",
+"web services under your control" => "shërbime web nën kontrollin tënd",
+"ZIP download is turned off." => "Shkarimi i skedarëve ZIP është i çaktivizuar.",
+"Files need to be downloaded one by one." => "Skedarët duhet të shkarkohen një nga një.",
+"Back to Files" => "Kthehu tek skedarët",
+"Selected files too large to generate zip file." => "Skedarët e selektuar janë shumë të mëdhenj për të krijuar një skedar ZIP.",
+"couldn't be determined" => "nuk u vendos dot",
+"Application is not enabled" => "Programi nuk është i aktivizuar.",
+"Authentication error" => "Veprim i gabuar gjatë vërtetimit të identitetit",
+"Token expired. Please reload page." => "Përmbajtja ka skaduar. Ju lutemi ringarkoni faqen.",
+"Files" => "Skedarët",
+"Text" => "Tekst",
+"Images" => "Foto",
+"%s enter the database username." => "% shkruani përdoruesin e database-it.",
+"%s enter the database name." => "%s shkruani emrin e database-it.",
+"%s you may not use dots in the database name" => "%s nuk mund të përdorni pikat tek emri i database-it",
+"MS SQL username and/or password not valid: %s" => "Përdoruesi dhe/apo kodi i MS SQL i pavlefshëm: %s",
+"You need to enter either an existing account or the administrator." => "Duhet të përdorni një llogari ekzistuese ose llogarinë e administratorit.",
+"MySQL username and/or password not valid" => "Përdoruesi dhe/apo kodi i MySQL-it i pavlefshëm.",
+"DB Error: \"%s\"" => "Veprim i gabuar i DB-it: \"%s\"",
+"Offending command was: \"%s\"" => "Komanda e gabuar ishte: \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "Përdoruesi MySQL '%s'@'localhost' ekziston.",
+"Drop this user from MySQL" => "Eliminoni këtë përdorues nga MySQL",
+"MySQL user '%s'@'%%' already exists" => "Përdoruesi MySQL '%s'@'%%' ekziston",
+"Drop this user from MySQL." => "Eliminoni këtë përdorues nga MySQL.",
+"Oracle username and/or password not valid" => "Përdoruesi dhe/apo kodi i Oracle-it i pavlefshëm",
+"Offending command was: \"%s\", name: %s, password: %s" => "Komanda e gabuar ishte: \"%s\", përdoruesi: %s, kodi: %s",
+"PostgreSQL username and/or password not valid" => "Përdoruesi dhe/apo kodi i PostgreSQL i pavlefshëm",
+"Set an admin username." => "Cakto emrin e administratorit.",
+"Set an admin password." => "Cakto kodin e administratorit.",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Serveri web i juaji nuk është konfiguruar akoma për të lejuar sinkronizimin e skedarëve sepse ndërfaqja WebDAV mund të jetë e dëmtuar.",
+"Please double check the <a href='%s'>installation guides</a>." => "Ju lutemi kontrolloni mirë <a href='%s'>shoqëruesin e instalimit</a>.",
+"seconds ago" => "sekonda më parë",
+"1 minute ago" => "1 minutë më parë",
+"%d minutes ago" => "%d minuta më parë",
+"1 hour ago" => "1 orë më parë",
+"%d hours ago" => "%d orë më parë",
+"today" => "sot",
+"yesterday" => "dje",
+"%d days ago" => "%d ditë më parë",
+"last month" => "muajin e shkuar",
+"%d months ago" => "%d 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.php b/lib/l10n/sr.php
index 1161b0a44b7..71d627e7890 100644
--- a/lib/l10n/sr.php
+++ b/lib/l10n/sr.php
@@ -5,6 +5,7 @@
"Users" => "Корисници",
"Apps" => "Апликације",
"Admin" => "Администратор",
+"web services under your control" => "веб сервиси под контролом",
"ZIP download is turned off." => "Преузимање ZIP-а је искључено.",
"Files need to be downloaded one by one." => "Датотеке морате преузимати једну по једну.",
"Back to Files" => "Назад на датотеке",
@@ -16,10 +17,12 @@
"Files" => "Датотеке",
"Text" => "Текст",
"Images" => "Слике",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш веб сервер тренутно не подржава синхронизацију датотека јер се чини да је WebDAV сучеље неисправно.",
+"Please double check the <a href='%s'>installation guides</a>." => "Погледајте <a href='%s'>водиче за инсталацију</a>.",
"seconds ago" => "пре неколико секунди",
"1 minute ago" => "пре 1 минут",
"%d minutes ago" => "пре %d минута",
-"1 hour ago" => "пре 1 сат",
+"1 hour ago" => "Пре једног сата",
"%d hours ago" => "пре %d сата/и",
"today" => "данас",
"yesterday" => "јуче",
@@ -28,8 +31,5 @@
"%d months ago" => "пре %d месеца/и",
"last year" => "прошле године",
"years ago" => "година раније",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s је доступна. Погледајте <a href=\"%s\">више информација</a>.",
-"up to date" => "је ажурна",
-"updates check is disabled" => "провера ажурирања је онемогућена",
"Could not find category \"%s\"" => "Не могу да пронађем категорију „%s“."
);
diff --git a/lib/l10n/sr@latin.php b/lib/l10n/sr@latin.php
index 3fc1f61eafa..13cedc83279 100644
--- a/lib/l10n/sr@latin.php
+++ b/lib/l10n/sr@latin.php
@@ -3,6 +3,8 @@
"Personal" => "Lično",
"Settings" => "Podešavanja",
"Users" => "Korisnici",
+"Apps" => "Programi",
+"Admin" => "Adninistracija",
"Authentication error" => "Greška pri autentifikaciji",
"Files" => "Fajlovi",
"Text" => "Tekst"
diff --git a/lib/l10n/sv.php b/lib/l10n/sv.php
index 63ca60e89cd..56776e574aa 100644
--- a/lib/l10n/sv.php
+++ b/lib/l10n/sv.php
@@ -5,6 +5,7 @@
"Users" => "Användare",
"Apps" => "Program",
"Admin" => "Admin",
+"web services under your control" => "webbtjänster under din kontroll",
"ZIP download is turned off." => "Nerladdning av ZIP är avstängd.",
"Files need to be downloaded one by one." => "Filer laddas ner en åt gången.",
"Back to Files" => "Tillbaka till Filer",
@@ -16,6 +17,24 @@
"Files" => "Filer",
"Text" => "Text",
"Images" => "Bilder",
+"%s enter the database username." => "%s ange databasanvändare.",
+"%s enter the database name." => "%s ange databasnamn",
+"%s you may not use dots in the database name" => "%s du får inte använda punkter i databasnamnet",
+"MS SQL username and/or password not valid: %s" => "MS SQL-användaren och/eller lösenordet var inte giltigt: %s",
+"You need to enter either an existing account or the administrator." => "Du måste antingen ange ett befintligt konto eller administratör.",
+"MySQL username and/or password not valid" => "MySQL-användarnamnet och/eller lösenordet är felaktigt",
+"DB Error: \"%s\"" => "DB error: \"%s\"",
+"Offending command was: \"%s\"" => "Det felaktiga kommandot var: \"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "MySQL-användaren '%s'@'localhost' existerar redan.",
+"Drop this user from MySQL" => "Radera denna användare från MySQL",
+"MySQL user '%s'@'%%' already exists" => "MySQl-användare '%s'@'%%' existerar redan",
+"Drop this user from MySQL." => "Radera denna användare från MySQL.",
+"Oracle connection could not be established" => "Oracle-anslutning kunde inte etableras",
+"Oracle username and/or password not valid" => "Oracle-användarnamnet och/eller lösenordet är felaktigt",
+"Offending command was: \"%s\", name: %s, password: %s" => "Det felande kommandot var: \"%s\", name: %s, password: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt",
+"Set an admin username." => "Ange ett användarnamn för administratören.",
+"Set an admin password." => "Ange ett administratörslösenord.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Din webbserver är inte korrekt konfigurerad för att tillåta filsynkronisering eftersom WebDAV inte verkar fungera.",
"Please double check the <a href='%s'>installation guides</a>." => "Var god kontrollera <a href='%s'>installationsguiden</a>.",
"seconds ago" => "sekunder sedan",
@@ -23,15 +42,12 @@
"%d minutes ago" => "%d minuter sedan",
"1 hour ago" => "1 timme sedan",
"%d hours ago" => "%d timmar sedan",
-"today" => "idag",
-"yesterday" => "igår",
+"today" => "i dag",
+"yesterday" => "i går",
"%d days ago" => "%d dagar sedan",
"last month" => "förra månaden",
"%d months ago" => "%d månader sedan",
"last year" => "förra året",
"years ago" => "år sedan",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s finns. Få <a href=\"%s\">mer information</a>",
-"up to date" => "uppdaterad",
-"updates check is disabled" => "uppdateringskontroll är inaktiverad",
"Could not find category \"%s\"" => "Kunde inte hitta kategorin \"%s\""
);
diff --git a/lib/l10n/ta_LK.php b/lib/l10n/ta_LK.php
index c76394bcb4f..9193f6f1d2f 100644
--- a/lib/l10n/ta_LK.php
+++ b/lib/l10n/ta_LK.php
@@ -2,9 +2,10 @@
"Help" => "உதவி",
"Personal" => "தனிப்பட்ட",
"Settings" => "அமைப்புகள்",
-"Users" => "பயனாளர்கள்",
+"Users" => "பயனாளர்",
"Apps" => "செயலிகள்",
"Admin" => "நிர்வாகம்",
+"web services under your control" => "வலைய சேவைகள் உங்களுடைய கட்டுப்பாட்டின் கீழ் உள்ளது",
"ZIP download is turned off." => "வீசொலிப் பூட்டு பதிவிறக்கம் நிறுத்தப்பட்டுள்ளது.",
"Files need to be downloaded one by one." => "கோப்புகள்ஒன்றன் பின் ஒன்றாக பதிவிறக்கப்படவேண்டும்.",
"Back to Files" => "கோப்புகளுக்கு செல்க",
@@ -27,8 +28,5 @@
"%d months ago" => "%d மாதத்திற்கு முன்",
"last year" => "கடந்த வருடம்",
"years ago" => "வருடங்களுக்கு முன்",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s இன்னும் இருக்கின்றன. <a href=\"%s\">மேலதிக தகவல்களுக்கு</a> எடுக்க",
-"up to date" => "நவீன",
-"updates check is disabled" => "இற்றைப்படுத்தலை சரிபார்ப்பதை செயலற்றதாக்குக",
"Could not find category \"%s\"" => "பிரிவு \"%s\" ஐ கண்டுப்பிடிக்க முடியவில்லை"
);
diff --git a/lib/l10n/te.php b/lib/l10n/te.php
new file mode 100644
index 00000000000..87c73d790e2
--- /dev/null
+++ b/lib/l10n/te.php
@@ -0,0 +1,13 @@
+<?php $TRANSLATIONS = array(
+"Help" => "సహాయం",
+"Settings" => "అమరికలు",
+"Users" => "వాడుకరులు",
+"seconds ago" => "క్షణాల క్రితం",
+"1 minute ago" => "1 నిమిషం క్రితం",
+"1 hour ago" => "1 గంట క్రితం",
+"today" => "ఈరోజు",
+"yesterday" => "నిన్న",
+"last month" => "పోయిన నెల",
+"last year" => "పోయిన సంవత్సరం",
+"years ago" => "సంవత్సరాల క్రితం"
+);
diff --git a/lib/l10n/th_TH.php b/lib/l10n/th_TH.php
index 0da607a0589..4ec6ef55f4e 100644
--- a/lib/l10n/th_TH.php
+++ b/lib/l10n/th_TH.php
@@ -5,6 +5,7 @@
"Users" => "ผู้ใช้งาน",
"Apps" => "แอปฯ",
"Admin" => "ผู้ดูแล",
+"web services under your control" => "เว็บเซอร์วิสที่คุณควบคุมการใช้งานได้",
"ZIP download is turned off." => "คุณสมบัติการดาวน์โหลด zip ถูกปิดการใช้งานไว้",
"Files need to be downloaded one by one." => "ไฟล์สามารถดาวน์โหลดได้ทีละครั้งเท่านั้น",
"Back to Files" => "กลับไปที่ไฟล์",
@@ -16,8 +17,8 @@
"Files" => "ไฟล์",
"Text" => "ข้อความ",
"Images" => "รูปภาพ",
-"seconds ago" => "วินาทีที่ผ่านมา",
-"1 minute ago" => "1 นาทีมาแล้ว",
+"seconds ago" => "วินาที ก่อนหน้านี้",
+"1 minute ago" => "1 นาทีก่อนหน้านี้",
"%d minutes ago" => "%d นาทีที่ผ่านมา",
"1 hour ago" => "1 ชั่วโมงก่อนหน้านี้",
"%d hours ago" => "%d ชั่วโมงก่อนหน้านี้",
@@ -27,9 +28,6 @@
"last month" => "เดือนที่แล้ว",
"%d months ago" => "%d เดือนมาแล้ว",
"last year" => "ปีที่แล้ว",
-"years ago" => "ปีที่ผ่านมา",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s พร้อมให้ใช้งานได้แล้ว. <a href=\"%s\">ดูรายละเอียดเพิ่มเติม</a>",
-"up to date" => "ทันสมัย",
-"updates check is disabled" => "การตรวจสอบชุดอัพเดทถูกปิดใช้งานไว้",
+"years ago" => "ปี ที่ผ่านมา",
"Could not find category \"%s\"" => "ไม่พบหมวดหมู่ \"%s\""
);
diff --git a/lib/l10n/tr.php b/lib/l10n/tr.php
index ab237cfe2e7..6325ad9886a 100644
--- a/lib/l10n/tr.php
+++ b/lib/l10n/tr.php
@@ -1,10 +1,11 @@
<?php $TRANSLATIONS = array(
-"Help" => "Yardı",
+"Help" => "Yardım",
"Personal" => "Kişisel",
"Settings" => "Ayarlar",
"Users" => "Kullanıcılar",
"Apps" => "Uygulamalar",
"Admin" => "Yönetici",
+"web services under your control" => "Bilgileriniz güvenli ve şifreli",
"ZIP download is turned off." => "ZIP indirmeleri kapatılmıştır.",
"Files need to be downloaded one by one." => "Dosyaların birer birer indirilmesi gerekmektedir.",
"Back to Files" => "Dosyalara dön",
@@ -16,7 +17,26 @@
"Files" => "Dosyalar",
"Text" => "Metin",
"Images" => "Resimler",
+"%s enter the database username." => "%s veritabanı kullanıcı adını gir.",
+"%s enter the database name." => "%s veritabanı adını gir.",
+"%s you may not use dots in the database name" => "%s veritabanı adında nokta kullanamayabilirsiniz",
+"MS SQL username and/or password not valid: %s" => "MS SQL kullanıcı adı ve/veya parolası geçersiz: %s",
+"You need to enter either an existing account or the administrator." => "Bir konto veya kullanici birlemek ihtiyacin. ",
+"MySQL username and/or password not valid" => "MySQL kullanıcı adı ve/veya parolası geçerli değil",
+"DB Error: \"%s\"" => "DB Hata: ''%s''",
+"Offending command was: \"%s\"" => "Komut rahasiz ''%s''. ",
+"MySQL user '%s'@'localhost' exists already." => "MySQL kullanici '%s @local host zatan var. ",
+"Drop this user from MySQL" => "Bu kullanici MySQLden list disari koymak. ",
+"MySQL user '%s'@'%%' already exists" => "MySQL kullanici '%s @ % % zaten var (zaten yazili)",
+"Drop this user from MySQL." => "Bu kulanıcıyı MySQL veritabanından kaldır",
+"Oracle connection could not be established" => "Oracle bağlantısı kurulamadı",
+"Oracle username and/or password not valid" => "Adi klullanici ve/veya parola Oracle mantikli değildir. ",
+"Offending command was: \"%s\", name: %s, password: %s" => "Hatalı komut: \"%s\", ad: %s, parola: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL adi kullanici ve/veya parola yasal degildir. ",
+"Set an admin username." => "Bir adi kullanici vermek. ",
+"Set an admin password." => "Parola yonetici birlemek. ",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Web sunucunuz dosya transferi için düzgün bir şekilde yapılandırılmamış. WevDAV arabirimini sorunlu gözüküyor.",
+"Please double check the <a href='%s'>installation guides</a>." => "Lütfen <a href='%s'>kurulum kılavuzlarını</a> iki kez kontrol edin.",
"seconds ago" => "saniye önce",
"1 minute ago" => "1 dakika önce",
"%d minutes ago" => "%d dakika önce",
@@ -29,8 +49,5 @@
"%d months ago" => "%d ay önce",
"last year" => "geçen yıl",
"years ago" => "yıl önce",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s kullanılabilir durumda. <a href=\"%s\">Daha fazla bilgi</a> alın",
-"up to date" => "güncel",
-"updates check is disabled" => "güncelleme kontrolü kapalı",
"Could not find category \"%s\"" => "\"%s\" kategorisi bulunamadı"
);
diff --git a/lib/l10n/ug.php b/lib/l10n/ug.php
new file mode 100644
index 00000000000..62d91616c1d
--- /dev/null
+++ b/lib/l10n/ug.php
@@ -0,0 +1,19 @@
+<?php $TRANSLATIONS = array(
+"Help" => "ياردەم",
+"Personal" => "شەخسىي",
+"Settings" => "تەڭشەكلەر",
+"Users" => "ئىشلەتكۈچىلەر",
+"Apps" => "ئەپلەر",
+"Authentication error" => "سالاھىيەت دەلىللەش خاتالىقى",
+"Files" => "ھۆججەتلەر",
+"Text" => "قىسقا ئۇچۇر",
+"Images" => "سۈرەتلەر",
+"1 minute ago" => "1 مىنۇت ئىلگىرى",
+"%d minutes ago" => "%d مىنۇت ئىلگىرى",
+"1 hour ago" => "1 سائەت ئىلگىرى",
+"%d hours ago" => "%d سائەت ئىلگىرى",
+"today" => "بۈگۈن",
+"yesterday" => "تۈنۈگۈن",
+"%d days ago" => "%d كۈن ئىلگىرى",
+"%d months ago" => "%d ئاي ئىلگىرى"
+);
diff --git a/lib/l10n/uk.php b/lib/l10n/uk.php
index 68f7151d15e..7ff7829e1a2 100644
--- a/lib/l10n/uk.php
+++ b/lib/l10n/uk.php
@@ -5,6 +5,7 @@
"Users" => "Користувачі",
"Apps" => "Додатки",
"Admin" => "Адмін",
+"web services under your control" => "підконтрольні Вам веб-сервіси",
"ZIP download is turned off." => "ZIP завантаження вимкнено.",
"Files need to be downloaded one by one." => "Файли повинні бути завантаженні послідовно.",
"Back to Files" => "Повернутися до файлів",
@@ -16,16 +17,11 @@
"Files" => "Файли",
"Text" => "Текст",
"Images" => "Зображення",
-"Set an admin username." => "Встановіть ім'я адміністратора.",
-"Set an admin password." => "Встановіть пароль адміністратора.",
-"Specify a data folder." => "Вкажіть теку для даних.",
"%s enter the database username." => "%s введіть ім'я користувача бази даних.",
"%s enter the database name." => "%s введіть назву бази даних.",
"%s you may not use dots in the database name" => "%s не можна використовувати крапки в назві бази даних",
-"%s set the database host." => "%s встановити хост бази даних.",
-"PostgreSQL username and/or password not valid" => "PostgreSQL ім'я користувача та/або пароль не дійсні",
+"MS SQL username and/or password not valid: %s" => "MS SQL ім'я користувача та/або пароль не дійсні: %s",
"You need to enter either an existing account or the administrator." => "Вам потрібно ввести або існуючий обліковий запис або administrator.",
-"Oracle username and/or password not valid" => "Oracle ім'я користувача та/або пароль не дійсні",
"MySQL username and/or password not valid" => "MySQL ім'я користувача та/або пароль не дійсні",
"DB Error: \"%s\"" => "Помилка БД: \"%s\"",
"Offending command was: \"%s\"" => "Команда, що викликала проблему: \"%s\"",
@@ -33,8 +29,11 @@
"Drop this user from MySQL" => "Видалити цього користувача з MySQL",
"MySQL user '%s'@'%%' already exists" => "Користувач MySQL '%s'@'%%' вже існує",
"Drop this user from MySQL." => "Видалити цього користувача з MySQL.",
+"Oracle username and/or password not valid" => "Oracle ім'я користувача та/або пароль не дійсні",
"Offending command was: \"%s\", name: %s, password: %s" => "Команда, що викликала проблему: \"%s\", ім'я: %s, пароль: %s",
-"MS SQL username and/or password not valid: %s" => "MS SQL ім'я користувача та/або пароль не дійсні: %s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL ім'я користувача та/або пароль не дійсні",
+"Set an admin username." => "Встановіть ім'я адміністратора.",
+"Set an admin password." => "Встановіть пароль адміністратора.",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ваш Web-сервер ще не налаштований належним чином для того, щоб дозволити синхронізацію файлів, через те що інтерфейс WebDAV, здається, зламаний.",
"Please double check the <a href='%s'>installation guides</a>." => "Будь ласка, перевірте <a href='%s'>інструкції по встановленню</a>.",
"seconds ago" => "секунди тому",
@@ -49,8 +48,5 @@
"%d months ago" => "%d місяців тому",
"last year" => "минулого року",
"years ago" => "роки тому",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s доступно. Отримати <a href=\"%s\">детальну інформацію</a>",
-"up to date" => "оновлено",
-"updates check is disabled" => "перевірка оновлень відключена",
"Could not find category \"%s\"" => "Не вдалося знайти категорію \"%s\""
);
diff --git a/lib/l10n/ur_PK.php b/lib/l10n/ur_PK.php
index 7e09d79bc68..21e711c6df5 100644
--- a/lib/l10n/ur_PK.php
+++ b/lib/l10n/ur_PK.php
@@ -4,5 +4,6 @@
"Settings" => "سیٹینگز",
"Users" => "یوزرز",
"Apps" => "ایپز",
-"Admin" => "ایڈمن"
+"Admin" => "ایڈمن",
+"web services under your control" => "آپ کے اختیار میں ویب سروسیز"
);
diff --git a/lib/l10n/vi.php b/lib/l10n/vi.php
index ea9660093ae..f2a7d669b8f 100644
--- a/lib/l10n/vi.php
+++ b/lib/l10n/vi.php
@@ -5,6 +5,7 @@
"Users" => "Người dùng",
"Apps" => "Ứng dụng",
"Admin" => "Quản trị",
+"web services under your control" => "dịch vụ web dưới sự kiểm soát của bạn",
"ZIP download is turned off." => "Tải về ZIP đã bị tắt.",
"Files need to be downloaded one by one." => "Tập tin cần phải được tải về từng người một.",
"Back to Files" => "Trở lại tập tin",
@@ -13,10 +14,10 @@
"Application is not enabled" => "Ứng dụng không được BẬT",
"Authentication error" => "Lỗi xác thực",
"Token expired. Please reload page." => "Mã Token đã hết hạn. Hãy tải lại trang.",
-"Files" => "Các tập tin",
+"Files" => "Tập tin",
"Text" => "Văn bản",
"Images" => "Hình ảnh",
-"seconds ago" => "1 giây trước",
+"seconds ago" => "vài giây trước",
"1 minute ago" => "1 phút trước",
"%d minutes ago" => "%d phút trước",
"1 hour ago" => "1 giờ trước",
@@ -28,8 +29,5 @@
"%d months ago" => "%d tháng trước",
"last year" => "năm trước",
"years ago" => "năm trước",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s có sẵn. <a href=\"%s\">xem thêm ở đây</a>",
-"up to date" => "đến ngày",
-"updates check is disabled" => "đã TĂT chức năng cập nhật ",
"Could not find category \"%s\"" => "không thể tìm thấy mục \"%s\""
);
diff --git a/lib/l10n/zh_CN.GB2312.php b/lib/l10n/zh_CN.GB2312.php
index 08975e44598..4780a69eb34 100644
--- a/lib/l10n/zh_CN.GB2312.php
+++ b/lib/l10n/zh_CN.GB2312.php
@@ -5,6 +5,7 @@
"Users" => "用户",
"Apps" => "程序",
"Admin" => "管理员",
+"web services under your control" => "您控制的网络服务",
"ZIP download is turned off." => "ZIP 下载已关闭",
"Files need to be downloaded one by one." => "需要逐个下载文件。",
"Back to Files" => "返回到文件",
@@ -15,16 +16,16 @@
"Files" => "文件",
"Text" => "文本",
"Images" => "图片",
+"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "因WebDAV接口故障,您的网络服务器好像并未允许文件同步。",
+"Please double check the <a href='%s'>installation guides</a>." => "请双击<a href='%s'>安装向导</a>。",
"seconds ago" => "秒前",
"1 minute ago" => "1 分钟前",
"%d minutes ago" => "%d 分钟前",
+"1 hour ago" => "1小时前",
"today" => "今天",
"yesterday" => "昨天",
"%d days ago" => "%d 天前",
"last month" => "上个月",
"last year" => "去年",
-"years ago" => "年前",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s 不可用。获知 <a href=\"%s\">详情</a>",
-"up to date" => "最新",
-"updates check is disabled" => "更新检测已禁用"
+"years ago" => "年前"
);
diff --git a/lib/l10n/zh_CN.php b/lib/l10n/zh_CN.php
index b79fdfcca1d..7630f885c4a 100644
--- a/lib/l10n/zh_CN.php
+++ b/lib/l10n/zh_CN.php
@@ -5,6 +5,7 @@
"Users" => "用户",
"Apps" => "应用",
"Admin" => "管理",
+"web services under your control" => "您控制的web服务",
"ZIP download is turned off." => "ZIP 下载已经关闭",
"Files need to be downloaded one by one." => "需要逐一下载文件",
"Back to Files" => "回到文件",
@@ -16,16 +17,11 @@
"Files" => "文件",
"Text" => "文本",
"Images" => "图片",
-"Set an admin username." => "请设置一个管理员用户名。",
-"Set an admin password." => "请设置一个管理员密码。",
-"Specify a data folder." => "请指定一个数据目录。",
"%s enter the database username." => "%s 输入数据库用户名。",
"%s enter the database name." => "%s 输入数据库名称。",
"%s you may not use dots in the database name" => "%s 您不能在数据库名称中使用英文句号。",
-"%s set the database host." => "%s 设置数据库所在主机。",
-"PostgreSQL username and/or password not valid" => "PostgreSQL 数据库用户名和/或密码无效",
+"MS SQL username and/or password not valid: %s" => "MS SQL 用户名和/或密码无效:%s",
"You need to enter either an existing account or the administrator." => "你需要输入一个数据库中已有的账户或管理员账户。",
-"Oracle username and/or password not valid" => "Oracle 数据库用户名和/或密码无效",
"MySQL username and/or password not valid" => "MySQL 数据库用户名和/或密码无效",
"DB Error: \"%s\"" => "数据库错误:\"%s\"",
"Offending command was: \"%s\"" => "冲突命令为:\"%s\"",
@@ -33,12 +29,16 @@
"Drop this user from MySQL" => "建议从 MySQL 数据库中丢弃 Drop 此用户",
"MySQL user '%s'@'%%' already exists" => "MySQL 用户 '%s'@'%%' 已存在",
"Drop this user from MySQL." => "建议从 MySQL 数据库中丢弃 Drop 此用户。",
+"Oracle connection could not be established" => "不能建立甲骨文连接",
+"Oracle username and/or password not valid" => "Oracle 数据库用户名和/或密码无效",
"Offending command was: \"%s\", name: %s, password: %s" => "冲突命令为:\"%s\",名称:%s,密码:%s",
-"MS SQL username and/or password not valid: %s" => "MS SQL 用户名和/或密码无效:%s",
+"PostgreSQL username and/or password not valid" => "PostgreSQL 数据库用户名和/或密码无效",
+"Set an admin username." => "请设置一个管理员用户名。",
+"Set an admin password." => "请设置一个管理员密码。",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "您的Web服务器尚未正确设置以允许文件同步, 因为WebDAV的接口似乎已损坏.",
"Please double check the <a href='%s'>installation guides</a>." => "请认真检查<a href='%s'>安装指南</a>.",
-"seconds ago" => "几秒前",
-"1 minute ago" => "1分钟前",
+"seconds ago" => "秒前",
+"1 minute ago" => "一分钟前",
"%d minutes ago" => "%d 分钟前",
"1 hour ago" => "1小时前",
"%d hours ago" => "%d小时前",
@@ -48,9 +48,6 @@
"last month" => "上月",
"%d months ago" => "%d 月前",
"last year" => "去年",
-"years ago" => "几年前",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s 已存在。点此 <a href=\"%s\">获取更多信息</a>",
-"up to date" => "已更新。",
-"updates check is disabled" => "更新检查功能被禁用。",
+"years ago" => "年前",
"Could not find category \"%s\"" => "无法找到分类 \"%s\""
);
diff --git a/lib/l10n/zh_TW.php b/lib/l10n/zh_TW.php
index 91b0329e246..afd196f7c82 100644
--- a/lib/l10n/zh_TW.php
+++ b/lib/l10n/zh_TW.php
@@ -5,10 +5,11 @@
"Users" => "使用者",
"Apps" => "應用程式",
"Admin" => "管理",
-"ZIP download is turned off." => "ZIP 下載已關閉",
-"Files need to be downloaded one by one." => "檔案需要逐一下載",
+"web services under your control" => "由您控制的網路服務",
+"ZIP download is turned off." => "ZIP 下載已關閉。",
+"Files need to be downloaded one by one." => "檔案需要逐一下載。",
"Back to Files" => "回到檔案列表",
-"Selected files too large to generate zip file." => "選擇的檔案太大以致於無法產生壓縮檔",
+"Selected files too large to generate zip file." => "選擇的檔案太大以致於無法產生壓縮檔。",
"couldn't be determined" => "無法判斷",
"Application is not enabled" => "應用程式未啟用",
"Authentication error" => "認證錯誤",
@@ -16,6 +17,24 @@
"Files" => "檔案",
"Text" => "文字",
"Images" => "圖片",
+"%s enter the database username." => "%s 輸入資料庫使用者名稱。",
+"%s enter the database name." => "%s 輸入資料庫名稱。",
+"%s you may not use dots in the database name" => "%s 資料庫名稱不能包含小數點",
+"MS SQL username and/or password not valid: %s" => "MS SQL 使用者和/或密碼無效:%s",
+"You need to enter either an existing account or the administrator." => "您必須輸入一個現有的帳號或管理員帳號。",
+"MySQL username and/or password not valid" => "MySQL 用戶名和/或密碼無效",
+"DB Error: \"%s\"" => "資料庫錯誤:\"%s\"",
+"Offending command was: \"%s\"" => "有問題的指令是:\"%s\"",
+"MySQL user '%s'@'localhost' exists already." => "MySQL 使用者 '%s'@'localhost' 已經存在。",
+"Drop this user from MySQL" => "在 MySQL 移除這個使用者",
+"MySQL user '%s'@'%%' already exists" => "MySQL 使用者 '%s'@'%%' 已經存在",
+"Drop this user from MySQL." => "在 MySQL 移除這個使用者。",
+"Oracle connection could not be established" => "無法建立 Oracle 資料庫連線",
+"Oracle username and/or password not valid" => "Oracle 用戶名和/或密碼無效",
+"Offending command was: \"%s\", name: %s, password: %s" => "有問題的指令是:\"%s\" ,使用者:\"%s\",密碼:\"%s\"",
+"PostgreSQL username and/or password not valid" => "PostgreSQL 用戶名和/或密碼無效",
+"Set an admin username." => "設定管理員帳號。",
+"Set an admin password." => "設定管理員密碼。",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "您的網頁伺服器尚未被正確設定來進行檔案同步,因為您的 WebDAV 界面似乎無法使用。",
"Please double check the <a href='%s'>installation guides</a>." => "請參考<a href='%s'>安裝指南</a>。",
"seconds ago" => "幾秒前",
@@ -30,8 +49,5 @@
"%d months ago" => "%d 個月之前",
"last year" => "去年",
"years ago" => "幾年前",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s 已經可用。取得 <a href=\"%s\">更多資訊</a>",
-"up to date" => "最新的",
-"updates check is disabled" => "檢查更新已停用",
"Could not find category \"%s\"" => "找不到分類:\"%s\""
);
diff --git a/lib/legacy/config.php b/lib/legacy/config.php
new file mode 100644
index 00000000000..5294a48ea44
--- /dev/null
+++ b/lib/legacy/config.php
@@ -0,0 +1,103 @@
+<?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/>.
+ *
+ */
+/*
+ *
+ * An example of config.php
+ *
+ * <?php
+ * $CONFIG = array(
+ * "database" => "mysql",
+ * "firstrun" => false,
+ * "pi" => 3.14
+ * );
+ * ?>
+ *
+ */
+
+/**
+ * This class is responsible for reading and writing config.php, the very basic
+ * configuration file of ownCloud.
+ */
+OC_Config::$object = new \OC\Config(OC::$SERVERROOT.'/config/');
+class OC_Config {
+
+ /**
+ * @var \OC\Config
+ */
+ public static $object;
+
+ /**
+ * @brief Lists all available config keys
+ * @return array with key names
+ *
+ * This function returns all keys saved in config.php. Please note that it
+ * does not return the values.
+ */
+ public static function getKeys() {
+ return self::$object->getKeys();
+ }
+
+ /**
+ * @brief Gets a value from config.php
+ * @param string $key key
+ * @param string $default = null default value
+ * @return string the value or $default
+ *
+ * This function gets the value from config.php. If it does not exist,
+ * $default will be returned.
+ */
+ public static function getValue($key, $default = null) {
+ return self::$object->getValue($key, $default);
+ }
+
+ /**
+ * @brief Sets a value
+ * @param string $key key
+ * @param string $value value
+ *
+ * This function sets the value and writes the config.php.
+ *
+ */
+ public static function setValue($key, $value) {
+ try {
+ self::$object->setValue($key, $value);
+ } catch (\OC\HintException $e) {
+ \OC_Template::printErrorPage($e->getMessage(), $e->getHint());
+ }
+ }
+
+ /**
+ * @brief Removes a key from the config
+ * @param string $key key
+ *
+ * This function removes a key from the config.php.
+ *
+ */
+ public static function deleteKey($key) {
+ try {
+ self::$object->deleteKey($key);
+ } catch (\OC\HintException $e) {
+ \OC_Template::printErrorPage($e->getMessage(), $e->getHint());
+ }
+ }
+}
diff --git a/lib/filesystem.php b/lib/legacy/filesystem.php
index 34f92b357ca..34f92b357ca 100644
--- a/lib/filesystem.php
+++ b/lib/legacy/filesystem.php
diff --git a/lib/filesystemview.php b/lib/legacy/filesystemview.php
index d6bca62e06a..d6bca62e06a 100644
--- a/lib/filesystemview.php
+++ b/lib/legacy/filesystemview.php
diff --git a/lib/legacy/log.php b/lib/legacy/log.php
new file mode 100644
index 00000000000..027cb89e97c
--- /dev/null
+++ b/lib/legacy/log.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+/**
+ * logging utilities
+ *
+ * Log is saved by default at data/owncloud.log using OC_Log_Owncloud.
+ * Selecting other backend is done with a config option 'log_type'.
+ */
+
+OC_Log::$object = new \OC\Log();
+class OC_Log {
+ public static $object;
+
+ const DEBUG=0;
+ const INFO=1;
+ const WARN=2;
+ const ERROR=3;
+ const FATAL=4;
+
+ static private $level_funcs = array(
+ self::DEBUG => 'debug',
+ self::INFO => 'info',
+ self::WARN => 'warning',
+ self::ERROR => 'error',
+ self::FATAL => 'emergency',
+ );
+
+ static public $enabled = true;
+ static protected $class = null;
+
+ /**
+ * write a message in the log
+ * @param string $app
+ * @param string $message
+ * @param int $level
+ */
+ public static function write($app, $message, $level) {
+ if (self::$enabled) {
+ $context = array('app' => $app);
+ $func = array(self::$object, self::$level_funcs[$level]);
+ call_user_func($func, $message, $context);
+ }
+ }
+}
diff --git a/lib/legacy/updater.php b/lib/legacy/updater.php
new file mode 100644
index 00000000000..eea7bb129cf
--- /dev/null
+++ b/lib/legacy/updater.php
@@ -0,0 +1,14 @@
+<?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.
+ */
+
+class OC_Updater {
+ public static function check() {
+ $updater = new \OC\Updater();
+ return $updater->check('http://apps.owncloud.com/updater.php');
+ }
+}
diff --git a/lib/log.php b/lib/log.php
index 3f3334801e5..e0b9fe3c696 100644
--- a/lib/log.php
+++ b/lib/log.php
@@ -1,69 +1,136 @@
<?php
/**
- * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
+ * 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;
+
/**
* logging utilities
*
- * Log is saved by default at data/owncloud.log using OC_Log_Owncloud.
- * Selecting other backend is done with a config option 'log_type'.
+ * This is a stand in, this should be replaced by a Psr\Log\LoggerInterface
+ * compatible logger. See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
+ * for the full interface specification.
+ *
+ * MonoLog is an example implementing this interface.
*/
-class OC_Log {
- const DEBUG=0;
- const INFO=1;
- const WARN=2;
- const ERROR=3;
- const FATAL=4;
+class Log {
+ private $logClass;
- static public $enabled = true;
- static protected $class = null;
+ /**
+ * System is unusable.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public function emergency($message, array $context = array()) {
+ $this->log(\OC_Log::FATAL, $message, $context);
+ }
/**
- * write a message in the log
- * @param string $app
+ * Action must be taken immediately.
+ *
+ * Example: Entire website down, database unavailable, etc. This should
+ * trigger the SMS alerts and wake you up.
+ *
* @param string $message
- * @param int level
+ * @param array $context
*/
- public static function write($app, $message, $level) {
- if (self::$enabled) {
- if (!self::$class) {
- self::$class = 'OC_Log_'.ucfirst(OC_Config::getValue('log_type', 'owncloud'));
- call_user_func(array(self::$class, 'init'));
- }
- $log_class=self::$class;
- $log_class::write($app, $message, $level);
- }
+ public function alert($message, array $context = array()) {
+ $this->log(\OC_Log::ERROR, $message, $context);
}
- //Fatal errors handler
- public static function onShutdown() {
- $error = error_get_last();
- if($error) {
- //ob_end_clean();
- self::write('PHP', $error['message'] . ' at ' . $error['file'] . '#' . $error['line'], self::FATAL);
- } else {
- return true;
- }
+ /**
+ * Critical conditions.
+ *
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public function critical($message, array $context = array()) {
+ $this->log(\OC_Log::ERROR, $message, $context);
}
- // Uncaught exception handler
- public static function onException($exception) {
- self::write('PHP',
- $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine(),
- self::FATAL);
+ /**
+ * Runtime errors that do not require immediate action but should typically
+ * be logged and monitored.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public function error($message, array $context = array()) {
+ $this->log(\OC_Log::ERROR, $message, $context);
}
- //Recoverable errors handler
- public static function onError($number, $message, $file, $line) {
- if (error_reporting() === 0) {
- return;
- }
- self::write('PHP', $message . ' at ' . $file . '#' . $line, self::WARN);
+ /**
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
+ * that are not necessarily wrong.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public function warning($message, array $context = array()) {
+ $this->log(\OC_Log::WARN, $message, $context);
+ }
+
+ /**
+ * Normal but significant events.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public function notice($message, array $context = array()) {
+ $this->log(\OC_Log::INFO, $message, $context);
+ }
+ /**
+ * Interesting events.
+ *
+ * Example: User logs in, SQL logs.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public function info($message, array $context = array()) {
+ $this->log(\OC_Log::INFO, $message, $context);
+ }
+
+ /**
+ * Detailed debug information.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public function debug($message, array $context = array()) {
+ $this->log(\OC_Log::DEBUG, $message, $context);
+ }
+
+ public function __construct() {
+ $this->logClass = 'OC_Log_'.ucfirst(\OC_Config::getValue('log_type', 'owncloud'));
+ call_user_func(array($this->logClass, 'init'));
+ }
+
+ /**
+ * Logs with an arbitrary level.
+ *
+ * @param mixed $level
+ * @param string $message
+ * @param array $context
+ */
+ public function log($level, $message, array $context = array()) {
+ if (isset($context['app'])) {
+ $app = $context['app'];
+ } else {
+ $app = 'no app in context';
+ }
+ $logClass=$this->logClass;
+ $logClass::write($app, $message, $level);
}
}
diff --git a/lib/log/errorhandler.php b/lib/log/errorhandler.php
new file mode 100644
index 00000000000..69cb960de91
--- /dev/null
+++ b/lib/log/errorhandler.php
@@ -0,0 +1,54 @@
+<?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;
+
+use OC\Log as LoggerInterface;
+
+class ErrorHandler {
+ /** @var LoggerInterface */
+ private static $logger;
+
+ public static function register() {
+ $handler = new ErrorHandler();
+
+ set_error_handler(array($handler, 'onError'));
+ register_shutdown_function(array($handler, 'onShutdown'));
+ set_exception_handler(array($handler, 'onException'));
+ }
+
+ public static function setLogger(LoggerInterface $logger) {
+ self::$logger = $logger;
+ }
+
+ //Fatal errors handler
+ public static function onShutdown() {
+ $error = error_get_last();
+ if($error && self::$logger) {
+ //ob_end_clean();
+ $msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line'];
+ self::$logger->critical($msg, array('app' => 'PHP'));
+ }
+ }
+
+ // Uncaught exception handler
+ public static function onException($exception) {
+ $msg = $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine();
+ self::$logger->critical($msg, array('app' => 'PHP'));
+ }
+
+ //Recoverable errors handler
+ public static function onError($number, $message, $file, $line) {
+ if (error_reporting() === 0) {
+ return;
+ }
+ $msg = $message . ' at ' . $file . '#' . $line;
+ self::$logger->warning($msg, array('app' => 'PHP'));
+
+ }
+}
diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php
index 20df52c27bb..7a11a588330 100644
--- a/lib/log/owncloud.php
+++ b/lib/log/owncloud.php
@@ -49,7 +49,8 @@ class OC_Log_Owncloud {
public static function write($app, $message, $level) {
$minLevel=min(OC_Config::getValue( "loglevel", OC_Log::WARN ), OC_Log::ERROR);
if($level>=$minLevel) {
- $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=>time());
+ $time = date("F d, Y H:i:s", time());
+ $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=> $time);
$handle = @fopen(self::$logFile, 'a');
if ($handle) {
fwrite($handle, json_encode($entry)."\n");
diff --git a/lib/mail.php b/lib/mail.php
index 61634632efc..b339b33e962 100644
--- a/lib/mail.php
+++ b/lib/mail.php
@@ -113,9 +113,12 @@ class OC_Mail {
*/
public static function getfooter() {
+ $defaults = new OC_Defaults();
+
$txt="\n--\n";
- $txt.="ownCloud\n";
- $txt.="Your Cloud, Your Data, Your Way!\n";
+ $txt.=$defaults->getName() . "\n";
+ $txt.=$defaults->getSlogan() . "\n";
+
return($txt);
}
diff --git a/lib/mimetypes.list.php b/lib/mimetypes.list.php
index 86ce9c6c237..2aac3bbfd27 100644
--- a/lib/mimetypes.list.php
+++ b/lib/mimetypes.list.php
@@ -86,11 +86,11 @@ return array(
'vcf' => 'text/vcard',
'vcard' => 'text/vcard',
'doc'=>'application/msword',
- 'docx'=>'application/msword',
+ 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls'=>'application/msexcel',
- 'xlsx'=>'application/msexcel',
+ 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'ppt'=>'application/mspowerpoint',
- 'pptx'=>'application/mspowerpoint',
+ 'pptx'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'sgf' => 'application/sgf',
'cdr' => 'application/coreldraw',
'impress' => 'text/impress',
@@ -98,5 +98,9 @@ return array(
'epub' => 'application/epub+zip',
'mobi' => 'application/x-mobipocket-ebook',
'exe' => 'application',
- 'msi' => 'application'
+ 'msi' => 'application',
+ 'md' => 'text/markdown',
+ 'markdown' => 'text/markdown',
+ 'mdown' => 'text/markdown',
+ 'mdwn' => 'text/markdown'
);
diff --git a/lib/ocs/result.php b/lib/ocs/result.php
index 8ab378d79c5..729c39056d9 100644
--- a/lib/ocs/result.php
+++ b/lib/ocs/result.php
@@ -22,7 +22,7 @@
class OC_OCS_Result{
- private $data, $message, $statusCode, $items, $perPage;
+ protected $data, $message, $statusCode, $items, $perPage;
/**
* create the OCS_Result object
diff --git a/lib/preferences.php b/lib/preferences.php
index 5f6434bcf9c..11ca760830e 100644
--- a/lib/preferences.php
+++ b/lib/preferences.php
@@ -59,7 +59,7 @@ class OC_Preferences{
}
/**
- * @brief Get all apps of a user
+ * @brief Get all apps of an user
* @param string $user user
* @return array with app ids
*
diff --git a/lib/public/backgroundjob.php b/lib/public/backgroundjob.php
index 601046fe691..cc076a3a845 100644
--- a/lib/public/backgroundjob.php
+++ b/lib/public/backgroundjob.php
@@ -1,49 +1,46 @@
<?php
/**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* 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/>.
-*
-*/
+ * ownCloud
+ *
+ * @author Jakob Sack
+ * @copyright 2012 Jakob Sack owncloud@jakobsack.de
+ *
+ * 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 forbackground jobs.
+ * Public interface of ownCloud for background jobs.
*/
// 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;
+use \OC\BackgroundJob\JobList;
+
/**
- * This class provides functions to manage backgroundjobs in ownCloud
- *
- * There are two kind of background jobs in ownCloud: regular tasks and
- * queued tasks.
+ * This class provides functions to register backgroundjobs in ownCloud
*
- * Regular tasks have to be registered in appinfo.php and
- * will run on a regular base. Fetching news could be a task that should run
- * frequently.
+ * To create a new backgroundjob create a new class that inharits from either \OC\BackgroundJob\Job,
+ * \OC\BackgroundJob\QueuedJob or \OC\BackgroundJob\TimedJob and register it using
+ * \OCP\BackgroundJob->registerJob($job, $argument), $argument will be passed to the run() function
+ * of the job when the job is executed.
*
- * Queued tasks have to be registered each time you want to execute them.
- * An example of the queued task would be the creation of the thumbnail. As
- * soon as the user uploads a picture the gallery app registers the queued
- * task "create thumbnail" and saves the path in the parameter instead of doing
- * the work right away. This makes the app more responsive. As soon as the task
- * is done it will be deleted from the list.
+ * A regular Job will be executed every time cron.php is run, a QueuedJob will only run once and a TimedJob
+ * will only run at a specific interval which is to be specified in the constructor of the job by calling
+ * $this->setInterval($interval) with $interval in seconds.
*/
class BackgroundJob {
/**
@@ -59,82 +56,136 @@ class BackgroundJob {
/**
* @brief sets the background jobs execution type
- * @param $type execution type
+ * @param string $type execution type
* @return boolean
*
* This method sets the execution type of the background jobs. Possible types
* are "none", "ajax", "webcron", "cron"
*/
- public static function setExecutionType( $type ) {
- return \OC_BackgroundJob::setExecutionType( $type );
+ public static function setExecutionType($type) {
+ return \OC_BackgroundJob::setExecutionType($type);
+ }
+
+ /**
+ * @param \OC\BackgroundJob\Job|string $job
+ * @param mixed $argument
+ */
+ public static function registerJob($job, $argument = null) {
+ $jobList = new JobList();
+ $jobList->add($job, $argument);
}
/**
+ * @deprecated
* @brief creates a regular task
- * @param $klass class name
- * @param $method method name
+ * @param string $klass class name
+ * @param string $method method name
* @return true
*/
- public static function addRegularTask( $klass, $method ) {
- return \OC_BackgroundJob_RegularTask::register( $klass, $method );
+ public static function addRegularTask($klass, $method) {
+ self::registerJob('OC\BackgroundJob\Legacy\RegularJob', array($klass, $method));
+ return true;
}
/**
+ * @deprecated
* @brief gets all regular tasks
* @return associative array
*
* key is string "$klass-$method", value is array( $klass, $method )
*/
static public function allRegularTasks() {
- return \OC_BackgroundJob_RegularTask::all();
+ $jobList = new JobList();
+ $allJobs = $jobList->getAll();
+ $regularJobs = array();
+ foreach ($allJobs as $job) {
+ if ($job instanceof RegularLegacyJob) {
+ $key = implode('-', $job->getArgument());
+ $regularJobs[$key] = $job->getArgument();
+ }
+ }
+ return $regularJobs;
}
/**
+ * @deprecated
* @brief Gets one queued task
- * @param $id ID of the task
+ * @param int $id ID of the task
* @return associative array
*/
- public static function findQueuedTask( $id ) {
- return \OC_BackgroundJob_QueuedTask::find( $id );
+ public static function findQueuedTask($id) {
+ $jobList = new JobList();
+ return $jobList->getById($id);
}
/**
+ * @deprecated
* @brief Gets all queued tasks
* @return array with associative arrays
*/
public static function allQueuedTasks() {
- return \OC_BackgroundJob_QueuedTask::all();
+ $jobList = new JobList();
+ $allJobs = $jobList->getAll();
+ $queuedJobs = array();
+ foreach ($allJobs as $job) {
+ if ($job instanceof QueuedLegacyJob) {
+ $queuedJob = $job->getArgument();
+ $queuedJob['id'] = $job->getId();
+ $queuedJobs[] = $queuedJob;
+ }
+ }
+ return $queuedJobs;
}
/**
+ * @deprecated
* @brief Gets all queued tasks of a specific app
- * @param $app app name
+ * @param string $app app name
* @return array with associative arrays
*/
- public static function queuedTaskWhereAppIs( $app ) {
- return \OC_BackgroundJob_QueuedTask::whereAppIs( $app );
+ public static function queuedTaskWhereAppIs($app) {
+ $jobList = new JobList();
+ $allJobs = $jobList->getAll();
+ $queuedJobs = array();
+ foreach ($allJobs as $job) {
+ if ($job instanceof QueuedLegacyJob) {
+ $queuedJob = $job->getArgument();
+ $queuedJob['id'] = $job->getId();
+ if ($queuedJob['app'] === $app) {
+ $queuedJobs[] = $queuedJob;
+ }
+ }
+ }
+ return $queuedJobs;
}
/**
+ * @deprecated
* @brief queues a task
- * @param $app app name
- * @param $klass class name
- * @param $method method name
- * @param $parameters all useful data as text
- * @return id of task
+ * @param string $app app name
+ * @param string $class class name
+ * @param string $method method name
+ * @param string $parameters all useful data as text
+ * @return int id of task
*/
- public static function addQueuedTask( $app, $klass, $method, $parameters ) {
- return \OC_BackgroundJob_QueuedTask::add( $app, $klass, $method, $parameters );
+ public static function addQueuedTask($app, $class, $method, $parameters) {
+ self::registerJob('OC\BackgroundJob\Legacy\QueuedJob', array('app' => $app, 'klass' => $class, 'method' => $method, 'parameters' => $parameters));
+ return true;
}
/**
+ * @deprecated
* @brief deletes a queued task
- * @param $id id of task
- * @return true/false
+ * @param int $id id of task
+ * @return bool
*
* Deletes a report
*/
- public static function deleteQueuedTask( $id ) {
- return \OC_BackgroundJob_QueuedTask::delete( $id );
+ public static function deleteQueuedTask($id) {
+ $jobList = new JobList();
+ $job = $jobList->getById($id);
+ if ($job) {
+ $jobList->remove($job);
+ }
}
}
diff --git a/lib/public/config.php b/lib/public/config.php
index 8076d640b49..73476d7551d 100644
--- a/lib/public/config.php
+++ b/lib/public/config.php
@@ -49,7 +49,7 @@ class Config {
* $default will be returned.
*/
public static function getSystemValue( $key, $default = null ) {
- return(\OC_Config::getValue( $key, $default ));
+ return \OC_Config::getValue( $key, $default );
}
/**
@@ -62,7 +62,12 @@ class Config {
* not be written, false will be returned.
*/
public static function setSystemValue( $key, $value ) {
- return(\OC_Config::setValue( $key, $value ));
+ try {
+ \OC_Config::setValue( $key, $value );
+ } catch (Exception $e) {
+ return false;
+ }
+ return true;
}
/**
@@ -76,7 +81,7 @@ class Config {
* not exist the default value will be returned
*/
public static function getAppValue( $app, $key, $default = null ) {
- return(\OC_Appconfig::getValue( $app, $key, $default ));
+ return \OC_Appconfig::getValue( $app, $key, $default );
}
/**
@@ -89,7 +94,12 @@ class Config {
* Sets a value. If the key did not exist before it will be created.
*/
public static function setAppValue( $app, $key, $value ) {
- return(\OC_Appconfig::setValue( $app, $key, $value ));
+ try {
+ \OC_Appconfig::setValue( $app, $key, $value );
+ } catch (Exception $e) {
+ return false;
+ }
+ return true;
}
/**
@@ -104,7 +114,7 @@ class Config {
* not exist the default value will be returned
*/
public static function getUserValue( $user, $app, $key, $default = null ) {
- return(\OC_Preferences::getValue( $user, $app, $key, $default ));
+ return \OC_Preferences::getValue( $user, $app, $key, $default );
}
/**
@@ -119,6 +129,11 @@ class Config {
* will be added automagically.
*/
public static function setUserValue( $user, $app, $key, $value ) {
- return(\OC_Preferences::setValue( $user, $app, $key, $value ));
+ try {
+ \OC_Preferences::setValue( $user, $app, $key, $value );
+ } catch (Exception $e) {
+ return false;
+ }
+ return true;
}
}
diff --git a/lib/public/defaults.php b/lib/public/defaults.php
new file mode 100644
index 00000000000..147f23e341f
--- /dev/null
+++ b/lib/public/defaults.php
@@ -0,0 +1,108 @@
+<?php
+/**
+* ownCloud
+*
+* @author Björn Schießle
+* @copyright 2013 Björn Schießle schiessle@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;
+
+/*
+ * public api to access default strings and urls for your templates
+ */
+
+class Defaults {
+
+ private $defaults;
+
+ function __construct() {
+ $this->defaults = new \OC_Defaults();
+ }
+
+ /**
+ * @breif get base URL for the organisation behind your ownCloud instance
+ * @return string
+ */
+ public function getBaseUrl() {
+ return $this->defaults->getBaseUrl();
+ }
+
+ /**
+ * @breif link to the desktop sync client
+ * @return string
+ */
+ public function getSyncClientUrl() {
+ return $this->defaults->getSyncClientUrl();
+ }
+
+ /**
+ * @breif base URL to the documentation of your ownCloud instance
+ * @return string
+ */
+ public function getDocBaseUrl() {
+ return $this->defaults->getDocBaseUrl();
+ }
+
+ /**
+ * @breif name of your ownCloud instance
+ * @return string
+ */
+ public function getName() {
+ return $this->defaults->getName();
+ }
+
+ /**
+ * @breif Entity behind your onwCloud instance
+ * @return string
+ */
+ public function getEntity() {
+ return $this->defaults->getEntity();
+ }
+
+ /**
+ * @breif ownCloud slogan
+ * @return string
+ */
+ public function getSlogan() {
+ return $this->defaults->getSlogan();
+ }
+
+ /**
+ * @breif logo claim
+ * @return string
+ */
+ public function getLogoClaim() {
+ return $this->defaults->getLogoClaim();
+ }
+
+ /**
+ * @breif footer, short version
+ * @return string
+ */
+ public function getShortFooter() {
+ return $this->defaults->getShortFooter();
+ }
+
+ /**
+ * @breif footer, long version
+ * @return string
+ */
+ public function getLongFooter() {
+ return $this->defaults->getLongFooter();
+ }
+}
diff --git a/lib/public/files.php b/lib/public/files.php
index 700bf574537..4975bbb7dfa 100644
--- a/lib/public/files.php
+++ b/lib/public/files.php
@@ -56,6 +56,16 @@ class Files {
}
/**
+ * search for files by mimetype
+ *
+ * @param string $query
+ * @return array
+ */
+ public function searchByMime($mimetype) {
+ return(\OC\Files\Filesystem::searchByMime( $mimetype ));
+ }
+
+ /**
* copy the contents of one stream to another
* @param resource source
* @param resource target
diff --git a/lib/public/share.php b/lib/public/share.php
index 8b8a41d47c0..596a729a47d 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -106,6 +106,125 @@ 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;
+
+ }
+
+ /**
+ * @brief Find which users can access a shared item
+ * @param $path to the file
+ * @param $user owner of the file
+ * @param include owner to the list of users with access to the file
+ * @return array
+ * @note $path needs to be relative to user data dir, e.g. 'file.txt'
+ * not '/admin/data/file.txt'
+ */
+ public static function getUsersSharingFile($path, $user, $includeOwner = false) {
+
+ $shares = array();
+ $publicShare = false;
+ $source = -1;
+ $cache = false;
+
+ $view = new \OC\Files\View('/' . $user . '/files/');
+ $meta = $view->getFileInfo(\OC\Files\Filesystem::normalizePath($path));
+
+ if($meta !== false) {
+ $source = $meta['fileid'];
+ $cache = new \OC\Files\Cache\Cache($meta['storage']);
+ }
+
+ while ($source !== -1) {
+
+ // Fetch all shares of this file path from DB
+ $query = \OC_DB::prepare(
+ 'SELECT `share_with`
+ FROM
+ `*PREFIX*share`
+ WHERE
+ `item_source` = ? AND `share_type` = ?'
+ );
+
+ $result = $query->execute(array($source, self::SHARE_TYPE_USER));
+
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
+ } else {
+ while ($row = $result->fetchRow()) {
+ $shares[] = $row['share_with'];
+ }
+ }
+ // We also need to take group shares into account
+
+ $query = \OC_DB::prepare(
+ 'SELECT `share_with`
+ FROM
+ `*PREFIX*share`
+ WHERE
+ `item_source` = ? AND `share_type` = ?'
+ );
+
+ $result = $query->execute(array($source, self::SHARE_TYPE_GROUP));
+
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
+ } else {
+ while ($row = $result->fetchRow()) {
+ $usersInGroup = \OC_Group::usersInGroup($row['share_with']);
+ $shares = array_merge($shares, $usersInGroup);
+ }
+ }
+
+ //check for public link shares
+ if (!$publicShare) {
+ $query = \OC_DB::prepare(
+ 'SELECT `share_with`
+ FROM
+ `*PREFIX*share`
+ WHERE
+ `item_source` = ? AND `share_type` = ?'
+ );
+
+ $result = $query->execute(array($source, self::SHARE_TYPE_LINK));
+
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR);
+ } else {
+ if ($result->fetchRow()) {
+ $publicShare = true;
+ }
+ }
+ }
+
+ // let's get the parent for the next round
+ $meta = $cache->get((int)$source);
+ if($meta !== false) {
+ $source = (int)$meta['parent'];
+ } else {
+ $source = -1;
+ }
+ }
+ // Include owner in list of users, if requested
+ if ($includeOwner) {
+ $shares[] = $user;
+ }
+
+ return array("users" => array_unique($shares), "public" => $publicShare);
+ }
/**
* @brief Get the items of item type shared with the current user
@@ -132,7 +251,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
@@ -173,6 +292,29 @@ class Share {
}
/**
+ * @brief resolves reshares down to the last real share
+ * @param $linkItem
+ * @return $fileOwner
+ */
+ public static function resolveReShare($linkItem)
+ {
+ if (isset($linkItem['parent'])) {
+ $parent = $linkItem['parent'];
+ while (isset($parent)) {
+ $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
+ $item = $query->execute(array($parent))->fetchRow();
+ if (isset($item['parent'])) {
+ $parent = $item['parent'];
+ } else {
+ return $item;
+ }
+ }
+ }
+ return $linkItem;
+ }
+
+
+ /**
* @brief Get the shared items of item type owned by the current user
* @param string Item type
* @param int Format (optional) Format type must be defined by the backend
@@ -193,7 +335,7 @@ class Share {
* @return Return depends on format
*/
public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
- $parameters = null, $includeCollections = false) {
+ $parameters = null, $includeCollections = false) {
return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
$parameters, -1, $includeCollections);
}
@@ -409,8 +551,16 @@ class Share {
'fileSource' => $item['file_source'],
'shareType' => $shareType,
'shareWith' => $shareWith,
+ 'itemParent' => $item['parent'],
));
self::delete($item['id']);
+ \OC_Hook::emit('OCP\Share', 'post_unshare', array(
+ 'itemType' => $itemType,
+ 'itemSource' => $itemSource,
+ 'shareType' => $shareType,
+ 'shareWith' => $shareWith,
+ 'itemParent' => $item['parent'],
+ ));
return true;
}
return false;
@@ -433,6 +583,11 @@ class Share {
foreach ($shares as $share) {
self::delete($share['id']);
}
+ \OC_Hook::emit('OCP\Share', 'post_unshareAll', array(
+ 'itemType' => $itemType,
+ 'itemSource' => $itemSource,
+ 'shares' => $shares
+ ));
return true;
}
return false;
@@ -502,6 +657,17 @@ class Share {
}
$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
$query->execute(array($permissions, $item['id']));
+ if ($itemType === 'file' || $itemType === 'folder') {
+ \OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
+ 'itemType' => $itemType,
+ 'itemSource' => $itemSource,
+ 'shareType' => $shareType,
+ 'shareWith' => $shareWith,
+ 'uidOwner' => \OC_User::getUser(),
+ 'permissions' => $permissions,
+ 'path' => $item['path'],
+ ));
+ }
// Check if permissions were removed
if ($item['permissions'] & ~$permissions) {
// If share permission is removed all reshares must be deleted
@@ -530,7 +696,13 @@ class Share {
// Remove the permissions for all reshares of this item
if (!empty($ids)) {
$ids = "'".implode("','", $ids)."'";
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = `permissions` & ?'
+ // TODO this should be done with Doctrine platform objects
+ if (\OC_Config::getValue( "dbtype") === 'oci') {
+ $andOp = 'BITAND(`permissions`, ?)';
+ } else {
+ $andOp = '`permissions` & ?';
+ }
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
.' WHERE `id` IN ('.$ids.')');
$query->execute(array($permissions));
}
@@ -661,6 +833,7 @@ class Share {
}
}
$backend = self::getBackend($itemType);
+ $collectionTypes = false;
// Get filesystem root to add it to the file target and remove from the
// file source, match file_source with the file cache
if ($itemType == 'file' || $itemType == 'folder') {
@@ -830,6 +1003,30 @@ class Share {
$switchedItems = array();
$mounts = array();
while ($row = $result->fetchRow()) {
+ if (isset($row['id'])) {
+ $row['id']=(int)$row['id'];
+ }
+ if (isset($row['share_type'])) {
+ $row['share_type']=(int)$row['share_type'];
+ }
+ if (isset($row['parent'])) {
+ $row['parent']=(int)$row['parent'];
+ }
+ if (isset($row['file_parent'])) {
+ $row['file_parent']=(int)$row['file_parent'];
+ }
+ if (isset($row['file_source'])) {
+ $row['file_source']=(int)$row['file_source'];
+ }
+ if (isset($row['permissions'])) {
+ $row['permissions']=(int)$row['permissions'];
+ }
+ if (isset($row['storage'])) {
+ $row['storage']=(int)$row['storage'];
+ }
+ if (isset($row['stime'])) {
+ $row['stime']=(int)$row['stime'];
+ }
// Filter out duplicate group shares for users with unique targets
if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
$row['share_type'] = self::SHARE_TYPE_GROUP;
@@ -845,7 +1042,7 @@ class Share {
// Check if the same owner shared with the user twice
// through a group and user share - this is allowed
$id = $targets[$row[$column]];
- if ($items[$id]['uid_owner'] == $row['uid_owner']) {
+ if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
// Switch to group share type to ensure resharing conditions aren't bypassed
if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
$items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
@@ -874,7 +1071,10 @@ class Share {
$row['path'] = '/Shared/'.basename($row['path']);
} else {
if (!isset($mounts[$row['storage']])) {
- $mounts[$row['storage']] = \OC\Files\Mount::findByNumericId($row['storage']);
+ $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
+ if (is_array($mountPoints)) {
+ $mounts[$row['storage']] = current($mountPoints);
+ }
}
if ($mounts[$row['storage']]) {
$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
@@ -1085,6 +1285,17 @@ class Share {
if ($shareType == self::SHARE_TYPE_GROUP) {
$groupItemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'],
$uidOwner, $suggestedItemTarget);
+ \OC_Hook::emit('OCP\Share', 'pre_shared', array(
+ 'itemType' => $itemType,
+ 'itemSource' => $itemSource,
+ 'itemTarget' => $groupItemTarget,
+ 'shareType' => $shareType,
+ 'shareWith' => $shareWith['group'],
+ 'uidOwner' => $uidOwner,
+ 'permissions' => $permissions,
+ 'fileSource' => $fileSource,
+ 'token' => $token
+ ));
if (isset($fileSource)) {
if ($parentFolder) {
if ($parentFolder === true) {
@@ -1145,7 +1356,7 @@ class Share {
'itemTarget' => $groupItemTarget,
'parent' => $parent,
'shareType' => $shareType,
- 'shareWith' => $uid,
+ 'shareWith' => $shareWith['group'],
'uidOwner' => $uidOwner,
'permissions' => $permissions,
'fileSource' => $fileSource,
@@ -1160,6 +1371,17 @@ class Share {
} else {
$itemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
$suggestedItemTarget);
+ \OC_Hook::emit('OCP\Share', 'pre_shared', array(
+ 'itemType' => $itemType,
+ 'itemSource' => $itemSource,
+ 'itemTarget' => $itemTarget,
+ 'shareType' => $shareType,
+ 'shareWith' => $shareWith,
+ 'uidOwner' => $uidOwner,
+ 'permissions' => $permissions,
+ 'fileSource' => $fileSource,
+ 'token' => $token
+ ));
if (isset($fileSource)) {
if ($parentFolder) {
if ($parentFolder === true) {
@@ -1428,10 +1650,10 @@ class Share {
public static function post_removeFromGroup($arguments) {
// TODO Don't call if user deleted?
- $query = \OC_DB::prepare('SELECT `id`, `share_type` FROM `*PREFIX*share`'
- .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)');
- $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'], self::$shareTypeGroupUserUnique,
- $arguments['uid']));
+ $sql = 'SELECT `id`, `share_type` FROM `*PREFIX*share`'
+ .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)';
+ $result = \OC_DB::executeAudited($sql, array(self::SHARE_TYPE_GROUP, $arguments['gid'],
+ self::$shareTypeGroupUserUnique, $arguments['uid']));
while ($item = $result->fetchRow()) {
if ($item['share_type'] == self::SHARE_TYPE_GROUP) {
// Delete all reshares by this user of the group share
@@ -1443,8 +1665,8 @@ class Share {
}
public static function post_deleteGroup($arguments) {
- $query = \OC_DB::prepare('SELECT id FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?');
- $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid']));
+ $sql = 'SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?';
+ $result = \OC_DB::executeAudited($sql, array(self::SHARE_TYPE_GROUP, $arguments['gid']));
while ($item = $result->fetchRow()) {
self::delete($item['id']);
}
diff --git a/lib/public/util.php b/lib/public/util.php
index db07cbcfff3..d69602f4507 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -217,6 +217,7 @@ class Util {
*/
public static function getDefaultEmailAddress($user_part) {
$host_name = self::getServerHostName();
+ $host_name = \OC_Config::getValue('mail_domain', $host_name);
$defaultEmailAddress = $user_part.'@'.$host_name;
if (\OC_Mail::ValidateAddress($defaultEmailAddress)) {
@@ -354,6 +355,20 @@ class Util {
public static function sanitizeHTML( $value ) {
return(\OC_Util::sanitizeHTML($value));
}
+
+ /**
+ * @brief Public function to encode url parameters
+ *
+ * This function is used to encode path to file before output.
+ * Encoding is done according to RFC 3986 with one exception:
+ * Character '/' is preserved as is.
+ *
+ * @param string $component part of URI to encode
+ * @return string
+ */
+ public static function encodePath($component) {
+ return(\OC_Util::encodePath($component));
+ }
/**
* @brief Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
diff --git a/lib/request.php b/lib/request.php
index 9f74cf9beb5..df33217f95d 100755
--- a/lib/request.php
+++ b/lib/request.php
@@ -9,16 +9,17 @@
class OC_Request {
/**
* @brief Check overwrite condition
- * @returns true/false
+ * @returns bool
*/
- private static function isOverwriteCondition() {
+ private static function isOverwriteCondition($type = '') {
$regex = '/' . OC_Config::getValue('overwritecondaddr', '') . '/';
- return $regex === '//' or preg_match($regex, $_SERVER['REMOTE_ADDR']) === 1;
+ return $regex === '//' or preg_match($regex, $_SERVER['REMOTE_ADDR']) === 1
+ or ($type !== 'protocol' and OC_Config::getValue('forcessl', false));
}
/**
* @brief Returns the server host
- * @returns the server host
+ * @returns string the server host
*
* Returns the server host, even if the website uses one or more
* reverse proxies
@@ -27,7 +28,7 @@ class OC_Request {
if(OC::$CLI) {
return 'localhost';
}
- if(OC_Config::getValue('overwritehost', '')<>'' and self::isOverwriteCondition()) {
+ if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) {
return OC_Config::getValue('overwritehost');
}
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
@@ -39,7 +40,13 @@ class OC_Request {
}
}
else{
- $host = $_SERVER['HTTP_HOST'];
+ if (isset($_SERVER['HTTP_HOST'])) {
+ return $_SERVER['HTTP_HOST'];
+ }
+ if (isset($_SERVER['SERVER_NAME'])) {
+ return $_SERVER['SERVER_NAME'];
+ }
+ return 'localhost';
}
return $host;
}
@@ -47,12 +54,12 @@ class OC_Request {
/**
* @brief Returns the server protocol
- * @returns the server protocol
+ * @returns string the server protocol
*
* Returns the server protocol. It respects reverse proxy servers and load balancers
*/
public static function serverProtocol() {
- if(OC_Config::getValue('overwriteprotocol', '')<>'' and self::isOverwriteCondition()) {
+ if(OC_Config::getValue('overwriteprotocol', '') !== '' and self::isOverwriteCondition('protocol')) {
return OC_Config::getValue('overwriteprotocol');
}
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
@@ -69,14 +76,14 @@ class OC_Request {
/**
* @brief Returns the request uri
- * @returns the request uri
+ * @returns string the request uri
*
* Returns the request uri, even if the website uses one or more
* reverse proxies
*/
public static function requestUri() {
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
- if (OC_Config::getValue('overwritewebroot', '') <> '' and self::isOverwriteCondition()) {
+ if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) {
$uri = self::scriptName() . substr($uri, strlen($_SERVER['SCRIPT_NAME']));
}
return $uri;
@@ -84,14 +91,14 @@ class OC_Request {
/**
* @brief Returns the script name
- * @returns the script name
+ * @returns string the script name
*
* Returns the script name, even if the website uses one or more
* reverse proxies
*/
public static function scriptName() {
$name = $_SERVER['SCRIPT_NAME'];
- if (OC_Config::getValue('overwritewebroot', '') <> '' and self::isOverwriteCondition()) {
+ if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) {
$serverroot = str_replace("\\", '/', substr(__DIR__, 0, -4));
$suburi = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen($serverroot)));
$name = OC_Config::getValue('overwritewebroot', '') . $suburi;
@@ -138,7 +145,7 @@ class OC_Request {
/**
* @brief Check if this is a no-cache request
- * @returns true for no-cache
+ * @returns boolean true for no-cache
*/
static public function isNoCache() {
if (!isset($_SERVER['HTTP_CACHE_CONTROL'])) {
@@ -149,7 +156,7 @@ class OC_Request {
/**
* @brief Check if the requestor understands gzip
- * @returns true for gzip encoding supported
+ * @returns boolean true for gzip encoding supported
*/
static public function acceptGZip() {
if (!isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
diff --git a/lib/response.php b/lib/response.php
index 49d79fda709..674176d078b 100644
--- a/lib/response.php
+++ b/lib/response.php
@@ -11,6 +11,7 @@ class OC_Response {
const STATUS_NOT_MODIFIED = 304;
const STATUS_TEMPORARY_REDIRECT = 307;
const STATUS_NOT_FOUND = 404;
+ const STATUS_INTERNAL_SERVER_ERROR = 500;
/**
* @brief Enable response caching by sending correct HTTP headers
@@ -70,6 +71,9 @@ class OC_Response {
case self::STATUS_NOT_FOUND;
$status = $status . ' Not Found';
break;
+ case self::STATUS_INTERNAL_SERVER_ERROR;
+ $status = $status . ' Internal Server Error';
+ break;
}
header($protocol.' '.$status);
}
diff --git a/lib/session/internal.php b/lib/session/internal.php
new file mode 100644
index 00000000000..60aecccc8aa
--- /dev/null
+++ b/lib/session/internal.php
@@ -0,0 +1,39 @@
+<?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\Session;
+
+/**
+ * Class Internal
+ *
+ * wrap php's internal session handling into the Session interface
+ *
+ * @package OC\Session
+ */
+class Internal extends Memory {
+ public function __construct($name) {
+ session_name($name);
+ session_start();
+ if (!isset($_SESSION)) {
+ throw new \Exception('Failed to start session');
+ }
+ $this->data = $_SESSION;
+ }
+
+ public function __destruct() {
+ $_SESSION = $this->data;
+ session_write_close();
+ }
+
+ public function clear() {
+ session_unset();
+ @session_regenerate_id(true);
+ @session_start();
+ $this->data = $_SESSION = array();
+ }
+}
diff --git a/lib/session/memory.php b/lib/session/memory.php
new file mode 100644
index 00000000000..c148ff4b9b9
--- /dev/null
+++ b/lib/session/memory.php
@@ -0,0 +1,63 @@
+<?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\Session;
+
+/**
+ * Class Internal
+ *
+ * store session data in an in-memory array, not persistance
+ *
+ * @package OC\Session
+ */
+class Memory extends Session {
+ protected $data;
+
+ public function __construct($name) {
+ //no need to use $name since all data is already scoped to this instance
+ $this->data = array();
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ public function set($key, $value) {
+ $this->data[$key] = $value;
+ }
+
+ /**
+ * @param string $key
+ * @return mixed
+ */
+ public function get($key) {
+ if (!$this->exists($key)) {
+ return null;
+ }
+ return $this->data[$key];
+ }
+
+ /**
+ * @param string $key
+ * @return bool
+ */
+ public function exists($key) {
+ return isset($this->data[$key]);
+ }
+
+ /**
+ * @param string $key
+ */
+ public function remove($key) {
+ unset($this->data[$key]);
+ }
+
+ public function clear() {
+ $this->data = array();
+ }
+}
diff --git a/lib/session/session.php b/lib/session/session.php
new file mode 100644
index 00000000000..55515f57a87
--- /dev/null
+++ b/lib/session/session.php
@@ -0,0 +1,79 @@
+<?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\Session;
+
+abstract class Session implements \ArrayAccess {
+ /**
+ * $name serves as a namespace for the session keys
+ *
+ * @param string $name
+ */
+ abstract public function __construct($name);
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ abstract public function set($key, $value);
+
+ /**
+ * @param string $key
+ * @return mixed should return null if $key does not exist
+ */
+ abstract public function get($key);
+
+ /**
+ * @param string $key
+ * @return bool
+ */
+ abstract public function exists($key);
+
+ /**
+ * should not throw any errors if $key does not exist
+ *
+ * @param string $key
+ */
+ abstract public function remove($key);
+
+ /**
+ * removes all entries within the cache namespace
+ */
+ abstract public function clear();
+
+ /**
+ * @param mixed $offset
+ * @return bool
+ */
+ public function offsetExists($offset) {
+ return $this->exists($offset);
+ }
+
+ /**
+ * @param mixed $offset
+ * @return mixed
+ */
+ public function offsetGet($offset) {
+ return $this->get($offset);
+ }
+
+ /**
+ * @param mixed $offset
+ * @param mixed $value
+ */
+ public function offsetSet($offset, $value) {
+ $this->set($offset, $value);
+ }
+
+ /**
+ * @param mixed $offset
+ */
+ public function offsetUnset($offset) {
+ $this->remove($offset);
+ }
+}
diff --git a/lib/setup.php b/lib/setup.php
index 8814447f52f..59f4cab75de 100644
--- a/lib/setup.php
+++ b/lib/setup.php
@@ -1,24 +1,18 @@
<?php
-class DatabaseSetupException extends Exception
+class DatabaseSetupException extends \OC\HintException
{
- private $hint;
-
- public function __construct($message, $hint, $code = 0, Exception $previous = null) {
- $this->hint = $hint;
- parent::__construct($message, $code, $previous);
- }
-
- public function __toString() {
- return __CLASS__ . ": [{$this->code}]: {$this->message} ({$this->hint})\n";
- }
-
- public function getHint() {
- return $this->hint;
- }
}
class OC_Setup {
+ static $dbSetupClasses = array(
+ 'mysql' => '\OC\Setup\MySQL',
+ 'pgsql' => '\OC\Setup\PostgreSQL',
+ 'oci' => '\OC\Setup\OCI',
+ 'mssql' => '\OC\Setup\MSSQL',
+ 'sqlite' => '\OC\Setup\Sqlite',
+ 'sqlite3' => '\OC\Setup\Sqlite',
+ );
public static function getTrans(){
return OC_L10N::get('lib');
@@ -37,755 +31,91 @@ class OC_Setup {
$error[] = $l->t('Set an admin password.');
}
if(empty($options['directory'])) {
- $error[] = $l->t('Specify a data folder.');
- }
-
- if($dbtype == 'mysql' or $dbtype == 'pgsql' or $dbtype == 'oci' or $dbtype == 'mssql') { //mysql and postgresql needs more config options
- if($dbtype == 'mysql')
- $dbprettyname = 'MySQL';
- else if($dbtype == 'pgsql')
- $dbprettyname = 'PostgreSQL';
- else if ($dbtype == 'mssql')
- $dbprettyname = 'MS SQL Server';
- else
- $dbprettyname = 'Oracle';
-
-
- if(empty($options['dbuser'])) {
- $error[] = $l->t("%s enter the database username.", array($dbprettyname));
- }
- if(empty($options['dbname'])) {
- $error[] = $l->t("%s enter the database name.", array($dbprettyname));
- }
- if(substr_count($options['dbname'], '.') >= 1) {
- $error[] = $l->t("%s you may not use dots in the database name", array($dbprettyname));
- }
- if($dbtype != 'oci' && empty($options['dbhost'])) {
- $error[] = $l->t("%s set the database host.", array($dbprettyname));
- }
- }
-
- if(count($error) == 0) { //no errors, good
- $username = htmlspecialchars_decode($options['adminlogin']);
- $password = htmlspecialchars_decode($options['adminpass']);
- $datadir = htmlspecialchars_decode($options['directory']);
-
- //use sqlite3 when available, otherise sqlite2 will be used.
- if($dbtype=='sqlite' and class_exists('SQLite3')) {
- $dbtype='sqlite3';
- }
-
- //generate a random salt that is used to salt the local user passwords
- $salt = OC_Util::generate_random_bytes(30);
- OC_Config::setValue('passwordsalt', $salt);
-
- //write the config file
- OC_Config::setValue('datadirectory', $datadir);
- OC_Config::setValue('dbtype', $dbtype);
- OC_Config::setValue('version', implode('.', OC_Util::getVersion()));
- if($dbtype == 'mysql') {
- $dbuser = $options['dbuser'];
- $dbpass = $options['dbpass'];
- $dbname = $options['dbname'];
- $dbhost = $options['dbhost'];
- $dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
-
- OC_Config::setValue('dbname', $dbname);
- OC_Config::setValue('dbhost', $dbhost);
- OC_Config::setValue('dbtableprefix', $dbtableprefix);
-
- try {
- self::setupMySQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username);
- } catch (DatabaseSetupException $e) {
- $error[] = array(
- 'error' => $e->getMessage(),
- 'hint' => $e->getHint()
- );
- return($error);
- } catch (Exception $e) {
- $error[] = array(
- 'error' => $e->getMessage(),
- 'hint' => ''
- );
- return($error);
- }
- }
- elseif($dbtype == 'pgsql') {
- $dbuser = $options['dbuser'];
- $dbpass = $options['dbpass'];
- $dbname = $options['dbname'];
- $dbhost = $options['dbhost'];
- $dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
-
- OC_Config::setValue('dbname', $dbname);
- OC_Config::setValue('dbhost', $dbhost);
- OC_Config::setValue('dbtableprefix', $dbtableprefix);
-
- try {
- self::setupPostgreSQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username);
- } catch (Exception $e) {
- $error[] = array(
- 'error' => $l->t('PostgreSQL username and/or password not valid'),
- 'hint' => $l->t('You need to enter either an existing account or the administrator.')
- );
- return $error;
- }
- }
- elseif($dbtype == 'oci') {
- $dbuser = $options['dbuser'];
- $dbpass = $options['dbpass'];
- $dbname = $options['dbname'];
- $dbtablespace = $options['dbtablespace'];
- $dbhost = isset($options['dbhost'])?$options['dbhost']:'';
- $dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
-
- OC_Config::setValue('dbname', $dbname);
- OC_Config::setValue('dbtablespace', $dbtablespace);
- OC_Config::setValue('dbhost', $dbhost);
- OC_Config::setValue('dbtableprefix', $dbtableprefix);
-
- try {
- self::setupOCIDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $dbtablespace, $username);
- } catch (Exception $e) {
- $error[] = array(
- 'error' => $l->t('Oracle username and/or password not valid'),
- 'hint' => $l->t('You need to enter either an existing account or the administrator.')
- );
- return $error;
- }
- }
- elseif ($dbtype == 'mssql') {
- $dbuser = $options['dbuser'];
- $dbpass = $options['dbpass'];
- $dbname = $options['dbname'];
- $dbhost = $options['dbhost'];
- $dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
-
- OC_Config::setValue('dbname', $dbname);
- OC_Config::setValue('dbhost', $dbhost);
- OC_Config::setValue('dbuser', $dbuser);
- OC_Config::setValue('dbpassword', $dbpass);
- OC_Config::setValue('dbtableprefix', $dbtableprefix);
-
- try {
- self::setupMSSQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix);
- } catch (Exception $e) {
- $error[] = array(
- 'error' => 'MS SQL username and/or password not valid',
- 'hint' => 'You need to enter either an existing account or the administrator.'
- );
- return $error;
- }
- }
- else {
- //delete the old sqlite database first, might cause infinte loops otherwise
- if(file_exists("$datadir/owncloud.db")) {
- unlink("$datadir/owncloud.db");
- }
- //in case of sqlite, we can always fill the database
- OC_DB::createDbFromStructure('db_structure.xml');
- }
-
- //create the user and group
- try {
- OC_User::createUser($username, $password);
- }
- catch(Exception $exception) {
- $error[] = $exception->getMessage();
- }
-
- if(count($error) == 0) {
- OC_Appconfig::setValue('core', 'installedat', microtime(true));
- OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true));
- OC_AppConfig::setValue('core', 'remote_core.css', '/core/minimizer.php');
- OC_AppConfig::setValue('core', 'remote_core.js', '/core/minimizer.php');
-
- OC_Group::createGroup('admin');
- OC_Group::addToGroup($username, 'admin');
- OC_User::login($username, $password);
-
- //guess what this does
- OC_Installer::installShippedApps();
-
- //create htaccess files for apache hosts
- if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
- self::createHtaccess();
- }
-
- //and we are done
- OC_Config::setValue('installed', true);
- }
- }
-
- return $error;
- }
-
- private static function setupMySQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username) {
- //check if the database user has admin right
- $l = self::getTrans();
- $connection = @mysql_connect($dbhost, $dbuser, $dbpass);
- if(!$connection) {
- throw new DatabaseSetupException($l->t('MySQL username and/or password not valid'),
- $l->t('You need to enter either an existing account or the administrator.'));
- }
- $oldUser=OC_Config::getValue('dbuser', false);
-
- //this should be enough to check for admin rights in mysql
- $query="SELECT user FROM mysql.user WHERE user='$dbuser'";
- if(mysql_query($query, $connection)) {
- //use the admin login data for the new database user
-
- //add prefix to the mysql user name to prevent collisions
- $dbusername=substr('oc_'.$username, 0, 16);
- if($dbusername!=$oldUser) {
- //hash the password so we don't need to store the admin config in the config file
- $dbpassword=md5(time().$dbpass);
-
- self::createDBUser($dbusername, $dbpassword, $connection);
-
- OC_Config::setValue('dbuser', $dbusername);
- OC_Config::setValue('dbpassword', $dbpassword);
- }
-
- //create the database
- self::createMySQLDatabase($dbname, $dbusername, $connection);
- }
- else {
- if($dbuser!=$oldUser) {
- OC_Config::setValue('dbuser', $dbuser);
- OC_Config::setValue('dbpassword', $dbpass);
- }
-
- //create the database
- self::createMySQLDatabase($dbname, $dbuser, $connection);
- }
-
- //fill the database if needed
- $query='select count(*) from information_schema.tables'
- ." where table_schema='$dbname' AND table_name = '{$dbtableprefix}users';";
- $result = mysql_query($query, $connection);
- if($result) {
- $row=mysql_fetch_row($result);
- }
- if(!$result or $row[0]==0) {
- OC_DB::createDbFromStructure('db_structure.xml');
- }
- mysql_close($connection);
- }
-
- private static function createMySQLDatabase($name, $user, $connection) {
- //we cant use OC_BD functions here because we need to connect as the administrative user.
- $l = self::getTrans();
- $query = "CREATE DATABASE IF NOT EXISTS `$name`";
- $result = mysql_query($query, $connection);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(mysql_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- }
- $query="GRANT ALL PRIVILEGES ON `$name` . * TO '$user'";
-
- //this query will fail if there aren't the right permissions, ignore the error
- mysql_query($query, $connection);
- }
-
- private static function createDBUser($name, $password, $connection) {
- // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one,
- // the anonymous user would take precedence when there is one.
- $l = self::getTrans();
- $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'";
- $result = mysql_query($query, $connection);
- if (!$result) {
- throw new DatabaseSetupException($l->t("MySQL user '%s'@'localhost' exists already.",
- array($name)), $l->t("Drop this user from MySQL", array($name)));
- }
- $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'";
- $result = mysql_query($query, $connection);
- if (!$result) {
- throw new DatabaseSetupException($l->t("MySQL user '%s'@'%%' already exists", array($name)),
- $l->t("Drop this user from MySQL."));
- }
- }
-
- private static function setupPostgreSQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username) {
- $e_host = addslashes($dbhost);
- $e_user = addslashes($dbuser);
- $e_password = addslashes($dbpass);
- $l = self::getTrans();
-
- //check if the database user has admin rights
- $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'";
- $connection = @pg_connect($connection_string);
- if(!$connection) {
- throw new Exception($l->t('PostgreSQL username and/or password not valid'));
- }
- $e_user = pg_escape_string($dbuser);
- //check for roles creation rights in postgresql
- $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'";
- $result = pg_query($connection, $query);
- if($result and pg_num_rows($result) > 0) {
- //use the admin login data for the new database user
-
- //add prefix to the postgresql user name to prevent collisions
- $dbusername='oc_'.$username;
- //create a new password so we don't need to store the admin config in the config file
- $dbpassword=md5(time());
-
- self::pg_createDBUser($dbusername, $dbpassword, $connection);
-
- OC_Config::setValue('dbuser', $dbusername);
- OC_Config::setValue('dbpassword', $dbpassword);
-
- //create the database
- self::pg_createDatabase($dbname, $dbusername, $connection);
- }
- else {
- OC_Config::setValue('dbuser', $dbuser);
- OC_Config::setValue('dbpassword', $dbpass);
-
- //create the database
- self::pg_createDatabase($dbname, $dbuser, $connection);
- }
-
- // the connection to dbname=postgres is not needed anymore
- pg_close($connection);
-
- // connect to the ownCloud database (dbname=$dbname) and check if it needs to be filled
- $dbuser = OC_Config::getValue('dbuser');
- $dbpass = OC_Config::getValue('dbpassword');
-
- $e_host = addslashes($dbhost);
- $e_dbname = addslashes($dbname);
- $e_user = addslashes($dbuser);
- $e_password = addslashes($dbpass);
-
- $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'";
- $connection = @pg_connect($connection_string);
- if(!$connection) {
- throw new Exception($l->t('PostgreSQL username and/or password not valid'));
- }
- $query = "select count(*) FROM pg_class WHERE relname='{$dbtableprefix}users' limit 1";
- $result = pg_query($connection, $query);
- if($result) {
- $row = pg_fetch_row($result);
- }
- if(!$result or $row[0]==0) {
- OC_DB::createDbFromStructure('db_structure.xml');
- }
- }
-
- private static function pg_createDatabase($name, $user, $connection) {
-
- //we cant use OC_BD functions here because we need to connect as the administrative user.
- $l = self::getTrans();
- $e_name = pg_escape_string($name);
- $e_user = pg_escape_string($user);
- $query = "select datname from pg_database where datname = '$e_name'";
- $result = pg_query($connection, $query);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
- }
- if(! pg_fetch_row($result)) {
- //The database does not exists... let's create it
- $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\"";
- $result = pg_query($connection, $query);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
- }
- else {
- $query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC";
- pg_query($connection, $query);
- }
+ $options['directory'] = OC::$SERVERROOT."/data";
}
- }
- private static function pg_createDBUser($name, $password, $connection) {
- $l = self::getTrans();
- $e_name = pg_escape_string($name);
- $e_password = pg_escape_string($password);
- $query = "select * from pg_roles where rolname='$e_name';";
- $result = pg_query($connection, $query);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
+ if (!isset(self::$dbSetupClasses[$dbtype])) {
+ $dbtype = 'sqlite';
}
- if(! pg_fetch_row($result)) {
- //user does not exists let's create it :)
- $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';";
- $result = pg_query($connection, $query);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
- }
- }
- else { // change password of the existing role
- $query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';";
- $result = pg_query($connection, $query);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
- }
- }
- }
+ $class = self::$dbSetupClasses[$dbtype];
+ $dbSetup = new $class(self::getTrans(), 'db_structure.xml');
+ $error = array_merge($error, $dbSetup->validate($options));
- private static function setupOCIDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $dbtablespace,
- $username) {
- $l = self::getTrans();
- $e_host = addslashes($dbhost);
- $e_dbname = addslashes($dbname);
- //check if the database user has admin right
- if ($e_host == '') {
- $easy_connect_string = $e_dbname; // use dbname as easy connect name
- } else {
- $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
- }
- $connection = @oci_connect($dbuser, $dbpass, $easy_connect_string);
- if(!$connection) {
- $e = oci_error();
- throw new Exception($l->t('Oracle username and/or password not valid'));
- }
- //check for roles creation rights in oracle
-
- $query='SELECT count(*) FROM user_role_privs, role_sys_privs'
- ." WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'";
- $stmt = oci_parse($connection, $query);
- if (!$stmt) {
- $entry = $l->t('DB Error: "%s"', array(oci_last_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
- $result = oci_execute($stmt);
- if($result) {
- $row = oci_fetch_row($stmt);
- }
- if($result and $row[0] > 0) {
- //use the admin login data for the new database user
-
- //add prefix to the oracle user name to prevent collisions
- $dbusername='oc_'.$username;
- //create a new password so we don't need to store the admin config in the config file
- $dbpassword=md5(time().$dbpass);
-
- //oracle passwords are treated as identifiers:
- // must start with aphanumeric char
- // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length.
- $dbpassword=substr($dbpassword, 0, 30);
-
- self::oci_createDBUser($dbusername, $dbpassword, $dbtablespace, $connection);
-
- OC_Config::setValue('dbuser', $dbusername);
- OC_Config::setValue('dbname', $dbusername);
- OC_Config::setValue('dbpassword', $dbpassword);
-
- //create the database not neccessary, oracle implies user = schema
- //self::oci_createDatabase($dbname, $dbusername, $connection);
- } else {
-
- OC_Config::setValue('dbuser', $dbuser);
- OC_Config::setValue('dbname', $dbname);
- OC_Config::setValue('dbpassword', $dbpass);
-
- //create the database not neccessary, oracle implies user = schema
- //self::oci_createDatabase($dbname, $dbuser, $connection);
- }
-
- //FIXME check tablespace exists: select * from user_tablespaces
-
- // the connection to dbname=oracle is not needed anymore
- oci_close($connection);
-
- // connect to the oracle database (schema=$dbuser) an check if the schema needs to be filled
- $dbuser = OC_Config::getValue('dbuser');
- //$dbname = OC_Config::getValue('dbname');
- $dbpass = OC_Config::getValue('dbpassword');
-
- $e_host = addslashes($dbhost);
- $e_dbname = addslashes($dbname);
-
- if ($e_host == '') {
- $easy_connect_string = $e_dbname; // use dbname as easy connect name
- } else {
- $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
- }
- $connection = @oci_connect($dbuser, $dbpass, $easy_connect_string);
- if(!$connection) {
- throw new Exception($l->t('Oracle username and/or password not valid'));
- }
- $query = "SELECT count(*) FROM user_tables WHERE table_name = :un";
- $stmt = oci_parse($connection, $query);
- $un = $dbtableprefix.'users';
- oci_bind_by_name($stmt, ':un', $un);
- if (!$stmt) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ if(count($error) != 0) {
+ return $error;
}
- $result = oci_execute($stmt);
- if($result) {
- $row = oci_fetch_row($stmt);
- }
- if(!$result or $row[0]==0) {
- OC_DB::createDbFromStructure('db_structure.xml');
- }
- }
+ //no errors, good
+ $username = htmlspecialchars_decode($options['adminlogin']);
+ $password = htmlspecialchars_decode($options['adminpass']);
+ $datadir = htmlspecialchars_decode($options['directory']);
- /**
- *
- * @param String $name
- * @param String $password
- * @param String $tablespace
- * @param resource $connection
- */
- private static function oci_createDBUser($name, $password, $tablespace, $connection) {
- $l = self::getTrans();
- $query = "SELECT * FROM all_users WHERE USERNAME = :un";
- $stmt = oci_parse($connection, $query);
- if (!$stmt) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
- oci_bind_by_name($stmt, ':un', $name);
- $result = oci_execute($stmt);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ if (OC_Util::runningOnWindows()) {
+ $datadir = rtrim(realpath($datadir), '\\');
}
- if(! oci_fetch_row($stmt)) {
- //user does not exists let's create it :)
- //password must start with alphabetic character in oracle
- $query = 'CREATE USER '.$name.' IDENTIFIED BY "'.$password.'" DEFAULT TABLESPACE '.$tablespace; //TODO set default tablespace
- $stmt = oci_parse($connection, $query);
- if (!$stmt) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
- //oci_bind_by_name($stmt, ':un', $name);
- $result = oci_execute($stmt);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s", name: %s, password: %s',
- array($query, $name, $password)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
- } else { // change password of the existing role
- $query = "ALTER USER :un IDENTIFIED BY :pw";
- $stmt = oci_parse($connection, $query);
- if (!$stmt) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
- oci_bind_by_name($stmt, ':un', $name);
- oci_bind_by_name($stmt, ':pw', $password);
- $result = oci_execute($stmt);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
+ //use sqlite3 when available, otherise sqlite2 will be used.
+ if($dbtype=='sqlite' and class_exists('SQLite3')) {
+ $dbtype='sqlite3';
}
- // grant necessary roles
- $query = 'GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER, UNLIMITED TABLESPACE TO '.$name;
- $stmt = oci_parse($connection, $query);
- if (!$stmt) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s"', array($query)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
- $result = oci_execute($stmt);
- if(!$result) {
- $entry = $l->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
- $entry .= $l->t('Offending command was: "%s", name: %s, password: %s',
- array($query, $name, $password)) . '<br />';
- \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
- }
- }
- private static function setupMSSQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix) {
- $l = self::getTrans();
-
- //check if the database user has admin right
- $masterConnectionInfo = array( "Database" => "master", "UID" => $dbuser, "PWD" => $dbpass);
+ //generate a random salt that is used to salt the local user passwords
+ $salt = OC_Util::generate_random_bytes(30);
+ OC_Config::setValue('passwordsalt', $salt);
- $masterConnection = @sqlsrv_connect($dbhost, $masterConnectionInfo);
- if(!$masterConnection) {
- $entry = null;
- if( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- throw new Exception($l->t('MS SQL username and/or password not valid: %s', array($entry)));
+ //write the config file
+ OC_Config::setValue('datadirectory', $datadir);
+ OC_Config::setValue('dbtype', $dbtype);
+ OC_Config::setValue('version', implode('.', OC_Util::getVersion()));
+ try {
+ $dbSetup->initialize($options);
+ $dbSetup->setupDatabase($username);
+ } catch (DatabaseSetupException $e) {
+ $error[] = array(
+ 'error' => $e->getMessage(),
+ 'hint' => $e->getHint()
+ );
+ return($error);
+ } catch (Exception $e) {
+ $error[] = array(
+ 'error' => 'Error while trying to create admin user: ' . $e->getMessage(),
+ 'hint' => ''
+ );
+ return($error);
}
- OC_Config::setValue('dbuser', $dbuser);
- OC_Config::setValue('dbpassword', $dbpass);
-
- self::mssql_createDBLogin($dbuser, $dbpass, $masterConnection);
-
- self::mssql_createDatabase($dbname, $masterConnection);
-
- self::mssql_createDBUser($dbuser, $dbname, $masterConnection);
-
- sqlsrv_close($masterConnection);
-
- self::mssql_createDatabaseStructure($dbhost, $dbname, $dbuser, $dbpass, $dbtableprefix);
- }
-
- private static function mssql_createDBLogin($name, $password, $connection) {
- $query = "SELECT * FROM master.sys.server_principals WHERE name = '".$name."';";
- $result = sqlsrv_query($connection, $query);
- if ($result === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- } else {
- $row = sqlsrv_fetch_array($result);
-
- if ($row === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- } else {
- if ($row == null) {
- $query = "CREATE LOGIN [".$name."] WITH PASSWORD = '".$password."';";
- $result = sqlsrv_query($connection, $query);
- if (!$result or $result === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- }
- }
- }
+ //create the user and group
+ try {
+ OC_User::createUser($username, $password);
}
- }
-
- private static function mssql_createDBUser($name, $dbname, $connection) {
- $query = "SELECT * FROM [".$dbname."].sys.database_principals WHERE name = '".$name."';";
- $result = sqlsrv_query($connection, $query);
- if ($result === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- } else {
- $row = sqlsrv_fetch_array($result);
-
- if ($row === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- } else {
- if ($row == null) {
- $query = "USE [".$dbname."]; CREATE USER [".$name."] FOR LOGIN [".$name."];";
- $result = sqlsrv_query($connection, $query);
- if (!$result || $result === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry = 'DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- }
- }
-
- $query = "USE [".$dbname."]; EXEC sp_addrolemember 'db_owner', '".$name."';";
- $result = sqlsrv_query($connection, $query);
- if (!$result || $result === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- }
- }
+ catch(Exception $exception) {
+ $error[] = $exception->getMessage();
}
- }
- private static function mssql_createDatabase($dbname, $connection) {
- $query = "CREATE DATABASE [".$dbname."];";
- $result = sqlsrv_query($connection, $query);
- if (!$result || $result === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- }
- }
+ if(count($error) == 0) {
+ OC_Appconfig::setValue('core', 'installedat', microtime(true));
+ OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true));
+ OC_AppConfig::setValue('core', 'remote_core.css', '/core/minimizer.php');
+ OC_AppConfig::setValue('core', 'remote_core.js', '/core/minimizer.php');
- private static function mssql_createDatabaseStructure($dbhost, $dbname, $dbuser, $dbpass, $dbtableprefix) {
- $connectionInfo = array( "Database" => $dbname, "UID" => $dbuser, "PWD" => $dbpass);
+ OC_Group::createGroup('admin');
+ OC_Group::addToGroup($username, 'admin');
+ OC_User::login($username, $password);
- $connection = @sqlsrv_connect($dbhost, $connectionInfo);
+ //guess what this does
+ OC_Installer::installShippedApps();
- //fill the database if needed
- $query = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{$dbname}' AND TABLE_NAME = '{$dbtableprefix}users'";
- $result = sqlsrv_query($connection, $query);
- if ($result === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
+ //create htaccess files for apache hosts
+ if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
+ self::createHtaccess();
}
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- } else {
- $row = sqlsrv_fetch_array($result);
- if ($row === false) {
- if ( ($errors = sqlsrv_errors() ) != null) {
- $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
- } else {
- $entry = '';
- }
- $entry.='Offending command was: '.$query.'<br />';
- \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
- } else {
- if ($row == null) {
- OC_DB::createDbFromStructure('db_structure.xml');
- }
- }
+ //and we are done
+ OC_Config::setValue('installed', true);
}
- sqlsrv_close($connection);
+ return $error;
}
/**
@@ -806,6 +136,7 @@ class OC_Setup {
$content.= "php_value upload_max_filesize 512M\n";//upload limit
$content.= "php_value post_max_size 512M\n";
$content.= "php_value memory_limit 512M\n";
+ $content.= "php_value mbstring.func_overload 0\n";
$content.= "<IfModule env_module>\n";
$content.= " SetEnv htaccessWorking true\n";
$content.= "</IfModule>\n";
@@ -823,6 +154,10 @@ class OC_Setup {
$content.= "AddType image/svg+xml svg svgz\n";
$content.= "AddEncoding gzip svgz\n";
$content.= "</IfModule>\n";
+ $content.= "<IfModule dir_module>\n";
+ $content.= "DirectoryIndex index.php index.html\n";
+ $content.= "</IfModule>\n";
+ $content.= "AddDefaultCharset utf-8\n";
$content.= "Options -Indexes\n";
@file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it
diff --git a/lib/setup/abstractdatabase.php b/lib/setup/abstractdatabase.php
new file mode 100644
index 00000000000..0beada7bd29
--- /dev/null
+++ b/lib/setup/abstractdatabase.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace OC\Setup;
+
+abstract class AbstractDatabase {
+ protected $trans;
+ protected $dbDefinitionFile;
+ protected $dbuser;
+ protected $dbpassword;
+ protected $dbname;
+ protected $dbhost;
+ protected $tableprefix;
+
+ public function __construct($trans, $dbDefinitionFile) {
+ $this->trans = $trans;
+ $this->dbDefinitionFile = $dbDefinitionFile;
+ }
+
+ public function validate($config) {
+ $errors = array();
+ if(empty($config['dbuser'])) {
+ $errors[] = $this->trans->t("%s enter the database username.", array($this->dbprettyname));
+ }
+ if(empty($config['dbname'])) {
+ $errors[] = $this->trans->t("%s enter the database name.", array($this->dbprettyname));
+ }
+ if(substr_count($config['dbname'], '.') >= 1) {
+ $errors[] = $this->trans->t("%s you may not use dots in the database name", array($this->dbprettyname));
+ }
+ return $errors;
+ }
+
+ public function initialize($config) {
+ $dbuser = $config['dbuser'];
+ $dbpass = $config['dbpass'];
+ $dbname = $config['dbname'];
+ $dbhost = !empty($config['dbhost']) ? $config['dbhost'] : 'localhost';
+ $dbtableprefix = isset($config['dbtableprefix']) ? $config['dbtableprefix'] : 'oc_';
+
+ \OC_Config::setValue('dbname', $dbname);
+ \OC_Config::setValue('dbhost', $dbhost);
+ \OC_Config::setValue('dbtableprefix', $dbtableprefix);
+
+ $this->dbuser = $dbuser;
+ $this->dbpassword = $dbpass;
+ $this->dbname = $dbname;
+ $this->dbhost = $dbhost;
+ $this->tableprefix = $dbtableprefix;
+ }
+}
diff --git a/lib/setup/mssql.php b/lib/setup/mssql.php
new file mode 100644
index 00000000000..b8329f99079
--- /dev/null
+++ b/lib/setup/mssql.php
@@ -0,0 +1,182 @@
+<?php
+
+namespace OC\Setup;
+
+class MSSQL extends AbstractDatabase {
+ public $dbprettyname = 'MS SQL Server';
+
+ public function setupDatabase() {
+ //check if the database user has admin right
+ $masterConnectionInfo = array( "Database" => "master", "UID" => $this->dbuser, "PWD" => $this->dbpassword);
+
+ $masterConnection = @sqlsrv_connect($this->dbhost, $masterConnectionInfo);
+ if(!$masterConnection) {
+ $entry = null;
+ if( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ throw new \DatabaseSetupException($this->trans->t('MS SQL username and/or password not valid: %s', array($entry)),
+ $this->trans->t('You need to enter either an existing account or the administrator.'));
+ }
+
+ \OC_Config::setValue('dbuser', $this->dbuser);
+ \OC_Config::setValue('dbpassword', $this->dbpassword);
+
+ $this->createDBLogin($masterConnection);
+
+ $this->createDatabase($masterConnection);
+
+ $this->createDBUser($masterConnection);
+
+ sqlsrv_close($masterConnection);
+
+ $this->createDatabaseStructure();
+ }
+
+ private function createDBLogin($connection) {
+ $query = "SELECT * FROM master.sys.server_principals WHERE name = '".$this->dbuser."';";
+ $result = sqlsrv_query($connection, $query);
+ if ($result === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ } else {
+ $row = sqlsrv_fetch_array($result);
+
+ if ($row === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ } else {
+ if ($row == null) {
+ $query = "CREATE LOGIN [".$this->dbuser."] WITH PASSWORD = '".$this->dbpassword."';";
+ $result = sqlsrv_query($connection, $query);
+ if (!$result or $result === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ }
+ }
+ }
+ }
+ }
+
+ private function createDBUser($connection) {
+ $query = "SELECT * FROM [".$this->dbname."].sys.database_principals WHERE name = '".$this->dbuser."';";
+ $result = sqlsrv_query($connection, $query);
+ if ($result === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ } else {
+ $row = sqlsrv_fetch_array($result);
+
+ if ($row === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ } else {
+ if ($row == null) {
+ $query = "USE [".$this->dbname."]; CREATE USER [".$this->dbuser."] FOR LOGIN [".$this->dbuser."];";
+ $result = sqlsrv_query($connection, $query);
+ if (!$result || $result === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry = 'DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ }
+ }
+
+ $query = "USE [".$this->dbname."]; EXEC sp_addrolemember 'db_owner', '".$this->dbuser."';";
+ $result = sqlsrv_query($connection, $query);
+ if (!$result || $result === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ }
+ }
+ }
+ }
+
+ private function createDatabase($connection) {
+ $query = "CREATE DATABASE [".$this->dbname."];";
+ $result = sqlsrv_query($connection, $query);
+ if (!$result || $result === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ }
+ }
+
+ private function createDatabaseStructure() {
+ $connectionInfo = array( "Database" => $this->dbname, "UID" => $this->dbuser, "PWD" => $this->dbpassword);
+
+ $connection = @sqlsrv_connect($this->dbhost, $connectionInfo);
+
+ //fill the database if needed
+ $query = "SELECT * FROM INFORMATION_SCHEMA.TABLES"
+ ." WHERE TABLE_SCHEMA = '".$this->dbname."'"
+ ." AND TABLE_NAME = '".$this->tableprefix."users'";
+ $result = sqlsrv_query($connection, $query);
+ if ($result === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ } else {
+ $row = sqlsrv_fetch_array($result);
+
+ if ($row === false) {
+ if ( ($errors = sqlsrv_errors() ) != null) {
+ $entry='DB Error: "'.print_r(sqlsrv_errors()).'"<br />';
+ } else {
+ $entry = '';
+ }
+ $entry.='Offending command was: '.$query.'<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ } else {
+ if ($row == null) {
+ \OC_DB::createDbFromStructure($this->dbDefinitionFile);
+ }
+ }
+ }
+
+ sqlsrv_close($connection);
+ }
+}
diff --git a/lib/setup/mysql.php b/lib/setup/mysql.php
new file mode 100644
index 00000000000..0cf04fde5a1
--- /dev/null
+++ b/lib/setup/mysql.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace OC\Setup;
+
+class MySQL extends AbstractDatabase {
+ public $dbprettyname = 'MySQL';
+
+ public function setupDatabase($username) {
+ //check if the database user has admin right
+ $connection = @mysql_connect($this->dbhost, $this->dbuser, $this->dbpassword);
+ if(!$connection) {
+ throw new \DatabaseSetupException($this->trans->t('MySQL username and/or password not valid'),
+ $this->trans->t('You need to enter either an existing account or the administrator.'));
+ }
+ $oldUser=\OC_Config::getValue('dbuser', false);
+
+ //this should be enough to check for admin rights in mysql
+ $query="SELECT user FROM mysql.user WHERE user='$this->dbuser'";
+ if(mysql_query($query, $connection)) {
+ //use the admin login data for the new database user
+
+ //add prefix to the mysql user name to prevent collisions
+ $this->dbuser=substr('oc_'.$username, 0, 16);
+ if($this->dbuser!=$oldUser) {
+ //hash the password so we don't need to store the admin config in the config file
+ $this->dbpassword=\OC_Util::generate_random_bytes(30);
+
+ $this->createDBUser($connection);
+
+ \OC_Config::setValue('dbuser', $this->dbuser);
+ \OC_Config::setValue('dbpassword', $this->dbpassword);
+ }
+
+ //create the database
+ $this->createDatabase($connection);
+ }
+ else {
+ if($this->dbuser!=$oldUser) {
+ \OC_Config::setValue('dbuser', $this->dbuser);
+ \OC_Config::setValue('dbpassword', $this->dbpassword);
+ }
+
+ //create the database
+ $this->createDatabase($connection);
+ }
+
+ //fill the database if needed
+ $query='select count(*) from information_schema.tables'
+ ." where table_schema='".$this->dbname."' AND table_name = '".$this->tableprefix."users';";
+ $result = mysql_query($query, $connection);
+ if($result) {
+ $row=mysql_fetch_row($result);
+ }
+ if(!$result or $row[0]==0) {
+ \OC_DB::createDbFromStructure($this->dbDefinitionFile);
+ }
+ mysql_close($connection);
+ }
+
+ private function createDatabase($connection) {
+ $name = $this->dbname;
+ $user = $this->dbuser;
+ //we cant use OC_BD functions here because we need to connect as the administrative user.
+ $query = "CREATE DATABASE IF NOT EXISTS `$name`";
+ $result = mysql_query($query, $connection);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(mysql_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.mssql', $entry, \OC_Log::WARN);
+ }
+ $query="GRANT ALL PRIVILEGES ON `$name` . * TO '$user'";
+
+ //this query will fail if there aren't the right permissions, ignore the error
+ mysql_query($query, $connection);
+ }
+
+ private function createDBUser($connection) {
+ $name = $this->dbuser;
+ $password = $this->dbpassword;
+ // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one,
+ // the anonymous user would take precedence when there is one.
+ $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'";
+ $result = mysql_query($query, $connection);
+ if (!$result) {
+ throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'localhost' exists already.", array($name)),
+ $this->trans->t("Drop this user from MySQL", array($name)));
+ }
+ $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'";
+ $result = mysql_query($query, $connection);
+ if (!$result) {
+ throw new \DatabaseSetupException($this->trans->t("MySQL user '%s'@'%%' already exists", array($name)),
+ $this->trans->t("Drop this user from MySQL."));
+ }
+ }
+}
diff --git a/lib/setup/oci.php b/lib/setup/oci.php
new file mode 100644
index 00000000000..86b53de45a4
--- /dev/null
+++ b/lib/setup/oci.php
@@ -0,0 +1,210 @@
+<?php
+
+namespace OC\Setup;
+
+class OCI extends AbstractDatabase {
+ public $dbprettyname = 'Oracle';
+
+ protected $dbtablespace;
+
+ public function initialize($config) {
+ parent::initialize($config);
+ if (array_key_exists('dbtablespace', $config)) {
+ $this->dbtablespace = $config['dbtablespace'];
+ } else {
+ $this->dbtablespace = 'USERS';
+ }
+ \OC_Config::setValue('dbtablespace', $this->dbtablespace);
+ }
+
+ public function setupDatabase($username) {
+ $e_host = addslashes($this->dbhost);
+ $e_dbname = addslashes($this->dbname);
+ //check if the database user has admin right
+ if ($e_host == '') {
+ $easy_connect_string = $e_dbname; // use dbname as easy connect name
+ } else {
+ $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
+ }
+ \OC_Log::write('setup oracle', 'connect string: ' . $easy_connect_string, \OC_Log::DEBUG);
+ $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string);
+ if(!$connection) {
+ $e = oci_error();
+ if (is_array ($e) && isset ($e['message'])) {
+ throw new \DatabaseSetupException($this->trans->t('Oracle connection could not be established'),
+ $e['message'].' Check environment: ORACLE_HOME='.getenv('ORACLE_HOME')
+ .' ORACLE_SID='.getenv('ORACLE_SID')
+ .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH')
+ .' NLS_LANG='.getenv('NLS_LANG')
+ .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable');
+ }
+ throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'),
+ 'Check environment: ORACLE_HOME='.getenv('ORACLE_HOME')
+ .' ORACLE_SID='.getenv('ORACLE_SID')
+ .' LD_LIBRARY_PATH='.getenv('LD_LIBRARY_PATH')
+ .' NLS_LANG='.getenv('NLS_LANG')
+ .' tnsnames.ora is '.(is_readable(getenv('ORACLE_HOME').'/network/admin/tnsnames.ora')?'':'not ').'readable');
+ }
+ //check for roles creation rights in oracle
+
+ $query='SELECT count(*) FROM user_role_privs, role_sys_privs'
+ ." WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'";
+ $stmt = oci_parse($connection, $query);
+ if (!$stmt) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_last_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ $result = oci_execute($stmt);
+ if($result) {
+ $row = oci_fetch_row($stmt);
+ }
+ if($result and $row[0] > 0) {
+ //use the admin login data for the new database user
+
+ //add prefix to the oracle user name to prevent collisions
+ $this->dbuser='oc_'.$username;
+ //create a new password so we don't need to store the admin config in the config file
+ $this->dbpassword=\OC_Util::generate_random_bytes(30);
+
+ //oracle passwords are treated as identifiers:
+ // must start with aphanumeric char
+ // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length.
+ $this->dbpassword=substr($this->dbpassword, 0, 30);
+
+ $this->createDBUser($connection);
+
+ \OC_Config::setValue('dbuser', $this->dbusername);
+ \OC_Config::setValue('dbname', $this->dbusername);
+ \OC_Config::setValue('dbpassword', $this->dbpassword);
+
+ //create the database not neccessary, oracle implies user = schema
+ //$this->createDatabase($this->dbname, $this->dbusername, $connection);
+ } else {
+
+ \OC_Config::setValue('dbuser', $this->dbuser);
+ \OC_Config::setValue('dbname', $this->dbname);
+ \OC_Config::setValue('dbpassword', $this->dbpassword);
+
+ //create the database not neccessary, oracle implies user = schema
+ //$this->createDatabase($this->dbname, $this->dbuser, $connection);
+ }
+
+ //FIXME check tablespace exists: select * from user_tablespaces
+
+ // the connection to dbname=oracle is not needed anymore
+ oci_close($connection);
+
+ // connect to the oracle database (schema=$this->dbuser) an check if the schema needs to be filled
+ $this->dbuser = \OC_Config::getValue('dbuser');
+ //$this->dbname = \OC_Config::getValue('dbname');
+ $this->dbpassword = \OC_Config::getValue('dbpassword');
+
+ $e_host = addslashes($this->dbhost);
+ $e_dbname = addslashes($this->dbname);
+
+ if ($e_host == '') {
+ $easy_connect_string = $e_dbname; // use dbname as easy connect name
+ } else {
+ $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
+ }
+ $connection = @oci_connect($this->dbuser, $this->dbpassword, $easy_connect_string);
+ if(!$connection) {
+ throw new \DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'),
+ $this->trans->t('You need to enter either an existing account or the administrator.'));
+ }
+ $query = "SELECT count(*) FROM user_tables WHERE table_name = :un";
+ $stmt = oci_parse($connection, $query);
+ $un = $this->dbtableprefix.'users';
+ oci_bind_by_name($stmt, ':un', $un);
+ if (!$stmt) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ $result = oci_execute($stmt);
+
+ if($result) {
+ $row = oci_fetch_row($stmt);
+ }
+ if(!$result or $row[0]==0) {
+ \OC_DB::createDbFromStructure($this->dbDefinitionFile);
+ }
+ }
+
+ /**
+ *
+ * @param String $name
+ * @param String $password
+ * @param resource $connection
+ */
+ private function createDBUser($connection) {
+ $name = $this->dbuser;
+ $password = $this->password;
+ $query = "SELECT * FROM all_users WHERE USERNAME = :un";
+ $stmt = oci_parse($connection, $query);
+ if (!$stmt) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ oci_bind_by_name($stmt, ':un', $name);
+ $result = oci_execute($stmt);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+
+ if(! oci_fetch_row($stmt)) {
+ //user does not exists let's create it :)
+ //password must start with alphabetic character in oracle
+ $query = 'CREATE USER '.$name.' IDENTIFIED BY "'.$password.'" DEFAULT TABLESPACE '.$this->dbtablespace;
+ $stmt = oci_parse($connection, $query);
+ if (!$stmt) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ //oci_bind_by_name($stmt, ':un', $name);
+ $result = oci_execute($stmt);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s',
+ array($query, $name, $password)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ } else { // change password of the existing role
+ $query = "ALTER USER :un IDENTIFIED BY :pw";
+ $stmt = oci_parse($connection, $query);
+ if (!$stmt) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ oci_bind_by_name($stmt, ':un', $name);
+ oci_bind_by_name($stmt, ':pw', $password);
+ $result = oci_execute($stmt);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ }
+ // grant necessary roles
+ $query = 'GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER, UNLIMITED TABLESPACE TO '.$name;
+ $stmt = oci_parse($connection, $query);
+ if (!$stmt) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ $result = oci_execute($stmt);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(oci_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s", name: %s, password: %s',
+ array($query, $name, $password)) . '<br />';
+ \OC_Log::write('setup.oci', $entry, \OC_Log::WARN);
+ }
+ }
+}
diff --git a/lib/setup/postgresql.php b/lib/setup/postgresql.php
new file mode 100644
index 00000000000..49fcbf0326e
--- /dev/null
+++ b/lib/setup/postgresql.php
@@ -0,0 +1,140 @@
+<?php
+
+namespace OC\Setup;
+
+class PostgreSQL extends AbstractDatabase {
+ public $dbprettyname = 'PostgreSQL';
+
+ public function setupDatabase($username) {
+ $e_host = addslashes($this->dbhost);
+ $e_user = addslashes($this->dbuser);
+ $e_password = addslashes($this->dbpassword);
+
+ //check if the database user has admin rights
+ $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'";
+ $connection = @pg_connect($connection_string);
+ if(!$connection) {
+ // Try if we can connect to the DB with the specified name
+ $e_dbname = addslashes($this->dbname);
+ $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'";
+ $connection = @pg_connect($connection_string);
+
+ if(!$connection)
+ throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'),
+ $this->trans->t('You need to enter either an existing account or the administrator.'));
+ }
+ $e_user = pg_escape_string($this->dbuser);
+ //check for roles creation rights in postgresql
+ $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'";
+ $result = pg_query($connection, $query);
+ if($result and pg_num_rows($result) > 0) {
+ //use the admin login data for the new database user
+
+ //add prefix to the postgresql user name to prevent collisions
+ $this->dbuser='oc_'.$username;
+ //create a new password so we don't need to store the admin config in the config file
+ $this->dbpassword=\OC_Util::generate_random_bytes(30);
+
+ $this->createDBUser($connection);
+
+ \OC_Config::setValue('dbuser', $this->dbuser);
+ \OC_Config::setValue('dbpassword', $this->dbpassword);
+
+ //create the database
+ $this->createDatabase($connection);
+ }
+ else {
+ \OC_Config::setValue('dbuser', $this->dbuser);
+ \OC_Config::setValue('dbpassword', $this->dbpassword);
+
+ //create the database
+ $this->createDatabase($connection);
+ }
+
+ // the connection to dbname=postgres is not needed anymore
+ pg_close($connection);
+
+ // connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled
+ $this->dbuser = \OC_Config::getValue('dbuser');
+ $this->dbpassword = \OC_Config::getValue('dbpassword');
+
+ $e_host = addslashes($this->dbhost);
+ $e_dbname = addslashes($this->dbname);
+ $e_user = addslashes($this->dbuser);
+ $e_password = addslashes($this->dbpassword);
+
+ $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'";
+ $connection = @pg_connect($connection_string);
+ if(!$connection) {
+ throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'),
+ $this->trans->t('You need to enter either an existing account or the administrator.'));
+ }
+ $query = "select count(*) FROM pg_class WHERE relname='".$this->tableprefix."users' limit 1";
+ $result = pg_query($connection, $query);
+ if($result) {
+ $row = pg_fetch_row($result);
+ }
+ if(!$result or $row[0]==0) {
+ \OC_DB::createDbFromStructure($this->dbDefinitionFile);
+ }
+ }
+
+ private function createDatabase($connection) {
+ //we cant use OC_BD functions here because we need to connect as the administrative user.
+ $e_name = pg_escape_string($this->dbname);
+ $e_user = pg_escape_string($this->dbuser);
+ $query = "select datname from pg_database where datname = '$e_name'";
+ $result = pg_query($connection, $query);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
+ }
+ if(! pg_fetch_row($result)) {
+ //The database does not exists... let's create it
+ $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\"";
+ $result = pg_query($connection, $query);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
+ }
+ else {
+ $query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC";
+ pg_query($connection, $query);
+ }
+ }
+ }
+
+ private function createDBUser($connection) {
+ $e_name = pg_escape_string($this->dbuser);
+ $e_password = pg_escape_string($this->dbpassword);
+ $query = "select * from pg_roles where rolname='$e_name';";
+ $result = pg_query($connection, $query);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
+ }
+
+ if(! pg_fetch_row($result)) {
+ //user does not exists let's create it :)
+ $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';";
+ $result = pg_query($connection, $query);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
+ }
+ }
+ else { // change password of the existing role
+ $query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';";
+ $result = pg_query($connection, $query);
+ if(!$result) {
+ $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
+ $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
+ \OC_Log::write('setup.pg', $entry, \OC_Log::WARN);
+ }
+ }
+ }
+}
diff --git a/lib/setup/sqlite.php b/lib/setup/sqlite.php
new file mode 100644
index 00000000000..fd4df792d62
--- /dev/null
+++ b/lib/setup/sqlite.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace OC\Setup;
+
+class Sqlite extends AbstractDatabase {
+ public $dbprettyname = 'Sqlite';
+
+ public function validate($config) {
+ return array();
+ }
+
+ public function initialize($config) {
+ }
+
+ public function setupDatabase($username) {
+ $datadir = \OC_Config::getValue('datadirectory');
+
+ //delete the old sqlite database first, might cause infinte loops otherwise
+ if(file_exists("$datadir/owncloud.db")) {
+ unlink("$datadir/owncloud.db");
+ }
+ //in case of sqlite, we can always fill the database
+ error_log("creating sqlite db");
+ \OC_DB::createDbFromStructure($this->dbDefinitionFile);
+ }
+}
diff --git a/lib/template.php b/lib/template.php
index 434c1e9e990..ae9ea187445 100644
--- a/lib/template.php
+++ b/lib/template.php
@@ -186,10 +186,15 @@ class OC_Template{
$this->l10n = OC_L10N::get($parts[0]);
// Some headers to enhance security
- header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains
header('X-XSS-Protection: 1; mode=block'); // Enforce browser based XSS filters
header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE
+ // iFrame Restriction Policy
+ $xFramePolicy = OC_Config::getValue('xframe_restriction', true);
+ if($xFramePolicy) {
+ header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains
+ }
+
// Content Security Policy
// If you change the standard policy, please also change it in config.sample.php
$policy = OC_Config::getValue('custom_csp_policy',
@@ -198,7 +203,8 @@ class OC_Template{
.'style-src \'self\' \'unsafe-inline\'; '
.'frame-src *; '
.'img-src *; '
- .'font-src \'self\' data:');
+ .'font-src \'self\' data:; '
+ .'media-src *');
header('Content-Security-Policy:'.$policy); // Standard
$this->findTemplate($name);
@@ -240,14 +246,14 @@ class OC_Template{
// if the formfactor is not yet autodetected do the
// autodetection now. For possible formfactors check the
// detectFormfactor documentation
- if(!isset($_SESSION['formfactor'])) {
- $_SESSION['formfactor'] = self::detectFormfactor();
+ if (!\OC::$session->exists('formfactor')) {
+ \OC::$session->set('formfactor', self::detectFormfactor());
}
// allow manual override via GET parameter
if(isset($_GET['formfactor'])) {
- $_SESSION['formfactor']=$_GET['formfactor'];
+ \OC::$session->set('formfactor', $_GET['formfactor']);
}
- $formfactor=$_SESSION['formfactor'];
+ $formfactor = \OC::$session->get('formfactor');
if($formfactor=='default') {
$fext='';
}elseif($formfactor=='mobile') {
@@ -272,7 +278,7 @@ class OC_Template{
protected function findTemplate($name)
{
// Read the selected theme from the config file
- $theme=OC_Config::getValue( "theme" );
+ $theme = OC_Util::getTheme();
// Read the detected formfactor and use the right file name.
$fext = self::getFormFactorExtension();
@@ -529,4 +535,25 @@ class OC_Template{
$content->printPage();
die();
}
+
+ /**
+ * print error page using Exception details
+ * @param Exception $exception
+ */
+
+ public static function printExceptionErrorPage(Exception $exception) {
+ $error_msg = $exception->getMessage();
+ if ($exception->getCode()) {
+ $error_msg = '['.$exception->getCode().'] '.$error_msg;
+ }
+ $hint = $exception->getTraceAsString();
+ while (method_exists($exception,'previous') && $exception = $exception->previous()) {
+ $error_msg .= '<br/>Caused by: ';
+ if ($exception->getCode()) {
+ $error_msg .= '['.$exception->getCode().'] ';
+ }
+ $error_msg .= $exception->getMessage();
+ };
+ self::printErrorPage($error_msg, $hint);
+ }
}
diff --git a/lib/templatelayout.php b/lib/templatelayout.php
index 29f120a6041..7115b8f0306 100644
--- a/lib/templatelayout.php
+++ b/lib/templatelayout.php
@@ -18,6 +18,20 @@ class OC_TemplateLayout extends OC_Template {
$this->assign('bodyid', 'body-user');
}
+ // Update notification
+ if(OC_Config::getValue('updatechecker', true) === true) {
+ $data=OC_Updater::check();
+ if(isset($data['version']) && $data['version'] != '' and $data['version'] !== Array() && OC_User::isAdminUser(OC_User::getUser())) {
+ $this->assign('updateAvailable', true);
+ $this->assign('updateVersion', $data['versionstring']);
+ $this->assign('updateLink', $data['web']);
+ } else {
+ $this->assign('updateAvailable', false); // No update available or not an admin user
+ }
+ } else {
+ $this->assign('updateAvailable', false); // Update check is disabled
+ }
+
// Add navigation entry
$this->assign( 'application', '', false );
$navigation = OC_App::getNavigation();
@@ -37,51 +51,35 @@ class OC_TemplateLayout extends OC_Template {
} else {
parent::__construct('core', 'layout.base');
}
+ $versionParameter = '?v=' . md5(implode(OC_Util::getVersion()));
// Add the js files
$jsfiles = self::findJavascriptFiles(OC_Util::$scripts);
$this->assign('jsfiles', array(), false);
if (OC_Config::getValue('installed', false) && $renderas!='error') {
- $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config'));
+ $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config') . $versionParameter);
}
if (!empty(OC_Util::$core_scripts)) {
- $this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false));
+ $this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false) . $versionParameter);
}
foreach($jsfiles as $info) {
$root = $info[0];
$web = $info[1];
$file = $info[2];
- $this->append( 'jsfiles', $web.'/'.$file);
+ $this->append( 'jsfiles', $web.'/'.$file . $versionParameter);
}
// Add the css files
$cssfiles = self::findStylesheetFiles(OC_Util::$styles);
$this->assign('cssfiles', array());
if (!empty(OC_Util::$core_styles)) {
- $this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false));
+ $this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false) . $versionParameter);
}
foreach($cssfiles as $info) {
$root = $info[0];
$web = $info[1];
$file = $info[2];
- $paths = explode('/', $file);
- $in_root = false;
- foreach(OC::$APPSROOTS as $app_root) {
- if($root == $app_root['path']) {
- $in_root = true;
- break;
- }
- }
-
- if($in_root ) {
- $app = $paths[0];
- unset($paths[0]);
- $path = implode('/', $paths);
- $this->append( 'cssfiles', OC_Helper::linkTo($app, $path));
- }
- else {
- $this->append( 'cssfiles', $web.'/'.$file);
- }
+ $this->append( 'cssfiles', $web.'/'.$file . $versionParameter);
}
}
@@ -102,7 +100,7 @@ class OC_TemplateLayout extends OC_Template {
static public function findStylesheetFiles($styles) {
// Read the selected theme from the config file
- $theme=OC_Config::getValue( 'theme' );
+ $theme = OC_Util::getTheme();
// Read the detected formfactor and use the right file name.
$fext = self::getFormFactorExtension();
@@ -110,7 +108,8 @@ class OC_TemplateLayout extends OC_Template {
$files = array();
foreach($styles as $style) {
// is it in 3rdparty?
- if(self::appendIfExist($files, OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $style.'.css')) {
+ if(strpos($style, '3rdparty') === 0 &&
+ self::appendIfExist($files, OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $style.'.css')) {
// or in the owncloud root?
}elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "$style$fext.css" )) {
@@ -121,20 +120,15 @@ class OC_TemplateLayout extends OC_Template {
}elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "core/$style.css" )) {
}else{
- $append = false;
- // or in apps?
- foreach( OC::$APPSROOTS as $apps_dir)
- {
- if(self::appendIfExist($files, $apps_dir['path'], $apps_dir['url'], "$style$fext.css")) {
- $append = true;
- break;
- }
- elseif(self::appendIfExist($files, $apps_dir['path'], $apps_dir['url'], "$style.css")) {
- $append = true;
- break;
- }
+ $app = substr($style, 0, strpos($style, '/'));
+ $style = substr($style, strpos($style, '/')+1);
+ $app_path = OC_App::getAppPath($app);
+ $app_url = OC::$WEBROOT . '/index.php/apps/' . $app;
+ if(self::appendIfExist($files, $app_path, $app_url, "$style$fext.css")) {
}
- if(! $append) {
+ elseif(self::appendIfExist($files, $app_path, $app_url, "$style.css")) {
+ }
+ else {
echo('css file not found: style:'.$style.' formfactor:'.$fext
.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT);
die();
@@ -160,7 +154,7 @@ class OC_TemplateLayout extends OC_Template {
static public function findJavascriptFiles($scripts) {
// Read the selected theme from the config file
- $theme=OC_Config::getValue( 'theme' );
+ $theme = OC_Util::getTheme();
// Read the detected formfactor and use the right file name.
$fext = self::getFormFactorExtension();
@@ -168,7 +162,8 @@ class OC_TemplateLayout extends OC_Template {
$files = array();
foreach($scripts as $script) {
// Is it in 3rd party?
- if(self::appendIfExist($files, OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $script.'.js')) {
+ if(strpos($script, '3rdparty') === 0 &&
+ self::appendIfExist($files, OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $script.'.js')) {
// Is it in apps and overwritten by the theme?
}elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script$fext.js" )) {
@@ -192,18 +187,15 @@ class OC_TemplateLayout extends OC_Template {
}else{
// Is it part of an app?
- $append = false;
- foreach( OC::$APPSROOTS as $apps_dir) {
- if(self::appendIfExist($files, $apps_dir['path'], OC::$WEBROOT.$apps_dir['url'], "$script$fext.js")) {
- $append = true;
- break;
- }
- elseif(self::appendIfExist($files, $apps_dir['path'], OC::$WEBROOT.$apps_dir['url'], "$script.js")) {
- $append = true;
- break;
- }
+ $app = substr($script, 0, strpos($script, '/'));
+ $script = substr($script, strpos($script, '/')+1);
+ $app_path = OC_App::getAppPath($app);
+ $app_url = OC_App::getAppWebPath($app);
+ if(self::appendIfExist($files, $app_path, $app_url, "$script$fext.js")) {
+ }
+ elseif(self::appendIfExist($files, $app_path, $app_url, "$script.js")) {
}
- if(! $append) {
+ else {
echo('js file not found: script:'.$script.' formfactor:'.$fext
.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT);
die();
diff --git a/lib/updater.php b/lib/updater.php
index e7d33ac2bb9..df7332a96a9 100644
--- a/lib/updater.php
+++ b/lib/updater.php
@@ -1,49 +1,67 @@
<?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/>.
- *
+ * 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;
+use OC\Hooks\BasicEmitter;
+
/**
- * Class that handels autoupdating of ownCloud
+ * Class that handles autoupdating of ownCloud
+ *
+ * Hooks provided in scope \OC\Updater
+ * - maintenanceStart()
+ * - maintenanceEnd()
+ * - dbUpgrade()
+ * - filecacheStart()
+ * - filecacheProgress(int $percentage)
+ * - filecacheDone()
+ * - failure(string $message)
*/
-class OC_Updater{
+class Updater extends BasicEmitter {
+
+ /**
+ * @var \OC\Log $log
+ */
+ private $log;
+
+ /**
+ * @param \OC\Log $log
+ */
+ public function __construct($log = null) {
+ $this->log = $log;
+ }
/**
* Check if a new version is available
+ * @param string $updateUrl the url to check, i.e. 'http://apps.owncloud.com/updater.php'
+ * @return array | bool
*/
- public static function check() {
- OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true));
- if(OC_Appconfig::getValue('core', 'installedat', '')=='') {
- OC_Appconfig::setValue('core', 'installedat', microtime(true));
+ public function check($updaterUrl) {
+
+ // Look up the cache - it is invalidated all 30 minutes
+ if ((\OC_Appconfig::getValue('core', 'lastupdatedat') + 1800) > time()) {
+ return json_decode(\OC_Appconfig::getValue('core', 'lastupdateResult'), true);
+ }
+
+ \OC_Appconfig::setValue('core', 'lastupdatedat', time());
+
+ if (\OC_Appconfig::getValue('core', 'installedat', '') == '') {
+ \OC_Appconfig::setValue('core', 'installedat', microtime(true));
}
- $updaterurl='http://apps.owncloud.com/updater.php';
- $version=OC_Util::getVersion();
- $version['installed']=OC_Appconfig::getValue('core', 'installedat');
- $version['updated']=OC_Appconfig::getValue('core', 'lastupdatedat');
- $version['updatechannel']='stable';
- $version['edition']=OC_Util::getEditionString();
- $versionstring=implode('x', $version);
+ $version = \OC_Util::getVersion();
+ $version['installed'] = \OC_Appconfig::getValue('core', 'installedat');
+ $version['updated'] = \OC_Appconfig::getValue('core', 'lastupdatedat');
+ $version['updatechannel'] = 'stable';
+ $version['edition'] = \OC_Util::getEditionString();
+ $versionString = implode('x', $version);
//fetch xml data from updater
- $url=$updaterurl.'?version='.$versionstring;
+ $url = $updaterUrl . '?version=' . $versionString;
// set a sensible timeout of 10 sec to stay responsive even if the update server is down.
$ctx = stream_context_create(
@@ -53,50 +71,89 @@ class OC_Updater{
)
)
);
- $xml=@file_get_contents($url, 0, $ctx);
- if($xml==false) {
+ $xml = @file_get_contents($url, 0, $ctx);
+ if ($xml == false) {
return array();
}
- $data=@simplexml_load_string($xml);
+ $data = @simplexml_load_string($xml);
- $tmp=array();
+ $tmp = array();
$tmp['version'] = $data->version;
$tmp['versionstring'] = $data->versionstring;
$tmp['url'] = $data->url;
$tmp['web'] = $data->web;
- return $tmp;
- }
+ // Cache the result
+ \OC_Appconfig::setValue('core', 'lastupdateResult', json_encode($data));
- public static function ShowUpdatingHint() {
- $l = OC_L10N::get('lib');
-
- if(OC_Config::getValue('updatechecker', true)==true) {
- $data=OC_Updater::check();
- if(isset($data['version']) and $data['version']<>'') {
- $txt='<span style="color:#AA0000; font-weight:bold;">'
- .$l->t('%s is available. Get <a href="%s">more information</a>',
- array($data['versionstring'], $data['web'])).'</span>';
- }else{
- $txt=$l->t('up to date');
- }
- }else{
- $txt=$l->t('updates check is disabled');
- }
- return($txt);
+ return $tmp;
}
-
/**
- * do ownCloud update
+ * runs the update actions in maintenance mode, does not upgrade the source files
*/
- public static function doUpdate() {
-
- //update ownCloud core
-
- //update all apps
+ public function upgrade() {
+ \OC_DB::enableCaching(false);
+ \OC_Config::setValue('maintenance', true);
+ $installedVersion = \OC_Config::getValue('version', '0.0.0');
+ $currentVersion = implode('.', \OC_Util::getVersion());
+ if ($this->log) {
+ $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
+ }
+ $this->emit('\OC\Updater', 'maintenanceStart');
+ try {
+ \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml');
+ $this->emit('\OC\Updater', 'dbUpgrade');
- //update version in config
+ // do a file cache upgrade for users with files
+ // this can take loooooooooooooooooooooooong
+ $this->upgradeFileCache();
+ } catch (\Exception $exception) {
+ $this->emit('\OC\Updater', 'failure', array($exception->getMessage()));
+ }
+ \OC_Config::setValue('version', implode('.', \OC_Util::getVersion()));
+ \OC_App::checkAppsRequirements();
+ // load all apps to also upgrade enabled apps
+ \OC_App::loadApps();
+ \OC_Config::setValue('maintenance', false);
+ $this->emit('\OC\Updater', 'maintenanceEnd');
+ }
+ private function upgradeFileCache() {
+ try {
+ $query = \OC_DB::prepare('
+ SELECT DISTINCT `user`
+ FROM `*PREFIX*fscache`
+ ');
+ $result = $query->execute();
+ } catch (\Exception $e) {
+ return;
+ }
+ $users = $result->fetchAll();
+ if (count($users) == 0) {
+ return;
+ }
+ $step = 100 / count($users);
+ $percentCompleted = 0;
+ $lastPercentCompletedOutput = 0;
+ $startInfoShown = false;
+ foreach ($users as $userRow) {
+ $user = $userRow['user'];
+ \OC\Files\Filesystem::initMountPoints($user);
+ \OC\Files\Cache\Upgrade::doSilentUpgrade($user);
+ if (!$startInfoShown) {
+ //We show it only now, because otherwise Info about upgraded apps
+ //will appear between this and progress info
+ $this->emit('\OC\Updater', 'filecacheStart');
+ $startInfoShown = true;
+ }
+ $percentCompleted += $step;
+ $out = floor($percentCompleted);
+ if ($out != $lastPercentCompletedOutput) {
+ $this->emit('\OC\Updater', 'filecacheProgress', array($out));
+ $lastPercentCompletedOutput = $out;
+ }
+ }
+ $this->emit('\OC\Updater', 'filecacheDone');
}
}
diff --git a/lib/user.php b/lib/user.php
index 6144f0f6bf9..830f13bb8df 100644
--- a/lib/user.php
+++ b/lib/user.php
@@ -30,35 +30,85 @@
* post_createUser(uid, password)
* pre_deleteUser(&run, uid)
* post_deleteUser(uid)
- * pre_setPassword(&run, uid, password)
- * post_setPassword(uid, password)
- * pre_login(&run, uid)
+ * pre_setPassword(&run, uid, password, recoveryPassword)
+ * post_setPassword(uid, password, recoveryPassword)
+ * pre_login(&run, uid, password)
* post_login(uid)
* logout()
*/
class OC_User {
- // The backend used for user management
- private static $_usedBackends = array();
+ public static $userSession = null;
+
+ private 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;
+ }
- private static $_setupedBackends = array();
+ /**
+ * @return \OC\User\Manager
+ */
+ private static function getManager() {
+ return self::getUserSession()->getManager();
+ }
- // Backends available (except database)
private static $_backends = array();
+ private static $_usedBackends = array();
+
+ private static $_setupedBackends = array();
+
/**
* @brief registers backend
- * @param $name name of the backend
- * @returns true/false
+ * @param string $backend name of the backend
+ * @deprecated Add classes by calling useBackend with a class instance instead
+ * @return bool
*
* Makes a list of backends that can be used by other modules
*/
- public static function registerBackend( $backend ) {
+ public static function registerBackend($backend) {
self::$_backends[] = $backend;
return true;
}
/**
* @brief gets available backends
+ * @deprecated
* @returns array of backends
*
* Returns the names of all backends.
@@ -69,6 +119,7 @@ class OC_User {
/**
* @brief gets used backends
+ * @deprecated
* @returns array of backends
*
* Returns the names of all used backends.
@@ -79,33 +130,36 @@ class OC_User {
/**
* @brief Adds the backend to the list of used backends
- * @param $backend default: database The backend to use for user managment
- * @returns true/false
+ * @param string | OC_User_Backend $backend default: database The backend to use for user management
+ * @return bool
*
* Set the User Authentication Module
*/
- public static function useBackend( $backend = 'database' ) {
- if($backend instanceof OC_User_Interface) {
- OC_Log::write('core', 'Adding user backend instance of '.get_class($backend).'.', OC_Log::DEBUG);
- self::$_usedBackends[get_class($backend)]=$backend;
+ public static function useBackend($backend = 'database') {
+ if ($backend instanceof OC_User_Interface) {
+ OC_Log::write('core', 'Adding user backend instance of ' . get_class($backend) . '.', OC_Log::DEBUG);
+ self::$_usedBackends[get_class($backend)] = $backend;
+ self::getManager()->registerBackend($backend);
} else {
// You'll never know what happens
- if( null === $backend OR !is_string( $backend )) {
+ if (null === $backend OR !is_string($backend)) {
$backend = 'database';
}
// Load backend
- switch( $backend ) {
+ switch ($backend) {
case 'database':
case 'mysql':
case 'sqlite':
- OC_Log::write('core', 'Adding user backend '.$backend.'.', OC_Log::DEBUG);
+ OC_Log::write('core', 'Adding user backend ' . $backend . '.', OC_Log::DEBUG);
self::$_usedBackends[$backend] = new OC_User_Database();
+ self::getManager()->registerBackend(self::$_usedBackends[$backend]);
break;
default:
- OC_Log::write('core', 'Adding default user backend '.$backend.'.', OC_Log::DEBUG);
+ OC_Log::write('core', 'Adding default user backend ' . $backend . '.', OC_Log::DEBUG);
$className = 'OC_USER_' . strToUpper($backend);
self::$_usedBackends[$backend] = new $className();
+ self::getManager()->registerBackend(self::$_usedBackends[$backend]);
break;
}
}
@@ -116,121 +170,73 @@ class OC_User {
* remove all used backends
*/
public static function clearBackends() {
- self::$_usedBackends=array();
+ self::$_usedBackends = array();
+ self::getManager()->clearBackends();
}
/**
* setup the configured backends in config.php
*/
public static function setupBackends() {
- $backends=OC_Config::getValue('user_backends', array());
- foreach($backends as $i=>$config) {
- $class=$config['class'];
- $arguments=$config['arguments'];
- if(class_exists($class)) {
- if(array_search($i, self::$_setupedBackends)===false) {
+ $backends = OC_Config::getValue('user_backends', array());
+ foreach ($backends as $i => $config) {
+ $class = $config['class'];
+ $arguments = $config['arguments'];
+ if (class_exists($class)) {
+ if (array_search($i, self::$_setupedBackends) === false) {
// make a reflection object
$reflectionObj = new ReflectionClass($class);
// use Reflection to create a new instance, using the $args
$backend = $reflectionObj->newInstanceArgs($arguments);
self::useBackend($backend);
- $_setupedBackends[]=$i;
+ self::$_setupedBackends[] = $i;
} else {
- OC_Log::write('core', 'User backend '.$class.' already initialized.', OC_Log::DEBUG);
+ OC_Log::write('core', 'User backend ' . $class . ' already initialized.', OC_Log::DEBUG);
}
} else {
- OC_Log::write('core', 'User backend '.$class.' not found.', OC_Log::ERROR);
+ OC_Log::write('core', 'User backend ' . $class . ' not found.', OC_Log::ERROR);
}
}
}
/**
* @brief Create a new user
- * @param $uid The username of the user to create
- * @param $password The password of the new user
- * @returns true/false
+ * @param string $uid The username of the user to create
+ * @param string $password The password of the new user
+ * @throws Exception
+ * @return bool true/false
*
* Creates a new user. Basic checking of username is done in OC_User
* itself, not in its subclasses.
*
* Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-"
*/
- public static function createUser( $uid, $password ) {
- // Check the name for bad characters
- // Allowed are: "a-z", "A-Z", "0-9" and "_.@-"
- if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $uid )) {
- throw new Exception('Only the following characters are allowed in a username:'
- .' "a-z", "A-Z", "0-9", and "_.@-"');
- }
- // No empty username
- if(trim($uid) == '') {
- throw new Exception('A valid username must be provided');
- }
- // No empty password
- if(trim($password) == '') {
- throw new Exception('A valid password must be provided');
- }
-
- // Check if user already exists
- if( self::userExistsForCreation($uid) ) {
- throw new Exception('The username is already being used');
- }
-
-
- $run = true;
- OC_Hook::emit( "OC_User", "pre_createUser", array( "run" => &$run, "uid" => $uid, "password" => $password ));
-
- if( $run ) {
- //create the user in the first backend that supports creating users
- foreach(self::$_usedBackends as $backend) {
- if(!$backend->implementsActions(OC_USER_BACKEND_CREATE_USER))
- continue;
-
- $backend->createUser($uid, $password);
- OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => $uid, "password" => $password ));
-
- return self::userExists($uid);
- }
- }
- return false;
+ public static function createUser($uid, $password) {
+ return self::getManager()->createUser($uid, $password);
}
/**
* @brief delete a user
- * @param $uid The username of the user to delete
- * @returns true/false
+ * @param string $uid The username of the user to delete
+ * @return bool
*
* Deletes a user
*/
- public static function deleteUser( $uid ) {
- $run = true;
- OC_Hook::emit( "OC_User", "pre_deleteUser", array( "run" => &$run, "uid" => $uid ));
-
- if( $run ) {
- //delete the user from all backends
- foreach(self::$_usedBackends as $backend) {
- $backend->deleteUser($uid);
- }
- if (self::userExists($uid)) {
- return false;
- }
+ public static function deleteUser($uid) {
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ $user->delete();
+
// We have to delete the user from all groups
- foreach( OC_Group::getUserGroups( $uid ) as $i ) {
- OC_Group::removeFromGroup( $uid, $i );
+ foreach (OC_Group::getUserGroups($uid) as $i) {
+ OC_Group::removeFromGroup($uid, $i);
}
// Delete the user's keys in preferences
OC_Preferences::deleteUser($uid);
// Delete user files in /data/
- OC_Helper::rmdirr(OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/'.$uid.'/');
-
- // Emit and exit
- OC_Hook::emit( "OC_User", "post_deleteUser", array( "uid" => $uid ));
- return true;
- }
- else{
- return false;
+ OC_Helper::rmdirr(OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid . '/');
}
}
@@ -238,75 +244,34 @@ class OC_User {
* @brief Try to login a user
* @param $uid The username of the user to log in
* @param $password The password of the user
- * @returns true/false
+ * @return bool
*
* Log in a user and regenerate a new session - if the password is ok
*/
- public static function login( $uid, $password ) {
- $run = true;
- OC_Hook::emit( "OC_User", "pre_login", array( "run" => &$run, "uid" => $uid ));
-
- if( $run ) {
- $uid = self::checkPassword( $uid, $password );
- $enabled = self::isEnabled($uid);
- if($uid && $enabled) {
- session_regenerate_id(true);
- self::setUserId($uid);
- self::setDisplayName($uid);
- OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password ));
- return true;
- }
- }
- return false;
+ public static function login($uid, $password) {
+ return self::getUserSession()->login($uid, $password);
}
/**
* @brief Sets user id for session and triggers emit
*/
public static function setUserId($uid) {
- $_SESSION['user_id'] = $uid;
+ OC::$session->set('user_id', $uid);
}
/**
* @brief Sets user display name for session
*/
public static function setDisplayName($uid, $displayName = null) {
- $result = false;
- if ($displayName ) {
- foreach(self::$_usedBackends as $backend) {
- if($backend->implementsActions(OC_USER_BACKEND_SET_DISPLAYNAME)) {
- if($backend->userExists($uid)) {
- $result |= $backend->setDisplayName($uid, $displayName);
- }
- }
- }
- } else {
- $displayName = self::determineDisplayName($uid);
- $result = true;
+ if (is_null($displayName)) {
+ $displayName = $uid;
}
- if (OC_User::getUser() === $uid) {
- $_SESSION['display_name'] = $displayName;
- }
- return $result;
- }
-
-
- /**
- * @brief get display name
- * @param $uid The username
- * @returns string display name or uid if no display name is defined
- *
- */
- private static function determineDisplayName( $uid ) {
- foreach(self::$_usedBackends as $backend) {
- if($backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) {
- $result=$backend->getDisplayName( $uid );
- if($result) {
- return $result;
- }
- }
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ return $user->setDisplayName($displayName);
+ } else {
+ return false;
}
- return $uid;
}
/**
@@ -315,36 +280,31 @@ class OC_User {
* Logout, destroys session
*/
public static function logout() {
- OC_Hook::emit( "OC_User", "logout", array());
- session_unset();
- session_destroy();
- OC_User::unsetMagicInCookie();
+ self::getUserSession()->logout();
}
/**
* @brief Check if the user is logged in
- * @returns true/false
+ * @returns bool
*
* Checks if the user is logged in
*/
public static function isLoggedIn() {
- if( isset($_SESSION['user_id']) AND $_SESSION['user_id']) {
+ if (\OC::$session->get('user_id')) {
OC_App::loadApps(array('authentication'));
self::setupBackends();
- if (self::userExists($_SESSION['user_id']) ) {
- return true;
- }
+ return self::userExists(\OC::$session->get('user_id'));
}
return false;
}
/**
* @brief Check if the user is an admin user
- * @param $uid uid of the admin
- * @returns bool
+ * @param string $uid uid of the admin
+ * @return bool
*/
public static function isAdminUser($uid) {
- if(OC_Group::inGroup($uid, 'admin' )) {
+ if (OC_Group::inGroup($uid, 'admin')) {
return true;
}
return false;
@@ -356,146 +316,132 @@ class OC_User {
* @return string uid or false
*/
public static function getUser() {
- if( isset($_SESSION['user_id']) AND $_SESSION['user_id'] ) {
- return $_SESSION['user_id'];
- }
- else{
+ $uid = OC::$session->get('user_id');
+ if (!is_null($uid)) {
+ return $uid;
+ } else {
return false;
}
}
/**
* @brief get the display name of the user currently logged in.
+ * @param string $uid
* @return string uid or false
*/
- public static function getDisplayName($user=null) {
- if ( $user ) {
- return self::determineDisplayName($user);
- } else if( isset($_SESSION['display_name']) AND $_SESSION['display_name'] ) {
- return $_SESSION['display_name'];
- }
- else{
- return false;
+ public static function getDisplayName($uid = null) {
+ if ($uid) {
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ return $user->getDisplayName();
+ } else {
+ return $uid;
+ }
+ } else {
+ $user = self::getUserSession()->getUser();
+ if ($user) {
+ return $user->getDisplayName();
+ } else {
+ return false;
+ }
}
}
/**
* @brief Autogenerate a password
- * @returns string
+ * @return string
*
* generates a password
*/
public static function generatePassword() {
- return uniqId();
+ return OC_Util::generate_random_bytes(30);
}
/**
* @brief Set password
- * @param $uid The username
- * @param $password The new password
- * @returns true/false
+ * @param string $uid The username
+ * @param string $password The new password
+ * @param string $recoveryPassword for the encryption app to reset encryption keys
+ * @return bool
*
* Change the password of a user
*/
- public static function setPassword( $uid, $password ) {
- $run = true;
- OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password ));
-
- if( $run ) {
- $success = false;
- foreach(self::$_usedBackends as $backend) {
- if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) {
- if($backend->userExists($uid)) {
- $success |= $backend->setPassword($uid, $password);
- }
- }
- }
- // invalidate all login cookies
- OC_Preferences::deleteApp($uid, 'login_token');
- OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password ));
- return $success;
- }
- else{
+ public static function setPassword($uid, $password, $recoveryPassword = null) {
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ return $user->setPassword($password, $recoveryPassword);
+ } else {
return false;
}
}
/**
* @brief Check whether user can change his password
- * @param $uid The username
- * @returns true/false
+ * @param string $uid The username
+ * @return bool
*
* Check whether a specified user can change his password
*/
public static function canUserChangePassword($uid) {
- foreach(self::$_usedBackends as $backend) {
- if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) {
- if($backend->userExists($uid)) {
- return true;
- }
- }
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ return $user->canChangePassword();
+ } else {
+ return false;
}
- return false;
}
/**
* @brief Check whether user can change his display name
- * @param $uid The username
- * @returns true/false
+ * @param string $uid The username
+ * @return bool
*
* Check whether a specified user can change his display name
*/
public static function canUserChangeDisplayName($uid) {
- if (OC_Config::getValue('allow_user_to_change_display_name', true)) {
- foreach(self::$_usedBackends as $backend) {
- if($backend->implementsActions(OC_USER_BACKEND_SET_DISPLAYNAME)) {
- if($backend->userExists($uid)) {
- return true;
- }
- }
- }
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ return $user->canChangeDisplayName();
+ } else {
+ return false;
}
- return false;
}
/**
* @brief Check if the password is correct
- * @param $uid The username
- * @param $password The password
- * @returns string
+ * @param string $uid The username
+ * @param string $password The password
+ * @return bool
*
* Check if the password is correct without logging in the user
* returns the user id or false
*/
- public static function checkPassword( $uid, $password ) {
- foreach(self::$_usedBackends as $backend) {
- if($backend->implementsActions(OC_USER_BACKEND_CHECK_PASSWORD)) {
- $result=$backend->checkPassword( $uid, $password );
- if($result) {
- return $result;
- }
+ 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;
}
}
/**
- * @brief Check if the password is correct
* @param string $uid The username
- * @param string $password The password
- * @returns string
+ * @return string
*
* returns the path to the users home directory
*/
public static function getHome($uid) {
- foreach(self::$_usedBackends as $backend) {
- if($backend->implementsActions(OC_USER_BACKEND_GET_HOME) && $backend->userExists($uid)) {
- $result=$backend->getHome($uid);
- if($result) {
- return $result;
- }
- }
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ return $user->getHome();
+ } else {
+ return OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
}
- return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid;
}
/**
@@ -505,148 +451,93 @@ class OC_User {
* Get a list of all users.
*/
public static function getUsers($search = '', $limit = null, $offset = null) {
- $users = array();
- foreach (self::$_usedBackends as $backend) {
- $backendUsers = $backend->getUsers($search, $limit, $offset);
- if (is_array($backendUsers)) {
- $users = array_merge($users, $backendUsers);
- }
+ $users = self::getManager()->search($search, $limit, $offset);
+ $uids = array();
+ foreach ($users as $user) {
+ $uids[] = $user->getUID();
}
- asort($users);
- return $users;
+ return $uids;
}
/**
* @brief Get a list of all users display name
- * @returns associative array with all display names (value) and corresponding uids (key)
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
+ * @return array associative array with all display names (value) and corresponding uids (key)
*
* Get a list of all display names and user ids.
*/
public static function getDisplayNames($search = '', $limit = null, $offset = null) {
$displayNames = array();
- foreach (self::$_usedBackends as $backend) {
- $backendDisplayNames = $backend->getDisplayNames($search, $limit, $offset);
- if (is_array($backendDisplayNames)) {
- $displayNames = array_merge($displayNames, $backendDisplayNames);
- }
+ $users = self::getManager()->searchDisplayName($search, $limit, $offset);
+ foreach ($users as $user) {
+ $displayNames[$user->getUID()] = $user->getDisplayName();
}
- asort($displayNames);
return $displayNames;
}
/**
* @brief check if a user exists
* @param string $uid the username
- * @param string $excludingBackend (default none)
* @return boolean
*/
- public static function userExists($uid, $excludingBackend=null) {
- foreach(self::$_usedBackends as $backend) {
- if (!is_null($excludingBackend) && !strcmp(get_class($backend), $excludingBackend)) {
- OC_Log::write('OC_User', $excludingBackend . 'excluded from user existance check.', OC_Log::DEBUG);
- continue;
- }
- $result=$backend->userExists($uid);
- if($result===true) {
- return true;
- }
- }
- return false;
+ public static function userExists($uid) {
+ return self::getManager()->userExists($uid);
}
- public static function userExistsForCreation($uid) {
- foreach(self::$_usedBackends as $backend) {
- if(!$backend->hasUserListings())
- continue;
-
- $result=$backend->userExists($uid);
- if($result===true) {
- return true;
- }
- }
- return false;
- }
-
/**
* disables a user
- * @param string $userid the user to disable
+ *
+ * @param string $uid the user to disable
*/
- public static function disableUser($userid) {
- $sql = "INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, `configkey`, `configvalue`) VALUES(?, ?, ?, ?)";
- $stmt = OC_DB::prepare($sql);
- if ( ! OC_DB::isError($stmt) ) {
- $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
- if ( OC_DB::isError($result) ) {
- OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
- }
- } else {
- OC_Log::write('OC_User', 'could not disable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
+ public static function disableUser($uid) {
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ $user->setEnabled(false);
}
}
/**
* enable a user
- * @param string $userid
+ *
+ * @param string $uid
*/
- public static function enableUser($userid) {
- $sql = 'DELETE FROM `*PREFIX*preferences`'
- ." WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?";
- $stmt = OC_DB::prepare($sql);
- if ( ! OC_DB::isError($stmt) ) {
- $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
- if ( OC_DB::isError($result) ) {
- OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR);
- }
- } else {
- OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
+ public static function enableUser($uid) {
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ $user->setEnabled(true);
}
}
/**
* checks if a user is enabled
- * @param string $userid
+ *
+ * @param string $uid
* @return bool
*/
- public static function isEnabled($userid) {
- $sql = 'SELECT `userid` FROM `*PREFIX*preferences`'
- .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?';
- $stmt = OC_DB::prepare($sql);
- if ( ! OC_DB::isError($stmt) ) {
- $result = $stmt->execute(array($userid, 'core', 'enabled', 'false'));
- if ( ! OC_DB::isError($result) ) {
- return $result->numRows() ? false : true;
- } else {
- OC_Log::write('OC_User',
- 'could not check if enabled: '. OC_DB::getErrorMessage($result),
- OC_Log::ERROR);
- }
+ public static function isEnabled($uid) {
+ $user = self::getManager()->get($uid);
+ if ($user) {
+ return $user->isEnabled();
} else {
- OC_Log::write('OC_User', 'could not check if enabled: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR);
+ return false;
}
- return false;
}
/**
* @brief Set cookie value to use in next page load
* @param string $username username to be set
+ * @param string $token
*/
public static function setMagicInCookie($username, $token) {
- $secure_cookie = OC_Config::getValue("forcessl", false);
- $expires = time() + OC_Config::getValue('remember_login_cookie_lifetime', 60*60*24*15);
- setcookie("oc_username", $username, $expires, '', '', $secure_cookie);
- setcookie("oc_token", $token, $expires, '', '', $secure_cookie, true);
- setcookie("oc_remember_login", true, $expires, '', '', $secure_cookie);
+ self::getUserSession()->setMagicInCookie($username, $token);
}
/**
* @brief Remove cookie for "remember username"
*/
public static function unsetMagicInCookie() {
- unset($_COOKIE["oc_username"]);
- unset($_COOKIE["oc_token"]);
- unset($_COOKIE["oc_remember_login"]);
- setcookie("oc_username", null, -1);
- setcookie("oc_token", null, -1);
- setcookie("oc_remember_login", null, -1);
+ self::getUserSession()->unsetMagicInCookie();
}
}
diff --git a/lib/user/backend.php b/lib/user/backend.php
index 93e8f17ca98..e9be08e429c 100644
--- a/lib/user/backend.php
+++ b/lib/user/backend.php
@@ -58,7 +58,7 @@ abstract class OC_User_Backend implements OC_User_Interface {
/**
* @brief Get all supported actions
- * @returns bitwise-or'ed actions
+ * @return int bitwise-or'ed actions
*
* Returns the supported actions as int to be
* compared with OC_USER_BACKEND_CREATE_USER etc.
@@ -76,8 +76,8 @@ abstract class OC_User_Backend implements OC_User_Interface {
/**
* @brief Check if backend implements actions
- * @param $actions bitwise-or'ed actions
- * @returns boolean
+ * @param int $actions bitwise-or'ed actions
+ * @return boolean
*
* Returns the supported actions as int to be
* compared with OC_USER_BACKEND_CREATE_USER etc.
@@ -87,12 +87,12 @@ abstract class OC_User_Backend implements OC_User_Interface {
}
/**
- * @brief delete a user
- * @param $uid The username of the user to delete
- * @returns true/false
- *
- * Deletes a user
- */
+ * @brief delete a user
+ * @param string $uid The username of the user to delete
+ * @return bool
+ *
+ * Deletes a user
+ */
public function deleteUser( $uid ) {
return false;
}
@@ -127,8 +127,8 @@ abstract class OC_User_Backend implements OC_User_Interface {
/**
* @brief get display name of the user
- * @param $uid user ID of the user
- * @return display name
+ * @param string $uid user ID of the user
+ * @return string display name
*/
public function getDisplayName($uid) {
return $uid;
diff --git a/lib/user/database.php b/lib/user/database.php
index 210c7f3e1eb..9f00a022d9f 100644
--- a/lib/user/database.php
+++ b/lib/user/database.php
@@ -46,7 +46,7 @@ class OC_User_Database extends OC_User_Backend {
private function getHasher() {
if(!self::$hasher) {
- //we don't want to use DES based crypt(), since it doesn't return a has with a recognisable prefix
+ //we don't want to use DES based crypt(), since it doesn't return a hash with a recognisable prefix
$forcePortable=(CRYPT_BLOWFISH!=1);
self::$hasher=new PasswordHash(8, $forcePortable);
}
@@ -85,7 +85,7 @@ class OC_User_Database extends OC_User_Backend {
*/
public function deleteUser( $uid ) {
// Delete user-group-relation
- $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*users` WHERE uid = ?' );
+ $query = OC_DB::prepare( 'DELETE FROM `*PREFIX*users` WHERE `uid` = ?' );
$query->execute( array( $uid ));
return true;
}
@@ -136,7 +136,7 @@ class OC_User_Database extends OC_User_Backend {
*/
public function getDisplayName($uid) {
if( $this->userExists($uid) ) {
- $query = OC_DB::prepare( 'SELECT displayname FROM `*PREFIX*users` WHERE `uid` = ?' );
+ $query = OC_DB::prepare( 'SELECT `displayname` FROM `*PREFIX*users` WHERE `uid` = ?' );
$result = $query->execute( array( $uid ))->fetchAll();
$displayName = trim($result[0]['displayname'], ' ');
if ( !empty($displayName) ) {
@@ -237,13 +237,13 @@ class OC_User_Database extends OC_User_Backend {
* @return boolean
*/
public function userExists($uid) {
- $query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' );
+ $query = OC_DB::prepare( 'SELECT COUNT(*) FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' );
$result = $query->execute( array( $uid ));
if (OC_DB::isError($result)) {
OC_Log::write('core', OC_DB::getErrorMessage($result), OC_Log::ERROR);
return false;
}
- return $result->numRows() > 0;
+ return $result->fetchOne() > 0;
}
/**
diff --git a/lib/user/dummy.php b/lib/user/dummy.php
index d63f60efbeb..b5b7a6c3c7a 100644
--- a/lib/user/dummy.php
+++ b/lib/user/dummy.php
@@ -1,114 +1,118 @@
<?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/>.
-*
-*/
+ * 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/>.
+ *
+ */
/**
* dummy user backend, does not keep state, only for testing use
*/
class OC_User_Dummy extends OC_User_Backend {
- private $users=array();
+ private $users = array();
+
/**
- * @brief Create a new user
- * @param $uid The username of the user to create
- * @param $password The password of the new user
- * @returns true/false
- *
- * Creates a new user. Basic checking of username is done in OC_User
- * itself, not in its subclasses.
- */
+ * @brief Create a new user
+ * @param string $uid The username of the user to create
+ * @param string $password The password of the new user
+ * @return bool
+ *
+ * Creates a new user. Basic checking of username is done in OC_User
+ * itself, not in its subclasses.
+ */
public function createUser($uid, $password) {
- if(isset($this->users[$uid])) {
+ if (isset($this->users[$uid])) {
return false;
- }else{
- $this->users[$uid]=$password;
+ } else {
+ $this->users[$uid] = $password;
return true;
}
}
/**
- * @brief delete a user
- * @param $uid The username of the user to delete
- * @returns true/false
- *
- * Deletes a user
- */
- public function deleteUser( $uid ) {
- if(isset($this->users[$uid])) {
+ * @brief delete a user
+ * @param string $uid The username of the user to delete
+ * @return bool
+ *
+ * Deletes a user
+ */
+ public function deleteUser($uid) {
+ if (isset($this->users[$uid])) {
unset($this->users[$uid]);
return true;
- }else{
+ } else {
return false;
}
}
/**
- * @brief Set password
- * @param $uid The username
- * @param $password The new password
- * @returns true/false
- *
- * Change the password of a user
- */
+ * @brief Set password
+ * @param string $uid The username
+ * @param string $password The new password
+ * @return bool
+ *
+ * Change the password of a user
+ */
public function setPassword($uid, $password) {
- if(isset($this->users[$uid])) {
- $this->users[$uid]=$password;
+ if (isset($this->users[$uid])) {
+ $this->users[$uid] = $password;
return true;
- }else{
+ } else {
return false;
}
}
/**
- * @brief Check if the password is correct
- * @param $uid The username
- * @param $password The password
- * @returns string
- *
- * Check if the password is correct without logging in the user
- * returns the user id or false
- */
+ * @brief Check if the password is correct
+ * @param string $uid The username
+ * @param string $password The password
+ * @return string
+ *
+ * Check if the password is correct without logging in the user
+ * returns the user id or false
+ */
public function checkPassword($uid, $password) {
- if(isset($this->users[$uid])) {
- return ($this->users[$uid]==$password);
- }else{
+ if (isset($this->users[$uid])) {
+ return ($this->users[$uid] == $password);
+ } else {
return false;
}
}
/**
- * @brief Get a list of all users
- * @returns array with all uids
- *
- * Get a list of all users.
- */
+ * @brief Get a list of all users
+ * @param string $search
+ * @param int $limit
+ * @param int $offset
+ * @return array with all uids
+ *
+ * Get a list of all users.
+ */
public function getUsers($search = '', $limit = null, $offset = null) {
return array_keys($this->users);
}
/**
- * @brief check if a user exists
- * @param string $uid the username
- * @return boolean
- */
+ * @brief check if a user exists
+ * @param string $uid the username
+ * @return boolean
+ */
public function userExists($uid) {
return isset($this->users[$uid]);
}
diff --git a/lib/user/manager.php b/lib/user/manager.php
new file mode 100644
index 00000000000..d17cdf1a200
--- /dev/null
+++ b/lib/user/manager.php
@@ -0,0 +1,228 @@
+<?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\User;
+
+use OC\Hooks\PublicEmitter;
+
+/**
+ * Class Manager
+ *
+ * Hooks available in scope \OC\User:
+ * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
+ * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
+ * - preDelete(\OC\User\User $user)
+ * - postDelete(\OC\User\User $user)
+ * - preCreateUser(string $uid, string $password)
+ * - postCreateUser(\OC\User\User $user, string $password)
+ *
+ * @package OC\User
+ */
+class Manager extends PublicEmitter {
+ /**
+ * @var \OC_User_Backend[] $backends
+ */
+ private $backends = array();
+
+ private $cachedUsers = array();
+
+ public function __construct() {
+ $cachedUsers = $this->cachedUsers;
+ $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
+ $i = array_search($user, $cachedUsers);
+ if ($i !== false) {
+ unset($cachedUsers[$i]);
+ }
+ });
+ }
+
+ /**
+ * register a user backend
+ *
+ * @param \OC_User_Backend $backend
+ */
+ public function registerBackend($backend) {
+ $this->backends[] = $backend;
+ }
+
+ /**
+ * remove a user backend
+ *
+ * @param \OC_User_Backend $backend
+ */
+ public function removeBackend($backend) {
+ $this->cachedUsers = array();
+ if (($i = array_search($backend, $this->backends)) !== false) {
+ unset($this->backends[$i]);
+ }
+ }
+
+ /**
+ * remove all user backends
+ */
+ public function clearBackends() {
+ $this->cachedUsers = array();
+ $this->backends = array();
+ }
+
+ /**
+ * get a user by user id
+ *
+ * @param string $uid
+ * @return \OC\User\User
+ */
+ public function get($uid) {
+ if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
+ return $this->cachedUsers[$uid];
+ }
+ foreach ($this->backends as $backend) {
+ if ($backend->userExists($uid)) {
+ return $this->getUserObject($uid, $backend);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * get or construct the user object
+ *
+ * @param string $uid
+ * @param \OC_User_Backend $backend
+ * @return \OC\User\User
+ */
+ protected function getUserObject($uid, $backend) {
+ if (isset($this->cachedUsers[$uid])) {
+ return $this->cachedUsers[$uid];
+ }
+ $this->cachedUsers[$uid] = new User($uid, $backend, $this);
+ return $this->cachedUsers[$uid];
+ }
+
+ /**
+ * check if a user exists
+ *
+ * @param string $uid
+ * @return bool
+ */
+ public function userExists($uid) {
+ $user = $this->get($uid);
+ return ($user !== null);
+ }
+
+ /**
+ * search by user id
+ *
+ * @param string $pattern
+ * @param int $limit
+ * @param int $offset
+ * @return \OC\User\User[]
+ */
+ public function search($pattern, $limit = null, $offset = null) {
+ $users = array();
+ foreach ($this->backends as $backend) {
+ $backendUsers = $backend->getUsers($pattern, $limit, $offset);
+ if (is_array($backendUsers)) {
+ foreach ($backendUsers as $uid) {
+ $users[] = $this->getUserObject($uid, $backend);
+ if (!is_null($limit)) {
+ $limit--;
+ }
+ if (!is_null($offset) and $offset > 0) {
+ $offset--;
+ }
+
+ }
+ }
+ }
+
+ usort($users, function ($a, $b) {
+ /**
+ * @var \OC\User\User $a
+ * @var \OC\User\User $b
+ */
+ return strcmp($a->getUID(), $b->getUID());
+ });
+ return $users;
+ }
+
+ /**
+ * search by displayName
+ *
+ * @param string $pattern
+ * @param int $limit
+ * @param int $offset
+ * @return \OC\User\User[]
+ */
+ public function searchDisplayName($pattern, $limit = null, $offset = null) {
+ $users = array();
+ foreach ($this->backends as $backend) {
+ $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
+ if (is_array($backendUsers)) {
+ foreach ($backendUsers as $uid => $displayName) {
+ $users[] = $this->getUserObject($uid, $backend);
+ if (!is_null($limit)) {
+ $limit--;
+ }
+ if (!is_null($offset) and $offset > 0) {
+ $offset--;
+ }
+
+ }
+ }
+ }
+
+ usort($users, function ($a, $b) {
+ /**
+ * @var \OC\User\User $a
+ * @var \OC\User\User $b
+ */
+ return strcmp($a->getDisplayName(), $b->getDisplayName());
+ });
+ return $users;
+ }
+
+ /**
+ * @param string $uid
+ * @param string $password
+ * @throws \Exception
+ * @return bool | \OC\User\User the created user of false
+ */
+ public function createUser($uid, $password) {
+ // Check the name for bad characters
+ // Allowed are: "a-z", "A-Z", "0-9" and "_.@-"
+ if (preg_match('/[^a-zA-Z0-9 _\.@\-]/', $uid)) {
+ throw new \Exception('Only the following characters are allowed in a username:'
+ . ' "a-z", "A-Z", "0-9", and "_.@-"');
+ }
+ // No empty username
+ if (trim($uid) == '') {
+ throw new \Exception('A valid username must be provided');
+ }
+ // No empty password
+ if (trim($password) == '') {
+ throw new \Exception('A valid password must be provided');
+ }
+
+ // Check if user already exists
+ if ($this->userExists($uid)) {
+ throw new \Exception('The username is already being used');
+ }
+
+ $this->emit('\OC\User', 'preCreateUser', array($uid, $password));
+ foreach ($this->backends as $backend) {
+ if ($backend->implementsActions(\OC_USER_BACKEND_CREATE_USER)) {
+ $backend->createUser($uid, $password);
+ $user = $this->getUserObject($uid, $backend);
+ $this->emit('\OC\User', 'postCreateUser', array($user, $password));
+ return $user;
+ }
+ }
+ return false;
+ }
+}
diff --git a/lib/user/session.php b/lib/user/session.php
new file mode 100644
index 00000000000..9a6c669e935
--- /dev/null
+++ b/lib/user/session.php
@@ -0,0 +1,173 @@
+<?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\User;
+
+use OC\Hooks\Emitter;
+
+/**
+ * Class Session
+ *
+ * Hooks available in scope \OC\User:
+ * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
+ * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
+ * - preDelete(\OC\User\User $user)
+ * - postDelete(\OC\User\User $user)
+ * - preCreateUser(string $uid, string $password)
+ * - postCreateUser(\OC\User\User $user)
+ * - preLogin(string $user, string $password)
+ * - postLogin(\OC\User\User $user)
+ * - logout()
+ *
+ * @package OC\User
+ */
+class Session implements Emitter {
+ /**
+ * @var \OC\User\Manager $manager
+ */
+ private $manager;
+
+ /**
+ * @var \OC\Session\Session $session
+ */
+ private $session;
+
+ /**
+ * @var \OC\User\User $activeUser
+ */
+ protected $activeUser;
+
+ /**
+ * @param \OC\User\Manager $manager
+ * @param \OC\Session\Session $session
+ */
+ public function __construct($manager, $session) {
+ $this->manager = $manager;
+ $this->session = $session;
+ }
+
+ /**
+ * @param string $scope
+ * @param string $method
+ * @param callable $callback
+ */
+ public function listen($scope, $method, $callback) {
+ $this->manager->listen($scope, $method, $callback);
+ }
+
+ /**
+ * @param string $scope optional
+ * @param string $method optional
+ * @param callable $callback optional
+ */
+ public function removeListener($scope = null, $method = null, $callback = null) {
+ $this->manager->removeListener($scope, $method, $callback);
+ }
+
+ /**
+ * get the manager object
+ *
+ * @return \OC\User\Manager
+ */
+ public function getManager() {
+ return $this->manager;
+ }
+
+ /**
+ * set the currently active user
+ *
+ * @param \OC\User\User $user
+ */
+ public function setUser($user) {
+ if (is_null($user)) {
+ $this->session->remove('user_id');
+ } else {
+ $this->session->set('user_id', $user->getUID());
+ }
+ $this->activeUser = $user;
+ }
+
+ /**
+ * get the current active user
+ *
+ * @return \OC\User\User
+ */
+ public function getUser() {
+ if ($this->activeUser) {
+ return $this->activeUser;
+ } else {
+ $uid = $this->session->get('user_id');
+ if ($uid) {
+ $this->activeUser = $this->manager->get($uid);
+ return $this->activeUser;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * try to login with the provided credentials
+ *
+ * @param string $uid
+ * @param string $password
+ * @return bool
+ */
+ public function login($uid, $password) {
+ $this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
+ $user = $this->manager->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;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * logout the user from the session
+ */
+ public function logout() {
+ $this->manager->emit('\OC\User', 'logout');
+ $this->setUser(null);
+ $this->unsetMagicInCookie();
+ }
+
+ /**
+ * Set cookie value to use in next page load
+ *
+ * @param string $username username to be set
+ * @param string $token
+ */
+ public function setMagicInCookie($username, $token) {
+ $secure_cookie = \OC_Config::getValue("forcessl", false); //TODO: DI for cookies and OC_Config
+ $expires = time() + \OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
+ setcookie("oc_username", $username, $expires, \OC::$WEBROOT, '', $secure_cookie);
+ setcookie("oc_token", $token, $expires, \OC::$WEBROOT, '', $secure_cookie, true);
+ setcookie("oc_remember_login", true, $expires, \OC::$WEBROOT, '', $secure_cookie);
+ }
+
+ /**
+ * Remove cookie for "remember username"
+ */
+ public function unsetMagicInCookie() {
+ unset($_COOKIE["oc_username"]); //TODO: DI
+ unset($_COOKIE["oc_token"]);
+ unset($_COOKIE["oc_remember_login"]);
+ setcookie('oc_username', '', time()-3600, \OC::$WEBROOT);
+ setcookie('oc_token', '', time()-3600, \OC::$WEBROOT);
+ setcookie('oc_remember_login', '', time()-3600, \OC::$WEBROOT);
+ }
+}
diff --git a/lib/user/user.php b/lib/user/user.php
new file mode 100644
index 00000000000..55d7848a979
--- /dev/null
+++ b/lib/user/user.php
@@ -0,0 +1,197 @@
+<?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\User;
+
+use OC\Hooks\Emitter;
+
+class User {
+ /**
+ * @var string $uid
+ */
+ private $uid;
+
+ /**
+ * @var string $displayName
+ */
+ private $displayName;
+
+ /**
+ * @var \OC_User_Backend $backend
+ */
+ private $backend;
+
+ /**
+ * @var bool $enabled
+ */
+ private $enabled;
+
+ /**
+ * @var Emitter | Manager $emitter
+ */
+ private $emitter;
+
+ /**
+ * @param string $uid
+ * @param \OC_User_Backend $backend
+ * @param Emitter $emitter
+ */
+ public function __construct($uid, $backend, $emitter = null) {
+ $this->uid = $uid;
+ if ($backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) {
+ $this->displayName = $backend->getDisplayName($uid);
+ } else {
+ $this->displayName = $uid;
+ }
+ $this->backend = $backend;
+ $this->emitter = $emitter;
+ $enabled = \OC_Preferences::getValue($uid, 'core', 'enabled', 'true'); //TODO: DI for OC_Preferences
+ $this->enabled = ($enabled === 'true');
+ }
+
+ /**
+ * get the user id
+ *
+ * @return string
+ */
+ public function getUID() {
+ return $this->uid;
+ }
+
+ /**
+ * get the displayname for the user, if no specific displayname is set it will fallback to the user id
+ *
+ * @return string
+ */
+ public function getDisplayName() {
+ return $this->displayName;
+ }
+
+ /**
+ * set the displayname for the user
+ *
+ * @param string $displayName
+ * @return bool
+ */
+ public function setDisplayName($displayName) {
+ if ($this->canChangeDisplayName()) {
+ $this->displayName = $displayName;
+ $result = $this->backend->setDisplayName($this->uid, $displayName);
+ return $result !== false;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Delete the user
+ *
+ * @return bool
+ */
+ public function delete() {
+ if ($this->emitter) {
+ $this->emitter->emit('\OC\User', 'preDelete', array($this));
+ }
+ $result = $this->backend->deleteUser($this->uid);
+ if ($this->emitter) {
+ $this->emitter->emit('\OC\User', 'postDelete', array($this));
+ }
+ return !($result === false);
+ }
+
+ /**
+ * 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
+ * @param string $recoveryPassword for the encryption app to reset encryption keys
+ * @return bool
+ */
+ public function setPassword($password, $recoveryPassword) {
+ if ($this->emitter) {
+ $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword));
+ }
+ if ($this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD)) {
+ $result = $this->backend->setPassword($this->uid, $password);
+ if ($this->emitter) {
+ $this->emitter->emit('\OC\User', 'postSetPassword', array($this, $password, $recoveryPassword));
+ }
+ return !($result === false);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * get the users home folder to mount
+ *
+ * @return string
+ */
+ public function getHome() {
+ if ($this->backend->implementsActions(\OC_USER_BACKEND_GET_HOME) and $home = $this->backend->getHome($this->uid)) {
+ return $home;
+ }
+ return \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $this->uid; //TODO switch to Config object once implemented
+ }
+
+ /**
+ * check if the backend supports changing passwords
+ *
+ * @return bool
+ */
+ public function canChangePassword() {
+ return $this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD);
+ }
+
+ /**
+ * check if the backend supports changing display names
+ *
+ * @return bool
+ */
+ public function canChangeDisplayName() {
+ return $this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME);
+ }
+
+ /**
+ * check if the user is enabled
+ *
+ * @return bool
+ */
+ public function isEnabled() {
+ return $this->enabled;
+ }
+
+ /**
+ * set the enabled status for the user
+ *
+ * @param bool $enabled
+ */
+ public function setEnabled($enabled) {
+ $this->enabled = $enabled;
+ $enabled = ($enabled) ? 'true' : 'false';
+ \OC_Preferences::setValue($this->uid, 'core', 'enabled', $enabled);
+ }
+}
diff --git a/lib/util.php b/lib/util.php
index e79daae8a0a..981b05b2b46 100755
--- a/lib/util.php
+++ b/lib/util.php
@@ -1,4 +1,7 @@
<?php
+
+require_once 'Patchwork/PHP/Shim/Normalizer.php';
+
/**
* Class for utility functions
*
@@ -38,6 +41,7 @@ class OC_Util {
$CONFIG_DATADIRECTORY = 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;
@@ -66,6 +70,7 @@ class OC_Util {
public static function tearDownFS() {
\OC\Files\Filesystem::tearDown();
self::$fsSetup=false;
+ self::$rootMounted=false;
}
/**
@@ -75,7 +80,7 @@ class OC_Util {
public static function getVersion() {
// hint: We only can count up. Reset minor/patchlevel when
// updating major/minor version number.
- return array(5, 80, 00);
+ return array(5, 80, 05);
}
/**
@@ -149,10 +154,10 @@ class OC_Util {
* @param bool dateOnly option to omit time from the result
*/
public static function formatDate( $timestamp, $dateOnly=false) {
- if(isset($_SESSION['timezone'])) {//adjust to clients timezone if we know it
+ if(\OC::$session->exists('timezone')) {//adjust to clients timezone if we know it
$systemTimeZone = intval(date('O'));
$systemTimeZone=(round($systemTimeZone/100, 0)*60)+($systemTimeZone%100);
- $clientTimeZone=$_SESSION['timezone']*60;
+ $clientTimeZone=\OC::$session->get('timezone')*60;
$offset=$clientTimeZone-$systemTimeZone;
$timestamp=$timestamp+$offset*60;
}
@@ -167,25 +172,30 @@ class OC_Util {
public static function checkServer() {
$errors=array();
+ $defaults = new \OC_Defaults();
+
$web_server_restart= 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('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;
}
//common hint for all file permissons error messages
- $permissionsHint='Permissions can usually be fixed by giving the webserver write access'
- .' to the ownCloud directory';
+ $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>.';
// 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 'config'",
- 'hint'=>'You can usually fix this by giving the webserver user write access'
- .' to the config directory in owncloud');
+ $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>.'
+ );
}
// Check if there is a writable install folder.
@@ -193,9 +203,12 @@ class OC_Util {
if( OC_App::getInstallPath() === null
|| !is_writable(OC_App::getInstallPath())
|| !is_readable(OC_App::getInstallPath()) ) {
- $errors[]=array('error'=>"Can't write into apps directory",
- 'hint'=>'You can usually fix this by giving the webserver user write access'
- .' to the apps directory in owncloud or disabling the appstore in the config file.');
+ $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> '
+ .'or disabling the appstore in the config file.'
+ );
}
}
$CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
@@ -205,10 +218,11 @@ class OC_Util {
if ($success) {
$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
} else {
- $errors[]=array('error'=>"Can't create data directory (".$CONFIG_DATADIRECTORY.")",
- 'hint'=>"You can usually fix this by giving the webserver write access to the ownCloud directory '"
- .OC::$SERVERROOT."' (in a terminal, use the command "
- ."'chown -R www-data:www-data /path/to/your/owncloud/install/data' ");
+ $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>.'
+ );
}
} else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
$errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud',
@@ -220,68 +234,76 @@ class OC_Util {
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= false;
+ $web_server_restart=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 = false;
+ $web_server_restart =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 = false;
+ $web_server_restart =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= false;
+ $web_server_restart=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= false;
+ $web_server_restart=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= false;
+ $web_server_restart=true;
}
- if(!function_exists('imagepng')) {
+ 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= false;
+ $web_server_restart=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= false;
+ $web_server_restart=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= false;
+ $web_server_restart=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= false;
+ $web_server_restart=true;
}
if(floatval(phpversion())<5.3) {
$errors[]=array('error'=>'PHP 5.3 is required.',
'hint'=>'Please ask your server administrator to update PHP to version 5.3 or higher.'
.' PHP 5.2 is no longer supported by ownCloud and the PHP community.');
- $web_server_restart= false;
+ $web_server_restart=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= false;
+ $web_server_restart=true;
}
- if(ini_get('safe_mode')) {
+ 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= false;
+ $web_server_restart=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;
}
if($web_server_restart) {
@@ -408,18 +430,19 @@ class OC_Util {
exit();
}
- /**
- * get an id unqiue for this instance
- * @return string
- */
- public static function getInstanceId() {
- $id=OC_Config::getValue('instanceid', null);
- if(is_null($id)) {
- $id=uniqid();
- OC_Config::setValue('instanceid', $id);
- }
- return $id;
- }
+ /**
+ * 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 Static lifespan (in seconds) when a request token expires.
@@ -446,13 +469,13 @@ class OC_Util {
*/
public static function callRegister() {
// Check if a token exists
- if(!isset($_SESSION['requesttoken'])) {
+ if(!\OC::$session->exists('requesttoken')) {
// No valid token found, generate a new one.
$requestToken = self::generate_random_bytes(20);
- $_SESSION['requesttoken']=$requestToken;
+ \OC::$session->set('requesttoken', $requestToken);
} else {
// Valid token already exists, send it
- $requestToken = $_SESSION['requesttoken'];
+ $requestToken = \OC::$session->get('requesttoken');
}
return($requestToken);
}
@@ -464,7 +487,7 @@ class OC_Util {
* @see OC_Util::callRegister()
*/
public static function isCallRegistered() {
- if(!isset($_SESSION['requesttoken'])) {
+ if(!\OC::$session->exists('requesttoken')) {
return false;
}
@@ -480,7 +503,7 @@ class OC_Util {
}
// Check if the token is valid
- if($token !== $_SESSION['requesttoken']) {
+ if($token !== \OC::$session->get('requesttoken')) {
// Not valid
return false;
} else {
@@ -516,7 +539,22 @@ class OC_Util {
}
return $value;
}
-
+
+ /**
+ * @brief Public function to encode url parameters
+ *
+ * This function is used to encode path to file before output.
+ * Encoding is done according to RFC 3986 with one exception:
+ * Character '/' is preserved as is.
+ *
+ * @param string $component part of URI to encode
+ * @return string
+ */
+ public static function encodePath($component) {
+ $encoded = rawurlencode($component);
+ $encoded = str_replace('%2F', '/', $encoded);
+ return $encoded;
+ }
/**
* Check if the htaccess file is working by creating a test file in the data directory and trying to access via http
@@ -591,7 +629,7 @@ class OC_Util {
} catch(\Sabre_DAV_Exception_NotAuthenticated $e) {
$return = true;
} catch(\Exception $e) {
- OC_Log::write('core', 'isWebDAVWorking: NO - Reason: '.$e, OC_Log::WARN);
+ OC_Log::write('core', 'isWebDAVWorking: NO - Reason: '.$e->getMessage(). ' ('.get_class($e).')', OC_Log::WARN);
$return = false;
}
@@ -614,8 +652,8 @@ class OC_Util {
$result = setlocale(LC_ALL, 'en_US.UTF-8', 'en_US.UTF8');
if($result == false) {
return false;
- }
- return true;
+ }
+ return true;
}
/**
@@ -629,7 +667,11 @@ class OC_Util {
/**
* Check if the ownCloud server can connect to the internet
*/
- public static function isinternetconnectionworking() {
+ public static function isInternetConnectionWorking() {
+ // in case there is no internet connection on purpose return false
+ if (self::isInternetConnectionEnabled() === false) {
+ return false;
+ }
// try to connect to owncloud.org to see if http connections to the internet are possible.
$connected = @fsockopen("www.owncloud.org", 80);
@@ -650,6 +692,13 @@ class OC_Util {
}
}
+
+ /**
+ * Check if the connection to the internet is disabled on purpose
+ */
+ public static function isInternetConnectionEnabled(){
+ return \OC_Config::getValue("has_internet_connection", true);
+ }
/**
* clear all levels of output buffering
@@ -786,4 +835,61 @@ 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
+ * @return string the theme
+ */
+ public static function getTheme() {
+ $theme = OC_Config::getValue("theme", '');
+
+ if($theme === '') {
+
+ if(is_dir(OC::$SERVERROOT . '/themes/default')) {
+ $theme = 'default';
+ }
+
+ }
+
+ return $theme;
+ }
+
+ /**
+ * 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
+ */
+ public static function clearOpcodeCache() {
+ // APC
+ if (function_exists('apc_clear_cache')) {
+ apc_clear_cache();
+ }
+ // Zend Opcache
+ if (function_exists('accelerator_reset')) {
+ accelerator_reset();
+ }
+ // XCache
+ if (function_exists('xcache_clear_cache')) {
+ xcache_clear_cache(XC_TYPE_VAR, 0);
+ }
+ }
+
+ /**
+ * Normalize a unicode string
+ * @param string $value a not normalized string
+ * @return bool|string
+ */
+ public static function normalizeUnicode($value) {
+ if(class_exists('Patchwork\PHP\Shim\Normalizer')) {
+ $normalizedValue = \Patchwork\PHP\Shim\Normalizer::normalize($value);
+ if($normalizedValue === false) {
+ \OC_Log::write( 'core', 'normalizing failed for "' . $value . '"', \OC_Log::WARN);
+ } else {
+ $value = $normalizedValue;
+ }
+ }
+
+ return $value;
+ }
}
diff --git a/lib/vcategories.php b/lib/vcategories.php
index 2f990c5d2d2..84036958359 100644
--- a/lib/vcategories.php
+++ b/lib/vcategories.php
@@ -125,7 +125,7 @@ class OC_VCategories {
OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
return false;
}
- return ($result->numRows() == 0);
+ return ($result->numRows() === 0);
} catch(Exception $e) {
OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
OCP\Util::ERROR);
@@ -325,6 +325,37 @@ class OC_VCategories {
}
/**
+ * @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.
@@ -523,7 +554,7 @@ class OC_VCategories {
}
try {
$stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` '
- . 'WHERE `uid` = ? AND');
+ . '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);
@@ -536,23 +567,31 @@ class OC_VCategories {
/**
* @brief Delete category/object relations from the db
- * @param int $id The id of the object
+ * @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 purgeObject($id, $type = null) {
+ 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 {
- $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
- . 'WHERE `objid` = ? AND `type`= ?');
- $result = $stmt->execute(array($id, $type));
+ $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::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(),
OCP\Util::ERROR);
return false;
}
diff --git a/lib/vobject/compoundproperty.php b/lib/vobject/compoundproperty.php
new file mode 100644
index 00000000000..d702ab802e0
--- /dev/null
+++ b/lib/vobject/compoundproperty.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * ownCloud - VObject Compound Property
+ *
+ * @author Thomas Tanghus
+ * @author Evert Pot (http://www.rooftopsolutions.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/>.
+ *
+ */
+
+namespace OC\VObject;
+
+/**
+ * This class overrides \Sabre\VObject\Property::serialize() to not
+ * double escape commas and semi-colons in compound properties.
+*/
+class CompoundProperty extends \Sabre\VObject\Property\Compound {
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ public function serialize() {
+
+ $str = $this->name;
+ if ($this->group) {
+ $str = $this->group . '.' . $this->name;
+ }
+
+ foreach($this->parameters as $param) {
+ $str.=';' . $param->serialize();
+ }
+ $src = array(
+ "\n",
+ );
+ $out = array(
+ '\n',
+ );
+ $str.=':' . str_replace($src, $out, $this->value);
+
+ $out = '';
+ while(strlen($str) > 0) {
+ if (strlen($str) > 75) {
+ $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
+ $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
+ } else {
+ $out .= $str . "\r\n";
+ $str = '';
+ break;
+ }
+ }
+
+ return $out;
+
+ }
+
+} \ No newline at end of file
diff --git a/lib/vobject/stringproperty.php b/lib/vobject/stringproperty.php
new file mode 100644
index 00000000000..b98a8f26c2b
--- /dev/null
+++ b/lib/vobject/stringproperty.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * ownCloud - VObject String Property
+ *
+ * This class adds escaping of simple string properties.
+ *
+ * @author Thomas Tanghus
+ * @author Evert Pot (http://www.rooftopsolutions.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/>.
+ *
+ */
+
+namespace OC\VObject;
+
+/**
+ * This class overrides \Sabre\VObject\Property::serialize() properly
+ * escape commas and semi-colons in string properties.
+*/
+class StringProperty extends \Sabre\VObject\Property {
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ public function serialize() {
+
+ $str = $this->name;
+ if ($this->group) {
+ $str = $this->group . '.' . $this->name;
+ }
+
+ foreach($this->parameters as $param) {
+ $str.=';' . $param->serialize();
+ }
+
+ $src = array(
+ '\\',
+ "\n",
+ ';',
+ ',',
+ );
+ $out = array(
+ '\\\\',
+ '\n',
+ '\;',
+ '\,',
+ );
+ $value = strtr($this->value, array('\,' => ',', '\;' => ';', '\\\\' => '\\'));
+ $str.=':' . str_replace($src, $out, $value);
+
+ $out = '';
+ while(strlen($str) > 0) {
+ if (strlen($str) > 75) {
+ $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
+ $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
+ } else {
+ $out .= $str . "\r\n";
+ $str = '';
+ break;
+ }
+ }
+
+ return $out;
+
+ }
+
+} \ No newline at end of file