aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/l10n/ast.php7
-rwxr-xr-xlib/private/activitymanager.php194
-rw-r--r--lib/private/appconfig.php4
-rw-r--r--lib/private/connector/sabre/aborteduploaddetectionplugin.php98
-rw-r--r--lib/private/connector/sabre/file.php20
-rw-r--r--lib/private/db/mdb2schemareader.php1
-rw-r--r--lib/private/files/cache/cache.php2
-rw-r--r--lib/private/l10n.php3
-rw-r--r--lib/private/preferences.php11
-rw-r--r--lib/private/repair.php3
-rw-r--r--lib/private/setup/mysql.php2
-rw-r--r--lib/public/activity/iextension.php120
-rw-r--r--lib/public/activity/imanager.php72
-rw-r--r--lib/repair/collation.php75
14 files changed, 499 insertions, 113 deletions
diff --git a/lib/l10n/ast.php b/lib/l10n/ast.php
index 078aad4529a..1ec3d8e28d3 100644
--- a/lib/l10n/ast.php
+++ b/lib/l10n/ast.php
@@ -93,14 +93,17 @@ $TRANSLATIONS = array(
"Cannot write into \"apps\" directory" => "Nun pue escribise nel direutoriu \"apps\"",
"Cannot create \"data\" directory (%s)" => "Nun pue crease'l direutoriu \"data\" (%s)",
"This can usually be fixed by <a href=\"%s\" target=\"_blank\">giving the webserver write access to the root directory</a>." => "Esto pue iguase davezu <a href=\"%s\" target=\"_blank\">dándo-y accesu d'escritura al direutoriu raigañu</a>.",
+"Please install one of theses locales on your system and restart your webserver." => "Instala ún d'estos locales nel to sistema y reanicia'l sirvidor web",
"Please ask your server administrator to install the module." => "Por favor, entrúga-y al to alministrador del sirvidor pa instalar el módulu.",
"PHP module %s not installed." => "Nun ta instaláu'l módulu PHP %s",
+"PHP %s or higher is required." => "Necesítase PHP %s o superior",
"PHP Safe Mode is enabled. ownCloud requires that it is disabled to work properly." => "Ta habilitáu'l mou seguru de PHP. ownCloud requier que tea deshabilitáu pa furrular afayadízamente",
"Please ask your server administrator to restart the web server." => "Por favor, entruga al to alministrador pa reaniciar el sirvidor web.",
"PostgreSQL >= 9 required" => "PostgreSQL >= 9 requeríu",
-"Please upgrade your database version" => "Por favor, anova la versión de la to base de datos",
-"Error occurred while checking PostgreSQL version" => "Asocedió un fallu entrín se comprobaba la versión de PostgreSQL",
+"Please upgrade your database version" => "Por favor, anueva la versión de la to base de datos",
+"Error occurred while checking PostgreSQL version" => "Asocedió un fallu mientres se comprobaba la versión de PostgreSQL",
"Please change the permissions to 0770 so that the directory cannot be listed by other users." => "Por favor, camuda los permisos a 0770 pa que'l direutoriu nun pueda llistase por otros usuarios.",
+"Data directory (%s) is readable by other users" => "El direutoriu de datos (%s) ye llexible por otros usuarios",
"Data directory (%s) is invalid" => "Ye inválidu'l direutoriu de datos (%s)",
"Could not obtain lock type %d on \"%s\"." => "Nun pudo facese'l bloquéu %d en \"%s\"."
);
diff --git a/lib/private/activitymanager.php b/lib/private/activitymanager.php
index 66aa039eb18..f31b121c8e8 100755
--- a/lib/private/activitymanager.php
+++ b/lib/private/activitymanager.php
@@ -10,13 +10,22 @@ namespace OC;
use OCP\Activity\IConsumer;
+use OCP\Activity\IExtension;
use OCP\Activity\IManager;
class ActivityManager implements IManager {
+ /**
+ * @var \Closure[]
+ */
private $consumers = array();
/**
+ * @var \Closure[]
+ */
+ private $extensions = array();
+
+ /**
* @param $app
* @param $subject
* @param $subjectParams
@@ -65,4 +74,189 @@ class ActivityManager implements IManager {
array_push($this->consumers, $callable);
}
+ /**
+ * In order to improve lazy loading a closure can be registered which will be called in case
+ * activity consumers are actually requested
+ *
+ * $callable has to return an instance of OCA\Activity\IConsumer
+ *
+ * @param \Closure $callable
+ * @return void
+ */
+ function registerExtension(\Closure $callable) {
+ array_push($this->extensions, $callable);
+ }
+
+ /**
+ * Will return additional notification types as specified by other apps
+ *
+ * @param string $languageCode
+ * @return array
+ */
+ function getNotificationTypes($languageCode) {
+ $notificationTypes = array();
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $result = $c->getNotificationTypes($languageCode);
+ if (is_array($result)) {
+ $notificationTypes = array_merge($notificationTypes, $result);
+ }
+ }
+ }
+
+ return $notificationTypes;
+ }
+
+ /**
+ * @param array $types
+ * @param string $filter
+ * @return array
+ */
+ function filterNotificationTypes($types, $filter) {
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $result = $c->filterNotificationTypes($types, $filter);
+ if (is_array($result)) {
+ $types = $result;
+ }
+ }
+ }
+ return $types;
+ }
+
+ /**
+ * @param string $method
+ * @return array
+ */
+ function getDefaultTypes($method) {
+ $defaultTypes = array();
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $types = $c->getDefaultTypes($method);
+ if (is_array($types)) {
+ $defaultTypes = array_merge($types, $defaultTypes);
+ }
+ }
+ }
+ return $defaultTypes;
+ }
+
+ /**
+ * @param string $app
+ * @param string $text
+ * @param array $params
+ * @param boolean $stripPath
+ * @param boolean $highlightParams
+ * @param string $languageCode
+ * @return string|false
+ */
+ function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) {
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $translation = $c->translate($app, $text, $params, $stripPath, $highlightParams, $languageCode);
+ if (is_string($translation)) {
+ return $translation;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $type
+ * @return string
+ */
+ function getTypeIcon($type) {
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $icon = $c->getTypeIcon($type);
+ if (is_string($icon)) {
+ return $icon;
+ }
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @param array $activity
+ * @return integer|false
+ */
+ function getGroupParameter($activity) {
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $parameter = $c->getGroupParameter($activity);
+ if ($parameter !== false) {
+ return $parameter;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ function getNavigation() {
+ $entries = array(
+ 'apps' => array(),
+ 'top' => array(),
+ );
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $additionalEntries = $c->getNavigation();
+ if (is_array($additionalEntries)) {
+ $entries['apps'] = array_merge($entries['apps'], $additionalEntries['apps']);
+ $entries['top'] = array_merge($entries['top'], $additionalEntries['top']);
+ }
+ }
+ }
+
+ return $entries;
+ }
+
+ /**
+ * @param string $filterValue
+ * @return boolean
+ */
+ function isFilterValid($filterValue) {
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ if ($c->isFilterValid($filterValue) === true) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $filter
+ * @return array
+ */
+ function getQueryForFilter($filter) {
+ foreach($this->extensions as $extension) {
+ $c = $extension();
+ if ($c instanceof IExtension) {
+ $result = $c->getQueryForFilter($filter);
+ if (is_array($result)) {
+ return $result;
+ }
+ }
+ }
+
+ return array(null, null);
+ }
}
diff --git a/lib/private/appconfig.php b/lib/private/appconfig.php
index f20c4a08426..1874d9f2b19 100644
--- a/lib/private/appconfig.php
+++ b/lib/private/appconfig.php
@@ -183,6 +183,10 @@ class AppConfig implements \OCP\IAppConfig {
);
$this->conn->insert('*PREFIX*appconfig', $data);
} else {
+ $oldValue = $this->getValue($app, $key);
+ if($oldValue === strval($value)) {
+ return true;
+ }
$data = array(
'configvalue' => $value,
);
diff --git a/lib/private/connector/sabre/aborteduploaddetectionplugin.php b/lib/private/connector/sabre/aborteduploaddetectionplugin.php
deleted file mode 100644
index b569f9a83c3..00000000000
--- a/lib/private/connector/sabre/aborteduploaddetectionplugin.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-/**
- * Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-/**
- * Class OC_Connector_Sabre_AbortedUploadDetectionPlugin
- *
- * This plugin will verify if the uploaded data has been stored completely.
- * This is done by comparing the content length of the request with the file size on storage.
- */
-class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends \Sabre\DAV\ServerPlugin {
-
- /**
- * Reference to main server object
- *
- * @var \Sabre\DAV\Server
- */
- private $server;
-
- /**
- * @var \OC\Files\View
- */
- private $fileView;
-
- /**
- * @param \OC\Files\View $view
- */
- public function __construct($view) {
- $this->fileView = $view;
- }
-
- /**
- * This initializes the plugin.
- *
- * This function is called by \Sabre\DAV\Server, after
- * addPlugin is called.
- *
- * This method should set up the requires event subscriptions.
- *
- * @param \Sabre\DAV\Server $server
- */
- public function initialize(\Sabre\DAV\Server $server) {
-
- $this->server = $server;
-
- $server->subscribeEvent('afterCreateFile', array($this, 'verifyContentLength'), 10);
- $server->subscribeEvent('afterWriteContent', array($this, 'verifyContentLength'), 10);
- }
-
- /**
- * @param string $filePath
- * @param \Sabre\DAV\INode $node
- * @throws \Sabre\DAV\Exception\BadRequest
- */
- public function verifyContentLength($filePath, \Sabre\DAV\INode $node = null) {
-
- // we should only react on PUT which is used for upload
- // e.g. with LOCK this will not work, but LOCK uses createFile() as well
- if ($this->server->httpRequest->getMethod() !== 'PUT') {
- return;
- }
-
- // ownCloud chunked upload will be handled in its own plugin
- $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked');
- if ($chunkHeader) {
- return;
- }
-
- // compare expected and actual size
- $expected = $this->getLength();
- if (!$expected) {
- return;
- }
- $actual = $this->fileView->filesize($filePath);
- if ($actual != $expected) {
- $this->fileView->unlink($filePath);
- throw new \Sabre\DAV\Exception\BadRequest('expected filesize ' . $expected . ' got ' . $actual);
- }
-
- }
-
- /**
- * @return string
- */
- public function getLength() {
- $req = $this->server->httpRequest;
- $length = $req->getHeader('X-Expected-Entity-Length');
- if (!$length) {
- $length = $req->getHeader('Content-Length');
- }
-
- return $length;
- }
-}
diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php
index 7591cc5c066..ece6885f24f 100644
--- a/lib/private/connector/sabre/file.php
+++ b/lib/private/connector/sabre/file.php
@@ -71,13 +71,13 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
}
// mark file as partial while uploading (ignored by the scanner)
- $partpath = $this->path . '.ocTransferId' . rand() . '.part';
+ $partFilePath = $this->path . '.ocTransferId' . rand() . '.part';
try {
- $putOkay = $this->fileView->file_put_contents($partpath, $data);
+ $putOkay = $this->fileView->file_put_contents($partFilePath, $data);
if ($putOkay === false) {
\OC_Log::write('webdav', '\OC\Files\Filesystem::file_put_contents() failed', \OC_Log::ERROR);
- $this->fileView->unlink($partpath);
+ $this->fileView->unlink($partFilePath);
// because we have no clue about the cause we can only throw back a 500/Internal Server Error
throw new \Sabre\DAV\Exception('Could not write file contents');
}
@@ -102,13 +102,22 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e);
}
+ // double check if the file was fully received
+ // compare expected and actual size
+ $expected = $_SERVER['CONTENT_LENGTH'];
+ $actual = $this->fileView->filesize($partFilePath);
+ if ($actual != $expected) {
+ $this->fileView->unlink($partFilePath);
+ throw new \Sabre\DAV\Exception\BadRequest('expected filesize ' . $expected . ' got ' . $actual);
+ }
+
// rename to correct path
try {
- $renameOkay = $this->fileView->rename($partpath, $this->path);
+ $renameOkay = $this->fileView->rename($partFilePath, $this->path);
$fileExists = $this->fileView->file_exists($this->path);
if ($renameOkay === false || $fileExists === false) {
\OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR);
- $this->fileView->unlink($partpath);
+ $this->fileView->unlink($partFilePath);
throw new \Sabre\DAV\Exception('Could not rename part file to final file');
}
}
@@ -259,5 +268,4 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
return null;
}
-
}
diff --git a/lib/private/db/mdb2schemareader.php b/lib/private/db/mdb2schemareader.php
index 61f58a1f200..288eef5cda0 100644
--- a/lib/private/db/mdb2schemareader.php
+++ b/lib/private/db/mdb2schemareader.php
@@ -82,6 +82,7 @@ class MDB2SchemaReader {
$name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name);
$name = $this->platform->quoteIdentifier($name);
$table = $schema->createTable($name);
+ $table->addOption('collate', 'utf8_bin');
break;
case 'create':
case 'overwrite':
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php
index 72af474adf8..cfa3e916185 100644
--- a/lib/private/files/cache/cache.php
+++ b/lib/private/files/cache/cache.php
@@ -472,6 +472,8 @@ class Cache {
$sql .= 'REGEXP_LIKE(`name`, ?, \'i\')';
} else if($dbtype === 'pgsql') {
$sql .= '`name` ILIKE ?';
+ } else if ($dbtype === 'mysql') {
+ $sql .= '`name` COLLATE utf8_general_ci LIKE ?';
} else {
$sql .= '`name` LIKE ?';
}
diff --git a/lib/private/l10n.php b/lib/private/l10n.php
index 3e44be88150..28b35e92a2f 100644
--- a/lib/private/l10n.php
+++ b/lib/private/l10n.php
@@ -404,14 +404,15 @@ class OC_L10N implements \OCP\IL10N {
/**
* find the best language
+ *
* @param array|string $app details below
- * string language
*
* If $app is an array, ownCloud assumes that these are the available
* languages. Otherwise ownCloud tries to find the files in the l10n
* folder.
*
* If nothing works it returns 'en'
+ * @return string language
*/
public function getLanguageCode($app=null) {
return self::findLanguage($app);
diff --git a/lib/private/preferences.php b/lib/private/preferences.php
index d1db25bbf09..a849cc23e1a 100644
--- a/lib/private/preferences.php
+++ b/lib/private/preferences.php
@@ -173,11 +173,16 @@ class Preferences {
*/
public function setValue($user, $app, $key, $value, $preCondition = null) {
// Check if the key does exist
- $query = 'SELECT COUNT(*) FROM `*PREFIX*preferences`'
+ $query = 'SELECT `configvalue` FROM `*PREFIX*preferences`'
. ' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?';
- $count = $this->conn->fetchColumn($query, array($user, $app, $key));
- $exists = $count > 0;
+ $oldValue = $this->conn->fetchColumn($query, array($user, $app, $key));
+ $exists = $oldValue !== false;
+ if($oldValue === strval($value)) {
+ // no changes
+ return true;
+ }
+
$affectedRows = 0;
if (!$exists && $preCondition === null) {
diff --git a/lib/private/repair.php b/lib/private/repair.php
index 89886dd9316..e6943c5d057 100644
--- a/lib/private/repair.php
+++ b/lib/private/repair.php
@@ -81,7 +81,8 @@ class Repair extends BasicEmitter {
*/
public static function getBeforeUpgradeRepairSteps() {
return array(
- new \OC\Repair\InnoDB()
+ new \OC\Repair\InnoDB(),
+ new \OC\Repair\Collation(\OC::$server->getConfig(), \OC_DB::getConnection())
);
}
diff --git a/lib/private/setup/mysql.php b/lib/private/setup/mysql.php
index b2c28173b1c..3327965fb49 100644
--- a/lib/private/setup/mysql.php
+++ b/lib/private/setup/mysql.php
@@ -61,7 +61,7 @@ class MySQL extends AbstractDatabase {
$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`";
+ $query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET utf8 COLLATE utf8_bin;";
$result = mysql_query($query, $connection);
if(!$result) {
$entry = $this->trans->t('DB Error: "%s"', array(mysql_error($connection))) . '<br />';
diff --git a/lib/public/activity/iextension.php b/lib/public/activity/iextension.php
new file mode 100644
index 00000000000..6bb403a8896
--- /dev/null
+++ b/lib/public/activity/iextension.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2014 Thomas Müller deepdiver@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Public interface of ownCloud for apps to use.
+ * Activity/IExtension interface
+ */
+
+// 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\Activity;
+
+interface IExtension {
+ /**
+ * The extension can return an array of additional notification types.
+ * If no additional types are to be added false is to be returned
+ *
+ * @param string $languageCode
+ * @return array|false
+ */
+ public function getNotificationTypes($languageCode);
+
+ /**
+ * The extension can filter the types based on the filter if required.
+ * In case no filter is to be applied false is to be returned unchanged.
+ *
+ * @param array $types
+ * @param string $filter
+ * @return array|false
+ */
+ public function filterNotificationTypes($types, $filter);
+
+ /**
+ * For a given method additional types to be displayed in the settings can be returned.
+ * In case no additional types are to be added false is to be returned.
+ *
+ * @param string $method
+ * @return array|false
+ */
+ public function getDefaultTypes($method);
+
+ /**
+ * The extension can translate a given message to the requested languages.
+ * If no translation is available false is to be returned.
+ *
+ * @param string $app
+ * @param string $text
+ * @param array $params
+ * @param boolean $stripPath
+ * @param boolean $highlightParams
+ * @param string $languageCode
+ * @return string|false
+ */
+ public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode);
+
+ /**
+ * A string naming the css class for the icon to be used can be returned.
+ * If no icon is known for the given type false is to be returned.
+ *
+ * @param string $type
+ * @return string|false
+ */
+ public function getTypeIcon($type);
+
+ /**
+ * The extension can define the parameter grouping by returning the index as integer.
+ * In case no grouping is required false is to be returned.
+ *
+ * @param array $activity
+ * @return integer|false
+ */
+ public function getGroupParameter($activity);
+
+ /**
+ * The extension can define additional navigation entries. The array returned has to contain two keys 'top'
+ * and 'apps' which hold arrays with the relevant entries.
+ * If no further entries are to be added false is no be returned.
+ *
+ * @return array|false
+ */
+ public function getNavigation();
+
+ /**
+ * The extension can check if a customer filter (given by a query string like filter=abc) is valid or not.
+ *
+ * @param string $filterValue
+ * @return boolean
+ */
+ public function isFilterValid($filterValue);
+
+ /**
+ * For a given filter the extension can specify the sql query conditions including parameters for that query.
+ * In case the extension does not know the filter false is to be returned.
+ * The query condition and the parameters are to be returned as array with two elements.
+ * E.g. return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%'));
+ *
+ * @param string $filter
+ * @return array|false
+ */
+ public function getQueryForFilter($filter);
+}
diff --git a/lib/public/activity/imanager.php b/lib/public/activity/imanager.php
index 449fdcc934d..0a49fdf4999 100644
--- a/lib/public/activity/imanager.php
+++ b/lib/public/activity/imanager.php
@@ -50,11 +50,81 @@ interface IManager {
* In order to improve lazy loading a closure can be registered which will be called in case
* activity consumers are actually requested
*
- * $callable has to return an instance of OCA\Activity\IConsumer
+ * $callable has to return an instance of \OCP\Activity\IConsumer
*
* @param \Closure $callable
* @return void
*/
function registerConsumer(\Closure $callable);
+ /**
+ * In order to improve lazy loading a closure can be registered which will be called in case
+ * activity consumers are actually requested
+ *
+ * $callable has to return an instance of \OCP\Activity\IExtension
+ *
+ * @param \Closure $callable
+ * @return void
+ */
+ function registerExtension(\Closure $callable);
+
+ /**
+ * Will return additional notification types as specified by other apps
+ * @param string $languageCode
+ * @return array
+ */
+ function getNotificationTypes($languageCode);
+
+ /**
+ * @param array $types
+ * @param string $filter
+ * @return array
+ */
+ function filterNotificationTypes($types, $filter);
+
+ /**
+ * @param string $method
+ * @return array
+ */
+ function getDefaultTypes($method);
+
+ /**
+ * @param string $app
+ * @param string $text
+ * @param array $params
+ * @param boolean $stripPath
+ * @param boolean $highlightParams
+ * @param string $languageCode
+ * @return string|false
+ */
+ function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode);
+
+ /**
+ * @param string $type
+ * @return string
+ */
+ function getTypeIcon($type);
+
+ /**
+ * @param array $activity
+ * @return integer|false
+ */
+ function getGroupParameter($activity);
+
+ /**
+ * @return array
+ */
+ function getNavigation();
+
+ /**
+ * @param string $filterValue
+ * @return boolean
+ */
+ function isFilterValid($filterValue);
+
+ /**
+ * @param string $filter
+ * @return array
+ */
+ function getQueryForFilter($filter);
}
diff --git a/lib/repair/collation.php b/lib/repair/collation.php
new file mode 100644
index 00000000000..2247cf82d0a
--- /dev/null
+++ b/lib/repair/collation.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Copyright (c) 2014 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\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class Collation extends BasicEmitter implements \OC\RepairStep {
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var \OC\DB\Connection
+ */
+ protected $connection;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OC\DB\Connection $connection
+ */
+ public function __construct($config, $connection) {
+ $this->connection = $connection;
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Repair MySQL collation';
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+ if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
+ $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to no'));
+ return;
+ }
+
+ $tables = $this->getAllNonUTF8BinTables($this->connection);
+ foreach ($tables as $table) {
+ $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
+ $query->execute();
+ }
+ }
+
+ /**
+ * @param \Doctrine\DBAL\Connection $connection
+ * @return string[]
+ */
+ protected function getAllNonUTF8BinTables($connection) {
+ $dbName = $this->config->getSystemValue("dbname");
+ $rows = $connection->fetchAll(
+ "SELECT DISTINCT(TABLE_NAME) AS `table`" .
+ " FROM INFORMATION_SCHEMA . COLUMNS" .
+ " WHERE TABLE_SCHEMA = ?" .
+ " AND (COLLATION_NAME <> 'utf8_bin' OR CHARACTER_SET_NAME <> 'utf8')" .
+ " AND TABLE_NAME LIKE \"*PREFIX*%\"",
+ array($dbName)
+ );
+ $result = array();
+ foreach ($rows as $row) {
+ $result[] = $row['table'];
+ }
+ return $result;
+ }
+}
+