diff options
author | Thomas Müller <thomas.mueller@tmit.eu> | 2013-07-12 09:43:04 +0200 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2013-07-12 09:43:04 +0200 |
commit | 24b4806af4a9b485b4b9a772809d118e91c6d97f (patch) | |
tree | df5664782eefd384bd6ed3dc363a25575da89202 /lib | |
parent | 8793acfb4e751cfdb464d259de45249cec5d6398 (diff) | |
parent | 3abe68176ff09ca579ff9e5f15872fb5cab8ff4d (diff) | |
download | nextcloud-server-24b4806af4a9b485b4b9a772809d118e91c6d97f.tar.gz nextcloud-server-24b4806af4a9b485b4b9a772809d118e91c6d97f.zip |
Merge branch 'master' into googledrive
Diffstat (limited to 'lib')
138 files changed, 4777 insertions, 2412 deletions
diff --git a/lib/api.php b/lib/api.php index fc76836995b..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(); } diff --git a/lib/app.php b/lib/app.php index c6f6e92e60e..f9b1c5ca7b5 100644 --- a/lib/app.php +++ b/lib/app.php @@ -174,7 +174,8 @@ class OC_App{ $apps=array('files'); $sql = 'SELECT `appid` FROM `*PREFIX*appconfig`' .' WHERE `configkey` = \'enabled\' AND `configvalue`=\'yes\''; - if (OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') { //FIXME oracle hack + 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\''; } @@ -258,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 @@ -348,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", diff --git a/lib/autoloader.php b/lib/autoloader.php index 9615838a9a2..21170639092 100644 --- a/lib/autoloader.php +++ b/lib/autoloader.php @@ -96,8 +96,8 @@ class Autoloader { } else { foreach ($this->prefixPaths as $prefix => $dir) { if (0 === strpos($class, $prefix)) { - $path = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; - $path = str_replace('_', DIRECTORY_SEPARATOR, $path); + $path = str_replace('\\', '/', $class) . '.php'; + $path = str_replace('_', '/', $path); $paths[] = $dir . '/' . $path; } } 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 9d1d4b5e058..d1279a46337 100644 --- a/lib/base.php +++ b/lib/base.php @@ -173,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(); @@ -235,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::WARN); + OC_Config::setValue('theme', ''); $minimizerCSS = new OC_Minimizer_CSS(); $minimizerCSS->clearCache(); $minimizerJS = new OC_Minimizer_JS(); @@ -265,6 +263,7 @@ class OC { 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"); @@ -278,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"); } @@ -289,14 +289,14 @@ class OC { $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){ - //set the session object to a dummy session so code relying on the session existing still works - self::$session = new \OC\Session\Memory(''); - OC_Log::write('core', 'Session could not be initialized', OC_Log::ERROR); @@ -312,16 +312,17 @@ class OC { exit(); } + $sessionLifeTime = self::getSessionLifeTime(); // regenerate session id periodically to avoid session fixation if (!self::$session->exists('SID_CREATED')) { self::$session->set('SID_CREATED', time()); - } else if (time() - self::$session->get('SID_CREATED') > 60*60*12) { + } else if (time() - self::$session->get('SID_CREATED') > $sessionLifeTime / 2) { session_regenerate_id(true); self::$session->set('SID_CREATED', time()); } // session timeout - if (self::$session->exists('LAST_ACTIVITY') && (time() - self::$session->get('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, $cookie_path); } @@ -333,6 +334,13 @@ class OC { 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() { if (!isset(OC::$router)) { OC::$router = new OC_Router(); @@ -394,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,14 +446,14 @@ class OC { stream_wrapper_register('oc', 'OC\Files\Stream\OC'); self::initTemplateEngine(); - self::checkConfig(); - self::checkInstalled(); - self::checkSSL(); if ( !self::$CLI ) { self::initSession(); } else { self::$session = new \OC\Session\Memory(''); } + self::checkConfig(); + self::checkInstalled(); + self::checkSSL(); $errors = OC_Util::checkServer(); if (count($errors) > 0) { @@ -456,6 +461,10 @@ 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)) { self::$session->set('user_id',''); @@ -537,9 +546,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'); + } } /** 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 9b87d4ce4e5..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; + + 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); + } - // Is the cache filled? - private static $init = false; + 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,113 +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; + 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); } - - // read all file in config dir ending by config.php - $config_files = glob( OC::$SERVERROOT."/config/*.config.php"); - - //Filter only regular files - $config_files = array_filter($config_files, 'is_file'); - - //Sort array naturally : - natsort($config_files); - - // Add default config - array_unshift($config_files,OC::$SERVERROOT."/config/config.php"); - - //Include file and merge config - foreach($config_files as $file){ + // Include file and merge config + foreach ($configFiles as $file) { + if (!file_exists($file)) { + continue; + } + unset($CONFIG); include $file; - if( isset( $CONFIG ) && is_array( $CONFIG )) { - self::$cache = array_merge(self::$cache, $CONFIG); + 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 617be508b16..06ab73e3e4d 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 1ffa048d6b2..0bffa58af78 100644 --- a/lib/connector/sabre/node.php +++ b/lib/connector/sabre/node.php @@ -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 61836551833..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); @@ -298,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); @@ -325,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) { @@ -366,12 +347,23 @@ class OC_DB { 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{ @@ -380,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" ); @@ -390,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() * @@ -404,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; } /** @@ -512,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']; @@ -528,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; } @@ -547,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'; @@ -576,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; } @@ -617,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(); @@ -641,15 +705,9 @@ class OC_DB { } $query = substr($query, 0, strlen($query) - 5); try { - $stmt = self::prepare($query); - $result = $stmt->execute($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 ); + $result = self::executeAudited($query, $inserts); + } catch(DatabaseException $e) { + OC_Template::printExceptionErrorPage( $e ); } if((int)$result->numRows() === 0) { @@ -657,7 +715,7 @@ class OC_DB { . 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 . '` (`' @@ -674,16 +732,12 @@ class OC_DB { } 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($inserts); + return $result; } /** @@ -718,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 ); @@ -734,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 @@ -883,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 @@ -899,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 ''; } /** @@ -938,15 +1023,17 @@ 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)) { @@ -964,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) { @@ -1065,7 +1155,7 @@ class PDOStatementWrapper{ die ($entry); } } - + /** * provide numRows */ 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 abb1617c25e..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; } @@ -170,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 index 8933101577d..923804f48d0 100644 --- a/lib/files/cache/backgroundwatcher.php +++ b/lib/files/cache/backgroundwatcher.php @@ -18,8 +18,8 @@ class BackgroundWatcher { if (!is_null(self::$folderMimetype)) { return self::$folderMimetype; } - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'); - $result = $query->execute(array('httpd/unix-directory')); + $sql = 'SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'; + $result = \OC_DB::executeAudited($sql, array('httpd/unix-directory')); $row = $result->fetchRow(); return $row['id']; } @@ -59,11 +59,11 @@ class BackgroundWatcher { */ static private function getNextFileId($previous, $folder) { if ($folder) { - $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND mimetype = ' . self::getFolderMimetype() . ' ORDER BY `fileid` ASC', 1); + $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` = ? ORDER BY `fileid` ASC', 1); } else { - $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND mimetype != ' . self::getFolderMimetype() . ' ORDER BY `fileid` ASC', 1); + $stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` != ? ORDER BY `fileid` ASC', 1); } - $result = $query->execute(array($previous)); + $result = \OC_DB::executeAudited($stmt, array($previous,self::getFolderMimetype())); if ($row = $result->fetchRow()) { return $row['fileid']; } else { diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php index 0210d5a73f1..3818fdbd840 100644 --- a/lib/files/cache/cache.php +++ b/lib/files/cache/cache.php @@ -65,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; @@ -81,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 { @@ -96,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->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`, `storage_mtime`, `encrypted`, `unencrypted_size`, `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])) { @@ -144,14 +151,10 @@ 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`, `storage_mtime`, `encrypted`, `unencrypted_size`, `etag` - FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC'); - - $result = $query->execute(array($fileId)); - if (\OC_DB::isError($result)) { - \OCP\Util::writeLog('cache', 'getFolderContents failed: ' . $result->getMessage(), \OCP\Util::ERROR); - } + $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']); @@ -179,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]); @@ -202,12 +208,9 @@ class Cache { $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->getMessage(), \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'); } @@ -220,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); } /** @@ -267,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->getNumericStorageId(), $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 { @@ -320,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']); @@ -334,38 +350,41 @@ class Cache { * @param string $target */ public function move($source, $target) { + // normalize source and target + $source = $this->normalize($source); + $target = $this->normalize($target); + $sourceData = $this->get($source); $sourceId = $sourceData['fileid']; $newParentId = $this->getParentId($target); if ($sourceData['mimetype'] === 'httpd/unix-directory') { //find all child entries - $query = \OC_DB::prepare('SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?'); - $result = $query->execute(array($this->getNumericStorageId(), $source . '/%')); + $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); - $query->execute(array($targetPath, md5($targetPath), $child['fileid'])); + \OC_DB::executeAudited($query, array($targetPath, md5($targetPath), $child['fileid'])); } } - $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `name` = ?, `parent` =?' - . ' WHERE `fileid` = ?'); - $query->execute(array($target, md5($target), basename($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->getNumericStorageId())); + $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)); } /** @@ -374,12 +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->getNumericStorageId(), $pathHash)); - if( \OC_DB::isError($result)) { - \OCP\Util::writeLog('cache', 'get status failed: ' . $result->getMessage(), \OCP\Util::ERROR); - } + $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; @@ -402,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`, `unencrypted_size`, `etag` - FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?' - ); - $result = $query->execute(array($pattern, $this->getNumericStorageId())); + + // 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']); @@ -428,12 +449,10 @@ class Cache { } else { $where = '`mimepart` = ?'; } - $query = \OC_DB::prepare(' - SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `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->getNumericStorageId())); + $result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId())); $files = array(); while ($row = $result->fetchRow()) { $row['mimetype'] = $this->getMimetype($row['mimetype']); @@ -470,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->getNumericStorageId())); + $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()) { @@ -497,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->getNumericStorageId())); + $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']; @@ -518,10 +537,7 @@ class Cache { public function getIncomplete() { $query = \OC_DB::prepare('SELECT `path` FROM `*PREFIX*filecache`' . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC',1); - $result = $query->execute(array($this->getNumericStorageId())); - if (\OC_DB::isError($result)) { - \OCP\Util::writeLog('cache', 'getIncomplete failed: ' . $result->getMessage(), \OCP\Util::ERROR); - } + $result = \OC_DB::executeAudited($query, array($this->getNumericStorageId())); if ($row = $result->fetchRow()) { return $row['path']; } else { @@ -536,8 +552,8 @@ class Cache { * @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']; @@ -551,4 +567,14 @@ class Cache { 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 b8e2548639b..8eed1f67a5d 100644 --- a/lib/files/cache/legacy.php +++ b/lib/files/cache/legacy.php @@ -26,8 +26,8 @@ class Legacy { * @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 { @@ -45,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; @@ -74,11 +74,11 @@ class Legacy { */ 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)); + $result = \OC_DB::executeAudited($sql, array($path)); $data = $result->fetchRow(); $data['etag'] = $this->getEtag($data['path'], $data['user']); return $data; @@ -111,7 +111,7 @@ class Legacy { if(is_null($query)){ $query = \OC_DB::prepare('SELECT `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = \'{DAV:}getetag\''); } - $result = $query->execute(array($user, '/' . $relativePath)); + $result = \OC_DB::executeAudited($query,array($user, '/' . $relativePath)); if ($row = $result->fetchRow()) { return trim($row['propertyvalue'], '"'); } else { @@ -126,8 +126,7 @@ class Legacy { * @return array */ function getChildren($id) { - $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?'); - $result = $query->execute(array($id)); + $result = \OC_DB::executeAudited('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?', array($id)); $data = $result->fetchAll(); foreach ($data as $i => $item) { $data[$i]['etag'] = $this->getEtag($item['path'], $item['user']); diff --git a/lib/files/cache/permissions.php b/lib/files/cache/permissions.php index 29c30b0f36c..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,9 @@ 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']; @@ -93,11 +91,12 @@ class Permissions { * @return int[] */ public function getDirectoryPermissions($parentId, $user) { - $query = \OC_DB::prepare('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` = ?'); + $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 = $query->execute(array($parentId, $user)); + $result = \OC_DB::executeAudited($sql, array($parentId, $user)); $filePermissions = array(); while ($row = $result->fetchRow()) { $filePermissions[$row['fileid']] = $row['permissions']; @@ -113,18 +112,17 @@ 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)); } } @@ -134,8 +132,8 @@ class Permissions { * @param int $fileId */ public function getUsers($fileId) { - $query = \OC_DB::prepare('SELECT `user` FROM `*PREFIX*permissions` WHERE `fileid` = ?'); - $result = $query->execute(array($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']; diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index 8f9a7921956..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(); @@ -59,12 +64,12 @@ 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) { - if ( ! self::isPartialFile($file) - and ! \OC\Files\Filesystem::isFileBlacklisted($file) + 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); @@ -79,20 +84,22 @@ class Scanner { } } $newData = $data; - if ($cacheData = $this->cache->get($file)) { - if ($checkExisting && $data['size'] === -1) { - $data['size'] = $cacheData['size']; - } - if ($data['mtime'] === $cacheData['mtime'] && - $data['size'] === $cacheData['size']) { - $data['etag'] = $cacheData['etag']; + 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 (!empty($newData)) { - $this->cache->put($file, $newData); - } + } + if (!empty($newData)) { + $this->cache->put($file, $newData); } return $data; } @@ -100,55 +107,79 @@ class Scanner { } /** - * 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 bool $recursive - * @param bool $onlyChilds + * @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)) { $child = ($path) ? $path . '/' . $file : $file; - if (!\OC\Files\Filesystem::isIgnoredDir($file)) { - $data = $this->scanFile($child, $recursive === self::SCAN_SHALLOW); + 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; } diff --git a/lib/files/cache/storage.php b/lib/files/cache/storage.php index 72de376798c..8a9e47ca36d 100644 --- a/lib/files/cache/storage.php +++ b/lib/files/cache/storage.php @@ -32,13 +32,13 @@ class Storage { $this->storageId = md5($this->storageId); } - $query = \OC_DB::prepare('SELECT `numeric_id` FROM `*PREFIX*storages` WHERE `id` = ?'); - $result = $query->execute(array($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 { - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*storages`(`id`) VALUES(?)'); - $query->execute(array($this->storageId)); + $sql = 'INSERT INTO `*PREFIX*storages` (`id`) VALUES(?)'; + \OC_DB::executeAudited($sql, array($this->storageId)); $this->numericId = \OC_DB::insertid('*PREFIX*storages'); } } @@ -48,8 +48,9 @@ class Storage { } public static function getStorageId($numericId) { - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?'); - $result = $query->execute(array($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 { diff --git a/lib/files/cache/updater.php b/lib/files/cache/updater.php index 417a47f3830..87c33a313a4 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 @@ -102,7 +103,7 @@ class Updater { static public function correctFolder($path, $time) { if ($path !== '' && $path !== '/') { $parent = dirname($path); - if ($parent === '.') { + if ($parent === '.' || $parent === '\\') { $parent = ''; } /** @@ -116,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); } } } diff --git a/lib/files/cache/upgrade.php b/lib/files/cache/upgrade.php index ca044ba81de..cfb9a117311 100644 --- a/lib/files/cache/upgrade.php +++ b/lib/files/cache/upgrade.php @@ -78,7 +78,7 @@ class Upgrade { VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); } if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) { - $insertQuery->execute(array($data['id'], $data['storage'], + \OC_DB::executeAudited($insertQuery, array($data['id'], $data['storage'], $data['path'], $data['path_hash'], $data['parent'], $data['name'], $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'], $data['etag'])); } @@ -97,7 +97,7 @@ class Upgrade { if(is_null($query)) { $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?'); } - $result = $query->execute(array($storage, $pathHash, $id)); + $result = \OC_DB::executeAudited($query, array($storage, $pathHash, $id)); return (bool)$result->fetchRow(); } diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php index b10625e20de..3d7d5abf8fe 100644 --- a/lib/files/filesystem.php +++ b/lib/files/filesystem.php @@ -30,6 +30,7 @@ namespace OC\Files; +use OC\Files\Storage\Loader; const FREE_SPACE_UNKNOWN = -2; const FREE_SPACE_UNLIMITED = -3; @@ -143,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 @@ -152,6 +165,9 @@ class Filesystem { * @return string */ static public function getMountPoint($path) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } $mount = self::$mounts->find($path); if ($mount) { return $mount->getMountPoint(); @@ -167,6 +183,9 @@ class Filesystem { * @return string[] */ static public function getMountPoints($path) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } $result = array(); $mounts = self::$mounts->findIn($path); foreach ($mounts as $mount) { @@ -182,6 +201,9 @@ class Filesystem { * @return \OC\Files\Storage\Storage */ public static function getStorage($mountPoint) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } $mount = self::$mounts->find($mountPoint); return $mount->getStorage(); } @@ -191,6 +213,9 @@ class Filesystem { * @return Mount\Mount[] */ public static function getMountByStorageId($id) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } return self::$mounts->findByStorageId($id); } @@ -199,6 +224,9 @@ class Filesystem { * @return Mount\Mount[] */ public static function getMountByNumericId($id) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } return self::$mounts->findByNumericId($id); } @@ -209,6 +237,9 @@ class Filesystem { * @return array consisting of the storage and the internal path */ static public function resolvePath($path) { + if (!self::$mounts) { + \OC_Util::setupFS(); + } $mount = self::$mounts->find($path); if ($mount) { return array($mount->getStorage(), $mount->getInternalPath($path)); @@ -221,9 +252,10 @@ class Filesystem { if (self::$defaultInstance) { return false; } + self::getLoader(); self::$defaultInstance = new View($root); - if(!self::$mounts) { + if (!self::$mounts) { self::$mounts = new Mount\Manager(); } @@ -235,8 +267,8 @@ class Filesystem { return true; } - static public function initMounts(){ - if(!self::$mounts) { + static public function initMounts() { + if (!self::$mounts) { self::$mounts = new Mount\Manager(); } } @@ -359,7 +391,9 @@ class Filesystem { * clear all mounts and storage backends */ public static function clearMounts() { - self::$mounts->clear(); + if (self::$mounts) { + self::$mounts->clear(); + } } /** @@ -370,7 +404,10 @@ class Filesystem { * @param string $mountpoint */ static public function mount($class, $arguments, $mountpoint) { - $mount = new Mount\Mount($class, $mountpoint, $arguments); + if (!self::$mounts) { + \OC_Util::setupFS(); + } + $mount = new Mount\Mount($class, $mountpoint, $arguments, self::getLoader()); self::$mounts->addMount($mount); } @@ -631,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; } diff --git a/lib/files/mapper.php b/lib/files/mapper.php index 15f5f0628b5..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,8 +162,9 @@ 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))); } public function slugifyPath($path, $index=null) { @@ -172,14 +172,9 @@ class Mapper $pathElements = explode('/', $path); $sluggedElements = array(); - - // rip off the extension ext from last element + $last= end($pathElements); - $parts = pathinfo($last); - $filename = $parts['filename']; - array_pop($pathElements); - array_push($pathElements, $filename); - + foreach ($pathElements as $pathElement) { // remove empty elements if (empty($pathElement)) { @@ -192,13 +187,15 @@ class Mapper // apply index to file name if ($index !== null) { $last= array_pop($sluggedElements); - array_push($sluggedElements, $last.'-'.$index); - } + + // 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); + } - // add back the extension - if (isset($parts['extension'])) { - $last= array_pop($sluggedElements); - array_push($sluggedElements, $last.'.'.$parts['extension']); } $sluggedPath = $this->unchangedPhysicalRoot.implode('/', $sluggedElements); @@ -213,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, '-'); @@ -228,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/mount.php b/lib/files/mount/mount.php index 69b8285ab4c..17b0055ee84 100644 --- a/lib/files/mount/mount.php +++ b/lib/files/mount/mount.php @@ -9,10 +9,10 @@ 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 */ @@ -23,19 +23,30 @@ class Mount { private $mountPoint; /** - * @param string|\OC\Files\Storage\Storage $storage + * @var \OC\Files\Storage\Loader $loader + */ + private $loader; + + /** + * @param string | \OC\Files\Storage\Storage $storage * @param string $mountpoint - * @param array $arguments (optional) + * @param array $arguments (optional)\ + * @param \OC\Files\Storage\Loader $loader */ - public function __construct($storage, $mountpoint, $arguments = null) { + 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 \OC\Files\Storage\Storage) { + if ($storage instanceof Storage) { $this->class = get_class($storage); - $this->storage = $storage; + $this->storage = $this->loader->wrap($mountpoint, $storage); } else { // Update old classes to new namespace if (strpos($storage, 'OC_Filestorage_') !== false) { @@ -62,7 +73,7 @@ class Mount { private function createStorage() { if (class_exists($this->class)) { try { - return new $this->class($this->arguments); + return $this->loader->load($this->mountPoint, $this->class, $this->arguments); } catch (\Exception $exception) { \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR); return null; 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 d684905bf9a..b08fd73ce19 100644 --- a/lib/files/storage/local.php +++ b/lib/files/storage/local.php @@ -39,7 +39,27 @@ if (\OC_Util::runningOnWindows()) { } public function rmdir($path) { - return @rmdir($this->datadir . $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) { 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/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 ecb0f30400a..c9727fe4984 100644 --- a/lib/files/view.php +++ b/lib/files/view.php @@ -300,7 +300,7 @@ class View { list ($count, $result) = \OC_Helper::streamCopy($data, $target); fclose($target); fclose($data); - if ($this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path)) { + if ($this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path) && $result !== false) { if (!$exists) { \OC_Hook::emit( Filesystem::CLASSNAME, @@ -353,7 +353,16 @@ class View { return false; } $run = true; - if ($this->fakeRoot == Filesystem::getRoot() && !Cache\Scanner::isPartialFile($path1)) { + 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( @@ -386,11 +395,28 @@ class View { $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); + + // 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() && !Cache\Scanner::isPartialFile($path1)) { + 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, @@ -484,7 +510,7 @@ class View { 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, @@ -648,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); } @@ -662,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( @@ -746,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; } } } diff --git a/lib/helper.php b/lib/helper.php index 225e9fd2a9a..1860a55fc8f 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -364,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 @@ -377,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)) { @@ -609,7 +619,7 @@ class OC_Helper { } /** - * remove all files in PHP /oc-noclean temp dir + * remove all files in PHP /oc-noclean temp dir */ public static function cleanTmpNoClean() { $tmpDirNoCleanFile=get_temp_dir().'/oc-noclean/'; @@ -777,9 +787,9 @@ class OC_Helper { $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); $freeSpace = \OC\Files\Filesystem::free_space($dir); - if ($upload_max_filesize == 0 and $post_max_size == 0) { + if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { $maxUploadFilesize = \OC\Files\FREE_SPACE_UNLIMITED; - } elseif ($upload_max_filesize === 0 or $post_max_size === 0) { + } 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); 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 index e615a58cfe8..9ffe1af2314 100644 --- a/lib/hooks/basicemitter.php +++ b/lib/hooks/basicemitter.php @@ -13,7 +13,7 @@ abstract class BasicEmitter implements Emitter { /** * @var (callable[])[] $listeners */ - private $listeners = array(); + protected $listeners = array(); /** * @param string $scope 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/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 22c934e238d..107b27a1fc8 100644 --- a/lib/l10n/ar.php +++ b/lib/l10n/ar.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,13 +17,10 @@ "Files" => "الملفات", "Text" => "معلومات إضافية", "Images" => "صور", -"Set an admin username." => "اعداد اسم مستخدم للمدير", -"Set an admin password." => "اعداد كلمة مرور للمدير", "%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." => "انت بحاجة لكتابة اسم مستخدم موجود أو حساب المدير.", "MySQL username and/or password not valid" => "اسم المستخدم و/أو كلمة المرور لنظام MySQL غير صحيح", "DB Error: \"%s\"" => "خطأ في قواعد البيانات : \"%s\"", @@ -33,7 +31,9 @@ "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." => "اعدادات خادمك غير صحيحة بشكل تسمح لك بمزامنة ملفاتك وذلك بسبب أن واجهة WebDAV تبدو معطلة", "Please double check the <a href='%s'>installation guides</a>." => "الرجاء التحقق من <a href='%s'>دليل التنصيب</a>.", "seconds ago" => "منذ ثواني", diff --git a/lib/l10n/bg_BG.php b/lib/l10n/bg_BG.php index 2de4c0a6e68..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,21 +17,25 @@ "Files" => "Файлове", "Text" => "Текст", "Images" => "Снимки", -"Set an admin username." => "Въведете потребителско име за администратор.", -"Set an admin password." => "Въведете парола за администратор.", "%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." => "Необходимо е да влезете в всъществуващ акаунт или като администратора", "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 потребителско име и/или парола", -"MS SQL username and/or password not valid: %s" => "Невалидно MS SQL потребителско име и/или парола: %s", +"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 минута", diff --git a/lib/l10n/bn_BD.php b/lib/l10n/bn_BD.php index f7c8f57466d..ab1d9b94d0d 100644 --- a/lib/l10n/bn_BD.php +++ b/lib/l10n/bn_BD.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" => "ফাইলে ফিরে চল", diff --git a/lib/l10n/ca.php b/lib/l10n/ca.php index 5c368a85b28..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,15 +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.", "%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 connection could not be established" => "No s'ha pogut establir la connexió Oracle", "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\"", @@ -32,9 +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", diff --git a/lib/l10n/cs_CZ.php b/lib/l10n/cs_CZ.php index 36469507d40..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,13 +17,10 @@ "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.", "%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.", "MySQL username and/or password not valid" => "Uživatelské jméno, či heslo MySQL není platné", "DB Error: \"%s\"" => "Chyba DB: \"%s\"", @@ -31,9 +29,12 @@ "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 pár vteřinami", diff --git a/lib/l10n/cy_GB.php b/lib/l10n/cy_GB.php index b3503dcc572..27140ba6dbb 100644 --- a/lib/l10n/cy_GB.php +++ b/lib/l10n/cy_GB.php @@ -5,6 +5,7 @@ "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", @@ -16,13 +17,10 @@ "Files" => "Ffeiliau", "Text" => "Testun", "Images" => "Delweddau", -"Set an admin username." => "Creu enw defnyddiwr i'r gweinyddwr.", -"Set an admin password." => "Gosod cyfrinair y gweinyddwr.", "%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", -"%s set the database host." => "%s gosod gwesteiwr y gronfa ddata.", -"PostgreSQL username and/or password not valid" => "Enw a/neu gyfrinair PostgreSQL annilys", +"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\"", @@ -33,7 +31,9 @@ "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", -"MS SQL username and/or password not valid: %s" => "Enw a/neu gyfrinair MS SQL annilys: %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", diff --git a/lib/l10n/da.php b/lib/l10n/da.php index aead17f510e..5f11453bcdd 100644 --- a/lib/l10n/da.php +++ b/lib/l10n/da.php @@ -5,6 +5,7 @@ "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,13 +17,10 @@ "Files" => "Filer", "Text" => "SMS", "Images" => "Billeder", -"Set an admin username." => "Angiv et admin brugernavn.", -"Set an admin password." => "Angiv et admin kodeord.", "%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.", "MySQL username and/or password not valid" => "MySQL brugernavn og/eller kodeord er ikke gyldigt.", "DB Error: \"%s\"" => "Databasefejl: \"%s\"", @@ -31,9 +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", diff --git a/lib/l10n/de.php b/lib/l10n/de.php index 74715bc66eb..4ef02402b9b 100644 --- a/lib/l10n/de.php +++ b/lib/l10n/de.php @@ -5,6 +5,7 @@ "Users" => "Benutzer", "Apps" => "Apps", "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\"", @@ -16,13 +17,10 @@ "Files" => "Dateien", "Text" => "Text", "Images" => "Bilder", -"Set an admin username." => "Setze Administrator Benutzername.", -"Set an admin password." => "Setze Administrator Passwort", "%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.", "MySQL username and/or password not valid" => "MySQL Benutzername und/oder Passwort ungültig", "DB Error: \"%s\"" => "DB Fehler: \"%s\"", @@ -31,9 +29,12 @@ "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'>Installationsanleitungen</a>.", "seconds ago" => "Gerade eben", diff --git a/lib/l10n/de_DE.php b/lib/l10n/de_DE.php index 5ebe4fb26fc..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,15 +17,11 @@ "Files" => "Dateien", "Text" => "Text", "Images" => "Bilder", -"Set an admin username." => "Setze Administrator Benutzername.", -"Set an admin password." => "Setze Administrator Passwort", "%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 connection could not be established" => "Die Oracle-Verbindung konnte nicht aufgebaut werden.", "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\"", @@ -32,9 +29,12 @@ "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", +"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", diff --git a/lib/l10n/el.php b/lib/l10n/el.php index 8637b8da269..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,13 +17,10 @@ "Files" => "Αρχεία", "Text" => "Κείμενο", "Images" => "Εικόνες", -"Set an admin username." => "Εισάγετε όνομα χρήστη διαχειριστή.", -"Set an admin password." => "Εισάγετε συνθηματικό διαχειριστή.", "%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." => "Χρειάζεται να εισάγετε είτε έναν υπάρχον λογαριασμό ή του διαχειριστή.", "MySQL username and/or password not valid" => "Μη έγκυρος χρήστης και/ή συνθηματικό της MySQL", "DB Error: \"%s\"" => "Σφάλμα Βάσης Δεδομένων: \"%s\"", @@ -31,9 +29,12 @@ "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", -"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 πιθανόν να είναι κατεστραμμένη.", "Please double check the <a href='%s'>installation guides</a>." => "Ελέγξτε ξανά τις <a href='%s'>οδηγίες εγκατάστασης</a>.", "seconds ago" => "δευτερόλεπτα πριν", 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 2782be65da9..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,6 +16,23 @@ "Files" => "Dosieroj", "Text" => "Teksto", "Images" => "Bildoj", +"%s enter the database username." => "%s enigu la uzantonomon de la datumbazo.", +"%s enter the database name." => "%s enigu la nomon de la datumbazo.", +"%s you may not use dots in the database name" => "%s vi ne povas uzi punktojn en la nomo de la datumbazo", +"MS SQL username and/or password not valid: %s" => "La uzantonomo de MS SQL aŭ la pasvorto ne validas: %s", +"MySQL username and/or password not valid" => "La uzantonomo de MySQL aŭ la pasvorto ne validas", +"DB Error: \"%s\"" => "Datumbaza eraro: “%s”", +"MySQL user '%s'@'localhost' exists already." => "La uzanto de MySQL “%s”@“localhost” jam ekzistas.", +"Drop this user from MySQL" => "Forigi ĉi tiun uzanton el MySQL", +"MySQL user '%s'@'%%' already exists" => "La uzanto de MySQL “%s”@“%%” jam ekzistas", +"Drop this user from MySQL." => "Forigi ĉi tiun uzanton el MySQL.", +"Oracle connection could not be established" => "Konekto al Oracle ne povas stariĝi", +"Oracle username and/or password not valid" => "La uzantonomo de Oracle aŭ la pasvorto ne validas", +"PostgreSQL username and/or password not valid" => "La uzantonomo de PostgreSQL aŭ la pasvorto ne validas", +"Set an admin username." => "Starigi administran uzantonomon.", +"Set an admin password." => "Starigi administran pasvorton.", +"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Via TTT-servilo ankoraŭ ne ĝuste agordiĝis por permesi sinkronigi dosierojn ĉar la WebDAV-interfaco ŝajnas rompita.", +"Please double check the <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", diff --git a/lib/l10n/es.php b/lib/l10n/es.php index 3b32036d3af..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,15 +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.", "%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 connection could not be established" => "No se pudo establecer la conexión a Oracle", "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\"", @@ -32,9 +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", diff --git a/lib/l10n/es_AR.php b/lib/l10n/es_AR.php index 1df1b16de65..e66771f7e74 100644 --- a/lib/l10n/es_AR.php +++ b/lib/l10n/es_AR.php @@ -5,6 +5,7 @@ "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", @@ -16,13 +17,10 @@ "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", "%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", "MySQL username and/or password not valid" => "Usuario y/o contraseña MySQL no válido", "DB Error: \"%s\"" => "Error DB: \"%s\"", @@ -31,9 +29,12 @@ "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" => "segundos atrás", diff --git a/lib/l10n/et_EE.php b/lib/l10n/et_EE.php index 24fc98bde64..4da2c36d6ac 100644 --- a/lib/l10n/et_EE.php +++ b/lib/l10n/et_EE.php @@ -5,6 +5,7 @@ "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", @@ -16,15 +17,11 @@ "Files" => "Failid", "Text" => "Tekst", "Images" => "Pildid", -"Set an admin username." => "Määra admin kasutajanimi.", -"Set an admin password." => "Määra admini parool.", "%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", -"%s set the database host." => "%s määra andmebaasi server.", -"PostgreSQL username and/or password not valid" => "PostgreSQL kasutajatunnus ja/või parool pole õiged", +"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.", -"Oracle connection could not be established" => "Ei suuda luua ühendust Oracle baasiga", "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\"", @@ -32,9 +29,12 @@ "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", -"MS SQL username and/or password not valid: %s" => "MS SQL kasutajatunnus ja/või parool pole õiged: %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", diff --git a/lib/l10n/eu.php b/lib/l10n/eu.php index 05b68b062c5..028ad0a631e 100644 --- a/lib/l10n/eu.php +++ b/lib/l10n/eu.php @@ -5,6 +5,7 @@ "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", @@ -16,13 +17,10 @@ "Files" => "Fitxategiak", "Text" => "Testua", "Images" => "Irudiak", -"Set an admin username." => "Ezarri administraziorako erabiltzaile izena.", -"Set an admin password." => "Ezarri administraziorako pasahitza.", "%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.", "MySQL username and/or password not valid" => "MySQL erabiltzaile edota pasahitza ez dira egokiak.", "DB Error: \"%s\"" => "DB errorea: \"%s\"", @@ -33,7 +31,9 @@ "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" => "segundu", diff --git a/lib/l10n/fa.php b/lib/l10n/fa.php index b0d423421df..40a778e2126 100644 --- a/lib/l10n/fa.php +++ b/lib/l10n/fa.php @@ -5,15 +5,36 @@ "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" => "تصاویر", +"%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" => "ثانیهها پیش", diff --git a/lib/l10n/fi_FI.php b/lib/l10n/fi_FI.php index 0caa7b12df6..75576c3034d 100644 --- a/lib/l10n/fi_FI.php +++ b/lib/l10n/fi_FI.php @@ -5,6 +5,7 @@ "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", @@ -16,21 +17,21 @@ "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.", "%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 connection could not be established" => "Oracle-yhteyttä ei voitu muodostaa", +"MS SQL username and/or password not valid: %s" => "MS SQL -käyttäjätunnus ja/tai -salasana on väärin: %s", "MySQL username and/or password not valid" => "MySQL:n käyttäjätunnus ja/tai salasana on väärin", "DB Error: \"%s\"" => "Tietokantavirhe: \"%s\"", "MySQL user '%s'@'localhost' exists already." => "MySQL-käyttäjä '%s'@'localhost' on jo olemassa.", "Drop this user from MySQL" => "Pudota tämä käyttäjä MySQL:stä", "MySQL user '%s'@'%%' already exists" => "MySQL-käyttäjä '%s'@'%%' on jo olemassa", "Drop this user from MySQL." => "Pudota tämä käyttäjä MySQL:stä.", +"Oracle connection could not be established" => "Oracle-yhteyttä ei voitu muodostaa", "Oracle username and/or password not valid" => "Oraclen käyttäjätunnus ja/tai salasana on väärin", -"MS SQL username and/or password not valid: %s" => "MS SQL -käyttäjätunnus ja/tai -salasana on väärin: %s", +"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", diff --git a/lib/l10n/fr.php b/lib/l10n/fr.php index aed5d056f37..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,15 +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.", "%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 connection could not be established" => "La connexion Oracle ne peut pas être établie", "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\"", @@ -32,9 +29,12 @@ "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" => "il y a quelques secondes", diff --git a/lib/l10n/gl.php b/lib/l10n/gl.php index 1b4db4b30af..351f18c7155 100644 --- a/lib/l10n/gl.php +++ b/lib/l10n/gl.php @@ -5,6 +5,7 @@ "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", @@ -16,15 +17,11 @@ "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", "%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 connection could not be established" => "Non foi posíbel estabelecer a conexión con Oracle", "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»", @@ -32,9 +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", diff --git a/lib/l10n/he.php b/lib/l10n/he.php index dcd0545adba..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 דקות", diff --git a/lib/l10n/hr.php b/lib/l10n/hr.php index 3ce75c99f0e..41c34d3108c 100644 --- a/lib/l10n/hr.php +++ b/lib/l10n/hr.php @@ -5,6 +5,7 @@ "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 3b5c886bd2c..3aa04274fa3 100644 --- a/lib/l10n/hu_HU.php +++ b/lib/l10n/hu_HU.php @@ -5,6 +5,7 @@ "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", @@ -16,15 +17,11 @@ "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.", "%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 connection could not be established" => "Az Oracle kapcsolat nem hozható létre", "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\"", @@ -32,9 +29,12 @@ "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" => "pár másodperce", diff --git a/lib/l10n/ia.php b/lib/l10n/ia.php index 573281553fc..e5f6e3ddf58 100644 --- a/lib/l10n/ia.php +++ b/lib/l10n/ia.php @@ -5,6 +5,7 @@ "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 29843a95327..c247651f0c9 100644 --- a/lib/l10n/id.php +++ b/lib/l10n/id.php @@ -5,6 +5,7 @@ "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", @@ -16,13 +17,10 @@ "Files" => "Berkas", "Text" => "Teks", "Images" => "Gambar", -"Set an admin username." => "Setel nama pengguna admin.", -"Set an admin password." => "Setel sandi admin.", "%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", -"%s set the database host." => "%s setel host basis data.", -"PostgreSQL username and/or password not valid" => "Nama pengguna dan/atau sandi PostgreSQL tidak valid", +"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\"", @@ -33,7 +31,9 @@ "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", -"MS SQL username and/or password not valid: %s" => "Nama pengguna dan/atau sandi MySQL tidak valid: %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", diff --git a/lib/l10n/is.php b/lib/l10n/is.php index 05bb6883953..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", diff --git a/lib/l10n/it.php b/lib/l10n/it.php index db26ac82ae3..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,15 +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.", "%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 connection could not be established" => "La connessione a Oracle non può essere stabilita", "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\"", @@ -32,9 +29,12 @@ "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", diff --git a/lib/l10n/ja_JP.php b/lib/l10n/ja_JP.php index a2eb4bee67b..36d06d360b9 100644 --- a/lib/l10n/ja_JP.php +++ b/lib/l10n/ja_JP.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." => "ファイルは1つずつダウンロードする必要があります。", "Back to Files" => "ファイルに戻る", @@ -16,15 +17,11 @@ "Files" => "ファイル", "Text" => "TTY TDD", "Images" => "画像", -"Set an admin username." => "管理者のユーザ名を設定。", -"Set an admin password." => "管理者のパスワードを設定。", "%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 connection could not be established" => "Oracleへの接続が確立できませんでした。", "MySQL username and/or password not valid" => "MySQLのユーザ名もしくはパスワードは有効ではありません", "DB Error: \"%s\"" => "DBエラー: \"%s\"", "Offending command was: \"%s\"" => "違反コマンド: \"%s\"", @@ -32,9 +29,12 @@ "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" => "数秒前", diff --git a/lib/l10n/ka_GE.php b/lib/l10n/ka_GE.php index 93835e4ead7..c6e77da2dac 100644 --- a/lib/l10n/ka_GE.php +++ b/lib/l10n/ka_GE.php @@ -5,6 +5,7 @@ "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" => "უკან ფაილებში", @@ -16,13 +17,10 @@ "Files" => "ფაილები", "Text" => "ტექსტი", "Images" => "სურათები", -"Set an admin username." => "დააყენეთ ადმინისტრატორის სახელი.", -"Set an admin password." => "დააყენეთ ადმინისტრატორის პაროლი.", "%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." => "თქვენ უნდა შეიყვანოთ არსებული მომხმარებელის სახელი ან ადმინისტრატორი.", "MySQL username and/or password not valid" => "MySQL იუზერნეიმი და/ან პაროლი არ არის სწორი", "DB Error: \"%s\"" => "DB შეცდომა: \"%s\"", @@ -33,7 +31,9 @@ "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", -"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" => "წამის წინ", diff --git a/lib/l10n/ko.php b/lib/l10n/ko.php index bf2a68369f1..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분 전", diff --git a/lib/l10n/ku_IQ.php b/lib/l10n/ku_IQ.php index 20d0249f569..6d7461a1685 100644 --- a/lib/l10n/ku_IQ.php +++ b/lib/l10n/ku_IQ.php @@ -3,5 +3,6 @@ "Settings" => "دهستكاری", "Users" => "بهكارهێنهر", "Apps" => "بهرنامهكان", -"Admin" => "بهڕێوهبهری سهرهكی" +"Admin" => "بهڕێوهبهری سهرهكی", +"web services under your control" => "ڕاژهی وێب لهژێر چاودێریت دایه" ); diff --git a/lib/l10n/lb.php b/lib/l10n/lb.php index 889fc3a377d..867b0a37409 100644 --- a/lib/l10n/lb.php +++ b/lib/l10n/lb.php @@ -3,12 +3,17 @@ "Personal" => "Perséinlech", "Settings" => "Astellungen", "Users" => "Benotzer", -"Apps" => "Applicatiounen", +"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 cebaa6937d8..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,13 +15,17 @@ "Token expired. Please reload page." => "Sesija baigėsi. Prašome perkrauti puslapį.", "Files" => "Failai", "Text" => "Žinučių", +"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" => "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 140c75af3ce..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,13 +17,10 @@ "Files" => "Datnes", "Text" => "Teksts", "Images" => "Attēli", -"Set an admin username." => "Iestatiet administratora lietotājvārdu.", -"Set an admin password." => "Iestatiet administratora paroli.", "%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.", "MySQL username and/or password not valid" => "Nav derīga MySQL parole un/vai lietotājvārds", "DB Error: \"%s\"" => "DB kļūda — “%s”", @@ -33,7 +31,9 @@ "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ļ", diff --git a/lib/l10n/mk.php b/lib/l10n/mk.php index 34790c93745..30fa9ab73c1 100644 --- a/lib/l10n/mk.php +++ b/lib/l10n/mk.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" => "Назад кон датотеки", diff --git a/lib/l10n/ms_MY.php b/lib/l10n/ms_MY.php index 6abbbe86e80..a2930597971 100644 --- a/lib/l10n/ms_MY.php +++ b/lib/l10n/ms_MY.php @@ -5,6 +5,7 @@ "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 5d1812fd742..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" => "ဖိုင်သို့ပြန်သွားမည်", diff --git a/lib/l10n/nb_NO.php b/lib/l10n/nb_NO.php index 23146154c77..ab2d4f91920 100644 --- a/lib/l10n/nb_NO.php +++ b/lib/l10n/nb_NO.php @@ -5,6 +5,7 @@ "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", diff --git a/lib/l10n/nl.php b/lib/l10n/nl.php index 2a6086a5968..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,15 +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.", "%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 connection could not be established" => "Er kon geen verbinding met Oracle worden bereikt", "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\"", @@ -32,9 +29,12 @@ "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>." => "Controleer de <a href='%s'>installatiehandleiding</a> goed.", "seconds ago" => "seconden geleden", diff --git a/lib/l10n/nn_NO.php b/lib/l10n/nn_NO.php index 8241573f9ae..c1739398109 100644 --- a/lib/l10n/nn_NO.php +++ b/lib/l10n/nn_NO.php @@ -5,6 +5,7 @@ "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", diff --git a/lib/l10n/oc.php b/lib/l10n/oc.php index 85e2a27b431..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", diff --git a/lib/l10n/pl.php b/lib/l10n/pl.php index 53a9290785c..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,15 +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.", "%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 connection could not be established" => "Nie można ustanowić połączenia z bazą Oracle", "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\"", @@ -32,9 +29,12 @@ "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.", +"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", diff --git a/lib/l10n/pt_BR.php b/lib/l10n/pt_BR.php index 9606477d945..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,15 +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.", "%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 connection could not be established" => "Conexão Oracle não pode ser estabelecida", "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\"", @@ -32,9 +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", diff --git a/lib/l10n/pt_PT.php b/lib/l10n/pt_PT.php index f49258157ed..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,15 +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", "%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 connection could not be established" => "Não foi possível estabelecer a ligação Oracle", "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\"", @@ -32,9 +29,12 @@ "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" => "Minutos atrás", diff --git a/lib/l10n/ro.php b/lib/l10n/ro.php index 6661caf86e7..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ă", diff --git a/lib/l10n/ru.php b/lib/l10n/ru.php index e077b688c09..052b0487c6c 100644 --- a/lib/l10n/ru.php +++ b/lib/l10n/ru.php @@ -5,6 +5,7 @@ "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,13 +17,10 @@ "Files" => "Файлы", "Text" => "Текст", "Images" => "Изображения", -"Set an admin username." => "Установить имя пользователя для admin.", -"Set an admin password." => "становит пароль для admin.", "%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." => "Вы должны войти или в существующий аккаунт или под администратором.", "MySQL username and/or password not valid" => "Неверное имя пользователя и/или пароль MySQL", "DB Error: \"%s\"" => "Ошибка БД: \"%s\"", @@ -31,9 +29,12 @@ "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" => "несколько секунд назад", diff --git a/lib/l10n/si_LK.php b/lib/l10n/si_LK.php index 4846fdcc066..49ded7026e0 100644 --- a/lib/l10n/si_LK.php +++ b/lib/l10n/si_LK.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" => "ගොනු වෙතට නැවත යන්න", diff --git a/lib/l10n/sk_SK.php b/lib/l10n/sk_SK.php index c1ec2470b46..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,15 +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.", "%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 connection could not be established" => "Nie je možné pripojiť sa k Oracle", "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\"", @@ -32,9 +29,12 @@ "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", diff --git a/lib/l10n/sl.php b/lib/l10n/sl.php index 7f8827d17f3..a5b4decd61a 100644 --- a/lib/l10n/sl.php +++ b/lib/l10n/sl.php @@ -5,6 +5,7 @@ "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", @@ -16,13 +17,10 @@ "Files" => "Datoteke", "Text" => "Besedilo", "Images" => "Slike", -"Set an admin username." => "Nastavi uporabniško ime skrbnika.", -"Set an admin password." => "Nastavi geslo skrbnika.", "%s enter the database username." => "%s - vnos uporabniškega imena podatkovne zbirke.", "%s enter the database name." => "%s - vnos imena podatkovne zbirke.", "%s you may not use dots in the database name" => "%s - v imenu podatkovne zbirke ni dovoljeno uporabljati pik.", -"%s set the database host." => "%s - vnos gostitelja podatkovne zbirke.", -"PostgreSQL username and/or password not valid" => "Uporabniško ime ali geslo PostgreSQL ni veljavno", +"MS SQL username and/or password not valid: %s" => "Uporabniško ime ali geslo MS SQL ni veljavno: %s", "You need to enter either an existing account or the administrator." => "Prijaviti se je treba v obstoječi ali pa skrbniški račun.", "MySQL username and/or password not valid" => "Uporabniško ime ali geslo MySQL ni veljavno", "DB Error: \"%s\"" => "Napaka podatkovne zbirke: \"%s\"", @@ -31,9 +29,12 @@ "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 veljavno: %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", diff --git a/lib/l10n/sq.php b/lib/l10n/sq.php index 04186f62102..df5e2a31743 100644 --- a/lib/l10n/sq.php +++ b/lib/l10n/sq.php @@ -5,6 +5,7 @@ "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", @@ -16,13 +17,10 @@ "Files" => "Skedarët", "Text" => "Tekst", "Images" => "Foto", -"Set an admin username." => "Cakto emrin e administratorit.", -"Set an admin password." => "Cakto kodin e administratorit.", "%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", -"%s set the database host." => "%s caktoni pozicionin (host) e database-it.", -"PostgreSQL username and/or password not valid" => "Përdoruesi dhe/apo kodi i PostgreSQL i pavlefshëm", +"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\"", @@ -33,7 +31,9 @@ "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", -"MS SQL username and/or password not valid: %s" => "Përdoruesi dhe/apo kodi i MS SQL i pavlefshëm: %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ë", diff --git a/lib/l10n/sr.php b/lib/l10n/sr.php index 45b8e06200c..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" => "Назад на датотеке", diff --git a/lib/l10n/sv.php b/lib/l10n/sv.php index 3dcb26d5d8d..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", diff --git a/lib/l10n/ta_LK.php b/lib/l10n/ta_LK.php index c9bb578b40f..9193f6f1d2f 100644 --- a/lib/l10n/ta_LK.php +++ b/lib/l10n/ta_LK.php @@ -5,6 +5,7 @@ "Users" => "பயனாளர்", "Apps" => "செயலிகள்", "Admin" => "நிர்வாகம்", +"web services under your control" => "வலைய சேவைகள் உங்களுடைய கட்டுப்பாட்டின் கீழ் உள்ளது", "ZIP download is turned off." => "வீசொலிப் பூட்டு பதிவிறக்கம் நிறுத்தப்பட்டுள்ளது.", "Files need to be downloaded one by one." => "கோப்புகள்ஒன்றன் பின் ஒன்றாக பதிவிறக்கப்படவேண்டும்.", "Back to Files" => "கோப்புகளுக்கு செல்க", diff --git a/lib/l10n/th_TH.php b/lib/l10n/th_TH.php index 7cda4ab6ae6..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" => "กลับไปที่ไฟล์", diff --git a/lib/l10n/tr.php b/lib/l10n/tr.php index 7996447b95d..6325ad9886a 100644 --- a/lib/l10n/tr.php +++ b/lib/l10n/tr.php @@ -5,6 +5,7 @@ "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,13 +17,10 @@ "Files" => "Dosyalar", "Text" => "Metin", "Images" => "Resimler", -"Set an admin username." => "Bir adi kullanici vermek. ", -"Set an admin password." => "Parola yonetici birlemek. ", "%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", -"%s set the database host." => "%s veritabanı sunucu adını tanımla", -"PostgreSQL username and/or password not valid" => "PostgreSQL adi kullanici ve/veya parola yasal degildir. ", +"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''", @@ -31,9 +29,12 @@ "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", -"MS SQL username and/or password not valid: %s" => "MS SQL kullanıcı adı ve/veya parolası geçersiz: %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", diff --git a/lib/l10n/uk.php b/lib/l10n/uk.php index 676879629ef..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,13 +17,10 @@ "Files" => "Файли", "Text" => "Текст", "Images" => "Зображення", -"Set an admin username." => "Встановіть ім'я адміністратора.", -"Set an admin password." => "Встановіть пароль адміністратора.", "%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.", "MySQL username and/or password not valid" => "MySQL ім'я користувача та/або пароль не дійсні", "DB Error: \"%s\"" => "Помилка БД: \"%s\"", @@ -33,7 +31,9 @@ "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" => "секунди тому", 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 6a4b8ebac93..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", diff --git a/lib/l10n/zh_CN.GB2312.php b/lib/l10n/zh_CN.GB2312.php index 3ab35f2bafa..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" => "返回到文件", diff --git a/lib/l10n/zh_CN.php b/lib/l10n/zh_CN.php index 61e405d8058..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,13 +17,10 @@ "Files" => "文件", "Text" => "文本", "Images" => "图片", -"Set an admin username." => "请设置一个管理员用户名。", -"Set an admin password." => "请设置一个管理员密码。", "%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." => "你需要输入一个数据库中已有的账户或管理员账户。", "MySQL username and/or password not valid" => "MySQL 数据库用户名和/或密码无效", "DB Error: \"%s\"" => "数据库错误:\"%s\"", @@ -31,9 +29,12 @@ "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" => "秒前", diff --git a/lib/l10n/zh_TW.php b/lib/l10n/zh_TW.php index 4e0d50e7fc9..afd196f7c82 100644 --- a/lib/l10n/zh_TW.php +++ b/lib/l10n/zh_TW.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,15 +17,11 @@ "Files" => "檔案", "Text" => "文字", "Images" => "圖片", -"Set an admin username." => "設定管理員帳號。", -"Set an admin password." => "設定管理員密碼。", "%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 connection could not be established" => "無法建立 Oracle 資料庫連線", "MySQL username and/or password not valid" => "MySQL 用戶名和/或密碼無效", "DB Error: \"%s\"" => "資料庫錯誤:\"%s\"", "Offending command was: \"%s\"" => "有問題的指令是:\"%s\"", @@ -32,9 +29,12 @@ "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 界面似乎無法使用。", "Please double check the <a href='%s'>installation guides</a>." => "請參考<a href='%s'>安裝指南</a>。", "seconds ago" => "幾秒前", 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/legacy/log.php b/lib/legacy/log.php new file mode 100644 index 00000000000..7802ead2412 --- /dev/null +++ b/lib/legacy/log.php @@ -0,0 +1,77 @@ +<?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); + } + } + + //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; + } + } + + // Uncaught exception handler + public static function onException($exception) { + self::write('PHP', + $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine(), + self::FATAL); + } + + //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); + + } +} 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/mail.php b/lib/mail.php index e15af277a64..b339b33e962 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -113,9 +113,12 @@ class OC_Mail { */ public static function getfooter() { - $txt="\n-- \n"; - $txt.="ownCloud\n"; - $txt.="Your Cloud, Your Data, Your Way!\n"; + $defaults = new OC_Defaults(); + + $txt="\n--\n"; + $txt.=$defaults->getName() . "\n"; + $txt.=$defaults->getSlogan() . "\n"; + return($txt); } 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/share.php b/lib/public/share.php index 03d662676c6..596a729a47d 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -123,85 +123,99 @@ class Share { 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' + * @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, $removeDuplicates = true) { + public static function getUsersSharingFile($path, $user, $includeOwner = false) { - $path_parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR)); - $path = ''; $shares = array(); $publicShare = false; + $source = -1; + $cache = false; + $view = new \OC\Files\View('/' . $user . '/files/'); - foreach ($path_parts as $p) { - $path .= '/' . $p; - $meta = $view->getFileInfo(\OC_Filesystem::normalizePath($path)); + $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 + 'SELECT `share_with` FROM `*PREFIX*share` WHERE - item_source = ? AND share_type = ?' + `item_source` = ? AND `share_type` = ?' ); $result = $query->execute(array($source, self::SHARE_TYPE_USER)); - if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); - } - - while ($row = $result->fetchRow()) { - $shares[] = $row['share_with']; + 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 + 'SELECT `share_with` FROM `*PREFIX*share` WHERE - item_source = ? AND share_type = ?' + `item_source` = ? AND `share_type` = ?' ); $result = $query->execute(array($source, self::SHARE_TYPE_GROUP)); - if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); - } - - while ($row = $result->fetchRow()) { - $usersInGroup = \OC_Group::usersInGroup($row['share_with']); - $shares = array_merge($shares, $usersInGroup); + 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 - $query = \OC_DB::prepare( - 'SELECT share_with - FROM - `*PREFIX*share` - WHERE - item_source = ? AND share_type = ?' - ); + 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)); + $result = $query->execute(array($source, self::SHARE_TYPE_LINK)); - if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); + } else { + if ($result->fetchRow()) { + $publicShare = true; + } + } } - - 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 @@ -278,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 @@ -298,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); } @@ -620,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 @@ -648,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)); } @@ -949,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; @@ -964,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; @@ -995,7 +1073,7 @@ class Share { if (!isset($mounts[$row['storage']])) { $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']); if (is_array($mountPoints)) { - $mounts[$row['storage']] = $mountPoints[key($mountPoints)]; + $mounts[$row['storage']] = current($mountPoints); } } if ($mounts[$row['storage']]) { @@ -1572,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 @@ -1587,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 6744c2d37bd..d69602f4507 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -355,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 4d8380eb9ac..df33217f95d 100755 --- a/lib/request.php +++ b/lib/request.php @@ -9,7 +9,7 @@ class OC_Request { /** * @brief Check overwrite condition - * @returns true/false + * @returns bool */ private static function isOverwriteCondition($type = '') { $regex = '/' . OC_Config::getValue('overwritecondaddr', '') . '/'; @@ -19,7 +19,7 @@ class OC_Request { /** * @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 @@ -40,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; } @@ -48,7 +54,7 @@ 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 */ @@ -70,7 +76,7 @@ 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 @@ -85,7 +91,7 @@ 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 @@ -139,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'])) { @@ -150,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/setup.php b/lib/setup.php index a63cc664dbc..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'); @@ -40,765 +34,88 @@ class OC_Setup { $options['directory'] = OC::$SERVERROOT."/data"; } - 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']); - - if (OC_Util::runningOnWindows()) { - $datadir = rtrim(realpath($datadir), '\\'); - } - - //use sqlite3 when available, otherise sqlite2 will be used. - if($dbtype=='sqlite' and class_exists('SQLite3')) { - $dbtype='sqlite3'; - } - - //generate a random salt that is used to salt the local user passwords - $salt = OC_Util::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 connection could not be established'), - 'hint' => $e->getMessage().' 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' - ); - 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 - error_log("creating sqlite db"); - OC_DB::createDbFromStructure('db_structure.xml'); - } - - //create the user and group - try { - OC_User::createUser($username, $password); - } - catch(Exception $exception) { - $error[] = 'Error while trying to create admin user: ' . $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=OC_Util::generate_random_bytes(30); - - 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=OC_Util::generate_random_bytes(30); - - 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); - } + if (!isset(self::$dbSetupClasses[$dbtype])) { + $dbtype = 'sqlite'; } - } - 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); - } + $class = self::$dbSetupClasses[$dbtype]; + $dbSetup = new $class(self::getTrans(), 'db_structure.xml'); + $error = array_merge($error, $dbSetup->validate($options)); - 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); - } + if(count($error) != 0) { + return $error; } - } - 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; - } - \OC_Log::write('setup oracle', 'connect string: ' . $easy_connect_string, \OC_Log::DEBUG); - $connection = @oci_connect($dbuser, $dbpass, $easy_connect_string); - if(!$connection) { - $e = oci_error(); - if (is_array ($e) && isset ($e['message'])) { - throw new Exception($e['message']); - } - throw new Exception($l->t('Oracle username and/or password not valid')); - } - //check for roles creation rights in oracle + //no errors, good + $username = htmlspecialchars_decode($options['adminlogin']); + $password = htmlspecialchars_decode($options['adminpass']); + $datadir = htmlspecialchars_decode($options['directory']); - $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 (OC_Util::runningOnWindows()) { + $datadir = rtrim(realpath($datadir), '\\'); } - 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=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. - $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); + //use sqlite3 when available, otherise sqlite2 will be used. + if($dbtype=='sqlite' and class_exists('SQLite3')) { + $dbtype='sqlite3'; } - //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'); + //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); - $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')); + //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); } - $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); - } - $result = oci_execute($stmt); - if($result) { - $row = oci_fetch_row($stmt); + //create the user and group + try { + OC_User::createUser($username, $password); } - if(!$result or $row[0]==0) { - OC_DB::createDbFromStructure('db_structure.xml'); + catch(Exception $exception) { + $error[] = $exception->getMessage(); } - } - /** - * - * @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(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'); - 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); - } - } - // 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); - - $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))); - } - - 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); + OC_Group::createGroup('admin'); + OC_Group::addToGroup($username, 'admin'); + OC_User::login($username, $password); - sqlsrv_close($masterConnection); + //guess what this does + OC_Installer::installShippedApps(); - 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 = ''; + //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) { - $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); - } - } - } + //and we are done + OC_Config::setValue('installed', true); } - } - 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); - } - } - } - } - - 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); - } - } - - private static function mssql_createDatabaseStructure($dbhost, $dbname, $dbuser, $dbpass, $dbtableprefix) { - $connectionInfo = array( "Database" => $dbname, "UID" => $dbuser, "PWD" => $dbpass); - - $connection = @sqlsrv_connect($dbhost, $connectionInfo); - - //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 = ''; - } - $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'); - } - } - } - - sqlsrv_close($connection); + return $error; } /** 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 9467dedb62a..ae9ea187445 100644 --- a/lib/template.php +++ b/lib/template.php @@ -535,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/updater.php b/lib/updater.php index 9081bfc4be8..df7332a96a9 100644 --- a/lib/updater.php +++ b/lib/updater.php @@ -1,56 +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() { + 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); + if ((\OC_Appconfig::getValue('core', 'lastupdatedat') + 1800) > time()) { + return json_decode(\OC_Appconfig::getValue('core', 'lastupdateResult'), true); } - OC_Appconfig::setValue('core', 'lastupdatedat', time()); + \OC_Appconfig::setValue('core', 'lastupdatedat', time()); - if(OC_Appconfig::getValue('core', 'installedat', '')=='') { - OC_Appconfig::setValue('core', 'installedat', microtime(true)); + 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( @@ -60,21 +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; // Cache the result - OC_Appconfig::setValue('core', 'lastupdateResult', json_encode($data)); + \OC_Appconfig::setValue('core', 'lastupdateResult', json_encode($data)); return $tmp; } -}
\ No newline at end of file + + /** + * runs the update actions in maintenance mode, does not upgrade the source files + */ + public function upgrade() { + \OC_DB::enableCaching(false); + \OC_Config::setValue('maintenance', true); + $installedVersion = \OC_Config::getValue('version', '0.0.0'); + $currentVersion = implode('.', \OC_Util::getVersion()); + if ($this->log) { + $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core')); + } + $this->emit('\OC\Updater', 'maintenanceStart'); + try { + \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); + $this->emit('\OC\Updater', 'dbUpgrade'); + + // do a file cache upgrade for users with files + // this can take loooooooooooooooooooooooong + $this->upgradeFileCache(); + } catch (\Exception $exception) { + $this->emit('\OC\Updater', 'failure', array($exception->getMessage())); + } + \OC_Config::setValue('version', implode('.', \OC_Util::getVersion())); + \OC_App::checkAppsRequirements(); + // load all apps to also upgrade enabled apps + \OC_App::loadApps(); + \OC_Config::setValue('maintenance', false); + $this->emit('\OC\Updater', 'maintenanceEnd'); + } + + private function upgradeFileCache() { + try { + $query = \OC_DB::prepare(' + SELECT DISTINCT `user` + FROM `*PREFIX*fscache` + '); + $result = $query->execute(); + } catch (\Exception $e) { + return; + } + $users = $result->fetchAll(); + if (count($users) == 0) { + return; + } + $step = 100 / count($users); + $percentCompleted = 0; + $lastPercentCompletedOutput = 0; + $startInfoShown = false; + foreach ($users as $userRow) { + $user = $userRow['user']; + \OC\Files\Filesystem::initMountPoints($user); + \OC\Files\Cache\Upgrade::doSilentUpgrade($user); + if (!$startInfoShown) { + //We show it only now, because otherwise Info about upgraded apps + //will appear between this and progress info + $this->emit('\OC\Updater', 'filecacheStart'); + $startInfoShown = true; + } + $percentCompleted += $step; + $out = floor($percentCompleted); + if ($out != $lastPercentCompletedOutput) { + $this->emit('\OC\Updater', 'filecacheProgress', array($out)); + $lastPercentCompletedOutput = $out; + } + } + $this->emit('\OC\Updater', 'filecacheDone'); + } +} diff --git a/lib/user.php b/lib/user.php index 1dde87a1339..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_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, "password" => $password)); - - 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) { - \OC::$session->set('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 (OC_User::getUser() === $uid) { - \OC::$session->set('display_name', $displayName); + if (is_null($displayName)) { + $displayName = $uid; } - 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( \OC::$session->get('user_id')) { + if (\OC::$session->get('user_id')) { OC_App::loadApps(array('authentication')); self::setupBackends(); - if (self::userExists(\OC::$session->get('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,32 +316,40 @@ class OC_User { * @return string uid or false */ public static function getUser() { - if( \OC::$session->get('user_id') ) { - return \OC::$session->get('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( \OC::$session->get('display_name') ) { - return \OC::$session->get('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 */ @@ -391,112 +359,89 @@ class OC_User { /** * @brief Set password - * @param $uid The username - * @param $password The new password - * @param $recoveryPassword for the encryption app to reset encryption keys - * @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, $recoveryPassword = null ) { - $run = true; - OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password, "recoveryPassword" => $recoveryPassword )); - - 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, "recoveryPassword" => $recoveryPassword )); - 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; } /** @@ -506,152 +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 = $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` = ?'; - if (OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') { //FIXME oracle hack - $sql = 'SELECT `userid` FROM `*PREFIX*preferences`' - .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND to_char(`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, OC::$WEBROOT, '', $secure_cookie); - setcookie("oc_token", $token, $expires, OC::$WEBROOT, '', $secure_cookie, true); - setcookie("oc_remember_login", true, $expires, OC::$WEBROOT, '', $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 d70b620f2ab..9f00a022d9f 100644 --- a/lib/user/database.php +++ b/lib/user/database.php @@ -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; } 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 581f35bc0ac..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 * @@ -77,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, 04); + return array(5, 80, 05); } /** @@ -169,6 +172,8 @@ 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')) @@ -181,14 +186,16 @@ class OC_Util { } //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. @@ -196,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" ); @@ -208,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', @@ -528,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 @@ -641,11 +667,10 @@ class OC_Util { /** * Check if the ownCloud server can connect to the internet */ - public static function isinternetconnectionworking() { - - // in case there is no internet connection on purpose there is no need to display a warning - if (!\OC_Config::getValue("has_internet_connection", true)) { - return true; + 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. @@ -667,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 @@ -810,9 +842,9 @@ class OC_Util { * @return string the theme */ public static function getTheme() { - $theme = OC_Config::getValue("theme"); + $theme = OC_Config::getValue("theme", ''); - if(is_null($theme)) { + if($theme === '') { if(is_dir(OC::$SERVERROOT . '/themes/default')) { $theme = 'default'; @@ -823,5 +855,41 @@ class OC_Util { 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 91c72d5dfae..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); @@ -554,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); |