diff --git a/.gitignore b/.gitignore index e61ec6f0359..b24edc91282 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,11 @@ nbproject # Node Modules /build/node_modules/ +# nodejs +/build/lib/ +/npm-debug.log + + # Tests - auto-generated files /data-autotest /tests/coverage* diff --git a/.gitmodules b/.gitmodules index b9c1a3702cf..bc2beee81ad 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "3rdparty"] path = 3rdparty - url = git://github.com/owncloud/3rdparty.git + url = https://github.com/owncloud/3rdparty.git diff --git a/.jshintrc b/.jshintrc index 90cec5c5961..77f9e9f143d 100644 --- a/.jshintrc +++ b/.jshintrc @@ -11,18 +11,22 @@ "maxparams": 5, "curly": true, "jquery": true, - "maxlen": 80, + "maxlen": 120, "indent": 4, "browser": true, "globals": { "console": true, "it": true, - "itx": true, + "xit": true, "expect": true, "describe": true, "beforeEach": true, "afterEach": true, "sinon": true, - "fakeServer": true + "fakeServer": true, + "_": true, + "OC": true, + "t": true, + "n": true } } diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 4473cf9056d..fa05b9b8a40 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -7,6 +7,7 @@ filter: - 'apps/*/l10n/*' - 'lib/l10n/*' - 'core/js/tests/lib/*.js' + - 'core/js/tests/specs/*.js' - 'core/js/jquery-1.10.0.min.js' - 'core/js/jquery-migrate-1.2.1.min.js' - 'core/js/jquery-showpassword.js' @@ -15,6 +16,8 @@ filter: - 'core/js/jquery-ui-1.10.0.custom.js' - 'core/js/jquery.inview.js' - 'core/js/jquery.placeholder.js' + - 'core/js/underscore.js' + - 'core/js/jquery.multiselect.js' imports: diff --git a/README.md b/README.md index 3f76c1a4773..0b13f11e768 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,14 @@ Git master: [![Build Status](https://ci.owncloud.org/job/server-master-linux/bad Quality: [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/owncloud/core/badges/quality-score.png?s=ce2f5ded03d4ac628e9ee5c767243fa7412e644f)](https://scrutinizer-ci.com/g/owncloud/core/) ### Installation instructions -http://doc.owncloud.org/server/5.0/developer_manual/app/gettingstarted.html +http://doc.owncloud.org/server/7.0/developer_manual/app/index.html ### Contribution Guidelines -http://owncloud.org/dev/contribute/ +http://owncloud.org/contribute/ ### Get in touch * [Forum](http://forum.owncloud.org) -* [Mailing list](https://mail.kde.org/mailman/listinfo/owncloud) +* [Mailing list](http://mailman.owncloud.org/mailman/listinfo) * [IRC channel](https://webchat.freenode.net/?channels=owncloud) * [Twitter](https://twitter.com/ownClouders) @@ -25,4 +25,4 @@ Please submit translations via Transifex: https://www.transifex.com/projects/p/owncloud/ For more detailed information about translations: -http://owncloud.org/dev/translation/ +http://doc.owncloud.org/server/7.0/developer_manual/core/translation.html diff --git a/apps/files/ajax/download.php b/apps/files/ajax/download.php index 1f7e42e0d3e..4b4a7f8948d 100644 --- a/apps/files/ajax/download.php +++ b/apps/files/ajax/download.php @@ -21,12 +21,6 @@ * */ -// only need filesystem apps -$RUNTIME_APPTYPES=array('filesystem'); - -// Init owncloud - - // Check if we are a user OCP\User::checkLoggedIn(); \OC::$session->close(); diff --git a/apps/files/ajax/getstoragestats.php b/apps/files/ajax/getstoragestats.php index 17415b6933f..dd8af39bada 100644 --- a/apps/files/ajax/getstoragestats.php +++ b/apps/files/ajax/getstoragestats.php @@ -1,8 +1,5 @@ close(); @@ -13,37 +7,21 @@ OCP\JSON::checkLoggedIn(); $dir = isset( $_GET['dir'] ) ? $_GET['dir'] : ''; $dir = \OC\Files\Filesystem::normalizePath($dir); $dirInfo = \OC\Files\Filesystem::getFileInfo($dir); -if (!$dirInfo->getType() === 'dir') { +if (!$dirInfo || !$dirInfo->getType() === 'dir') { header("HTTP/1.0 404 Not Found"); exit(); } -$doBreadcrumb = isset($_GET['breadcrumb']); $data = array(); $baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; $permissions = $dirInfo->getPermissions(); -// Make breadcrumb -if($doBreadcrumb) { - $breadcrumb = \OCA\Files\Helper::makeBreadcrumb($dir); - - $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); - $breadcrumbNav->assign('breadcrumb', $breadcrumb, false); - $breadcrumbNav->assign('baseURL', $baseUrl); - - $data['breadcrumb'] = $breadcrumbNav->fetchPage(); -} - // make filelist $files = \OCA\Files\Helper::getFiles($dir); -$list = new OCP\Template("files", "part.list", ""); -$list->assign('files', $files, false); -$list->assign('baseURL', $baseUrl, false); -$list->assign('downloadURL', OCP\Util::linkToRoute('download', array('file' => '/'))); -$list->assign('isPublic', false); -$data['files'] = $list->fetchPage(); +$data['directory'] = $dir; +$data['files'] = \OCA\Files\Helper::formatFileInfos($files); $data['permissions'] = $permissions; OCP\JSON::success(array('data' => $data)); diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php index 1234cf11394..7d6be59beab 100644 --- a/apps/files/ajax/newfile.php +++ b/apps/files/ajax/newfile.php @@ -112,9 +112,8 @@ if($source) { } if($result) { $meta = \OC\Files\Filesystem::getFileInfo($target); - $mime=$meta['mimetype']; - $id = $meta['fileid']; - $eventSource->send('success', array('mime' => $mime, 'size' => \OC\Files\Filesystem::filesize($target), 'id' => $id, 'etag' => $meta['etag'])); + $data = \OCA\Files\Helper::formatFileInfo($meta); + $eventSource->send('success', $data); } else { $eventSource->send('error', array('message' => $l10n->t('Error while downloading %s to %s', array($source, $target)))); } @@ -139,16 +138,7 @@ if($source) { if($success) { $meta = \OC\Files\Filesystem::getFileInfo($target); - $id = $meta['fileid']; - $mime = $meta['mimetype']; - $size = $meta['size']; - OCP\JSON::success(array('data' => array( - 'id' => $id, - 'mime' => $mime, - 'size' => $size, - 'content' => $content, - 'etag' => $meta['etag'], - ))); + OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta))); exit(); } } diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php index 032447460f3..89c241189d7 100644 --- a/apps/files/ajax/newfolder.php +++ b/apps/files/ajax/newfolder.php @@ -58,8 +58,8 @@ if(\OC\Files\Filesystem::mkdir($target)) { $path = '/'.$foldername; } $meta = \OC\Files\Filesystem::getFileInfo($path); - $id = $meta['fileid']; - OCP\JSON::success(array('data' => array('id' => $id))); + $meta['type'] = 'dir'; // missing ?! + OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta))); exit(); } diff --git a/apps/files/ajax/rawlist.php b/apps/files/ajax/rawlist.php deleted file mode 100644 index 6c2569e2ebb..00000000000 --- a/apps/files/ajax/rawlist.php +++ /dev/null @@ -1,57 +0,0 @@ -close(); - -// Load the files -$dir = isset($_GET['dir']) ? $_GET['dir'] : ''; -$mimetypes = isset($_GET['mimetypes']) ? json_decode($_GET['mimetypes'], true) : ''; - -// Clean up duplicates from array and deal with non-array requests -if (is_array($mimetypes)) { - $mimetypes = array_unique($mimetypes); -} elseif (is_null($mimetypes)) { - $mimetypes = array($_GET['mimetypes']); -} - -// make filelist -$files = array(); -/** - * @var \OCP\Files\FileInfo[] $files - */ -// If a type other than directory is requested first load them. -if ($mimetypes && !in_array('httpd/unix-directory', $mimetypes)) { - $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir, 'httpd/unix-directory')); -} - -if (is_array($mimetypes) && count($mimetypes)) { - foreach ($mimetypes as $mimetype) { - $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir, $mimetype)); - } -} else { - $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir)); -} -// Sort by name -usort($files, array('\OCA\Files\Helper', 'fileCmp')); - -$result = array(); -foreach ($files as $file) { - $fileData = array(); - $fileData['directory'] = $dir; - $fileData['name'] = $file->getName(); - $fileData['type'] = $file->getType(); - $fileData['path'] = $file['path']; - $fileData['id'] = $file->getId(); - $fileData['size'] = $file->getSize(); - $fileData['mtime'] = $file->getMtime(); - $fileData['mimetype'] = $file->getMimetype(); - $fileData['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file->getMimetype()); - $fileData["date"] = OCP\Util::formatDate($file->getMtime()); - $fileData['mimetype_icon'] = \OCA\Files\Helper::determineIcon($file); - $result[] = $fileData; -} - -OC_JSON::success(array('data' => $result)); diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index 4ed51c52775..b21a9dfba2e 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -20,6 +20,10 @@ if (empty($_POST['dirToken'])) { die(); } } else { + // TODO: ideally this code should be in files_sharing/ajax/upload.php + // and the upload/file transfer code needs to be refactored into a utility method + // that could be used there + // return only read permissions for public upload $allowedPermissions = OCP\PERMISSION_READ; $public_directory = !empty($_POST['subdir']) ? $_POST['subdir'] : '/'; @@ -141,19 +145,14 @@ if (strpos($dir, '..') === false) { $error = $l->t('The target folder has been moved or deleted.'); $errorCode = 'targetnotfound'; } else { - $result[] = array('status' => 'success', - 'mime' => $meta['mimetype'], - 'mtime' => $meta['mtime'], - 'size' => $meta['size'], - 'id' => $meta['fileid'], - 'name' => basename($target), - 'etag' => $meta['etag'], - 'originalname' => $files['tmp_name'][$i], - 'uploadMaxFilesize' => $maxUploadFileSize, - 'maxHumanFilesize' => $maxHumanFileSize, - 'permissions' => $meta['permissions'] & $allowedPermissions, - 'directory' => $directory, - ); + $data = \OCA\Files\Helper::formatFileInfo($meta); + $data['status'] = 'success'; + $data['originalname'] = $files['tmp_name'][$i]; + $data['uploadMaxFilesize'] = $maxUploadFileSize; + $data['maxHumanFilesize'] = $maxHumanFileSize; + $data['permissions'] = $meta['permissions'] & $allowedPermissions; + $data['directory'] = $directory; + $result[] = $data; } } else { @@ -169,19 +168,15 @@ if (strpos($dir, '..') === false) { if ($meta === false) { $error = $l->t('Upload failed. Could not get file info.'); } else { - $result[] = array('status' => 'existserror', - 'mime' => $meta['mimetype'], - 'mtime' => $meta['mtime'], - 'size' => $meta['size'], - 'id' => $meta['fileid'], - 'name' => basename($target), - 'etag' => $meta['etag'], - 'originalname' => $files['tmp_name'][$i], - 'uploadMaxFilesize' => $maxUploadFileSize, - 'maxHumanFilesize' => $maxHumanFileSize, - 'permissions' => $meta['permissions'] & $allowedPermissions, - 'directory' => $directory, - ); + $data = \OCA\Files\Helper::formatFileInfo($meta); + $data['permissions'] = $data['permissions'] & $allowedPermissions; + $data['status'] = 'existserror'; + $data['originalname'] = $files['tmp_name'][$i]; + $data['uploadMaxFilesize'] = $maxUploadFileSize; + $data['maxHumanFilesize'] = $maxHumanFileSize; + $data['permissions'] = $meta['permissions'] & $allowedPermissions; + $data['directory'] = $directory; + $result[] = $data; } } } diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php index 1b2d144da5c..c1baee4f1ef 100644 --- a/apps/files/appinfo/remote.php +++ b/apps/files/appinfo/remote.php @@ -22,12 +22,6 @@ * License along with this library. If not, see . * */ -// load needed apps -$RUNTIME_APPTYPES = array('filesystem', 'authentication', 'logging'); - -OC_App::loadApps($RUNTIME_APPTYPES); - -OC_Util::obEnd(); // Backends $authBackend = new OC_Connector_Sabre_Auth(); @@ -44,6 +38,7 @@ $server->setBaseUri($baseuri); $defaults = new OC_Defaults(); $server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, $defaults->getName())); $server->addPlugin(new Sabre_DAV_Locks_Plugin($lockBackend)); +$server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); $server->addPlugin(new OC_Connector_Sabre_FilesPlugin()); $server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin()); $server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav')); diff --git a/apps/files/command/scan.php b/apps/files/command/scan.php index f334f29a939..25ab70af362 100644 --- a/apps/files/command/scan.php +++ b/apps/files/command/scan.php @@ -58,7 +58,6 @@ class Scan extends Command { protected function execute(InputInterface $input, OutputInterface $output) { if ($input->getOption('all')) { - \OC_App::loadApps('authentication'); $users = $this->userManager->search(''); } else { $users = $input->getArgument('user_id'); diff --git a/apps/files/css/files.css b/apps/files/css/files.css index af863aca33e..1bac5d2b7db 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -77,10 +77,10 @@ } /* make sure there's enough room for the file actions */ #body-user #filestable { - min-width: 750px; + min-width: 688px; /* 768 (mobile break) - 80 (nav width) */ } #body-user #controls { - min-width: 600px; + min-width: 688px; /* 768 (mobile break) - 80 (nav width) */ } #filestable tbody tr { background-color:#fff; height:40px; } diff --git a/apps/files/css/mobile.css b/apps/files/css/mobile.css new file mode 100644 index 00000000000..3ad7d634838 --- /dev/null +++ b/apps/files/css/mobile.css @@ -0,0 +1,68 @@ +@media only screen and (max-width: 768px) { + +/* don’t require a minimum width for files table */ +#body-user #filestable { + min-width: initial !important; +} + +/* do not show Deleted Files on mobile, not optimized yet and button too long */ +#controls #trash { + display: none; +} + +/* hide size and date columns */ +table th#headerSize, +table td.filesize, +table th#headerDate, +table td.date { + display: none; +} + +/* remove shift for multiselect bar to account for missing navigation */ +table.multiselect thead { + padding-left: 0; +} + +/* restrict length of displayed filename to prevent overflow */ +table td.filename .nametext { + max-width: 75% !important; +} + +/* always show actions on mobile, not only on hover */ +#fileList a.action { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)" !important; + filter: alpha(opacity=20) !important; + opacity: .2 !important; + display: inline !important; +} +/* do not show Rename or Versions on mobile */ +#fileList .action.action-rename, +#fileList .action.action-versions { + display: none !important; +} +/* some padding for better clickability */ +#fileList a.action img { + padding: 0 6px 0 12px; +} +/* hide text of the actions on mobile */ +#fileList a.action span { + display: none; +} + +/* ellipsis on file names */ +.nametext { + width: 60%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* proper notification area for multi line messages */ +#notification-container { + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; +} +} diff --git a/apps/files/index.php b/apps/files/index.php index c66cd40fb56..b8ff08c1b05 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -27,19 +27,21 @@ OCP\User::checkLoggedIn(); // Load the files we need OCP\Util::addStyle('files', 'files'); OCP\Util::addStyle('files', 'upload'); +OCP\Util::addStyle('files', 'mobile'); OCP\Util::addscript('files', 'file-upload'); OCP\Util::addscript('files', 'jquery.iframe-transport'); OCP\Util::addscript('files', 'jquery.fileupload'); OCP\Util::addscript('files', 'jquery-visibility'); +OCP\Util::addscript('files', 'breadcrumb'); OCP\Util::addscript('files', 'filelist'); OCP\App::setActiveNavigationEntry('files_index'); // Load the files $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : ''; $dir = \OC\Files\Filesystem::normalizePath($dir); -$dirInfo = \OC\Files\Filesystem::getFileInfo($dir); +$dirInfo = \OC\Files\Filesystem::getFileInfo($dir, false); // Redirect if directory does not exist -if (!$dirInfo->getType() === 'dir') { +if (!$dirInfo || !$dirInfo->getType() === 'dir') { header('Location: ' . OCP\Util::getScriptName() . ''); exit(); } @@ -59,44 +61,19 @@ if ($isIE8 && isset($_GET['dir'])){ exit(); } -$ajaxLoad = false; -$files = array(); $user = OC_User::getUser(); -if ($isIE8){ - // after the redirect above, the URL will have a format - // like "files#?dir=path" which means that no path was given - // (dir is not set). In that specific case, we don't return any - // files because the client will take care of switching the dir - // to the one from the hash, then ajax-load the initial file list - $files = array(); - $ajaxLoad = true; -} -else{ - $files = \OCA\Files\Helper::getFiles($dir); -} $config = \OC::$server->getConfig(); -// Make breadcrumb -$breadcrumb = \OCA\Files\Helper::makeBreadcrumb($dir); - -// make breadcrumb und filelist markup -$list = new OCP\Template('files', 'part.list', ''); -$list->assign('files', $files); -$list->assign('baseURL', OCP\Util::linkTo('files', 'index.php') . '?dir='); -$list->assign('downloadURL', OCP\Util::linkToRoute('download', array('file' => '/'))); -$list->assign('isPublic', false); -$breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); -$breadcrumbNav->assign('breadcrumb', $breadcrumb); -$breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files', 'index.php') . '?dir='); - +// needed for share init, permissions will be reloaded +// anyway with ajax load $permissions = $dirInfo->getPermissions(); // information about storage capacities -$storageInfo=OC_Helper::getStorageInfo($dir); +$storageInfo=OC_Helper::getStorageInfo($dir, $dirInfo); $freeSpace=$storageInfo['free']; $uploadLimit=OCP\Util::uploadLimit(); -$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); +$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir, $freeSpace); $publicUploadEnabled = $config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'); // if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code) $encryptionInitStatus = 2; @@ -111,20 +88,12 @@ if ($trashEnabled) { $trashEmpty = \OCA\Files_Trashbin\Trashbin::isEmpty($user); } -$isCreatable = \OC\Files\Filesystem::isCreatable($dir . '/'); -$fileHeader = (!isset($files) or count($files) > 0); -$emptyContent = ($isCreatable and !$fileHeader) or $ajaxLoad; - OCP\Util::addscript('files', 'fileactions'); OCP\Util::addscript('files', 'files'); OCP\Util::addscript('files', 'keyboardshortcuts'); $tmpl = new OCP\Template('files', 'index', 'user'); -$tmpl->assign('fileList', $list->fetchPage()); -$tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage()); $tmpl->assign('dir', $dir); -$tmpl->assign('isCreatable', $isCreatable); $tmpl->assign('permissions', $permissions); -$tmpl->assign('files', $files); $tmpl->assign('trash', $trashEnabled); $tmpl->assign('trashEmpty', $trashEmpty); $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit @@ -140,8 +109,5 @@ $tmpl->assign("mailNotificationEnabled", $config->getAppValue('core', 'shareapi_ $tmpl->assign("allowShareWithLink", $config->getAppValue('core', 'shareapi_allow_links', 'yes')); $tmpl->assign("encryptionInitStatus", $encryptionInitStatus); $tmpl->assign('disableSharing', false); -$tmpl->assign('ajaxLoad', $ajaxLoad); -$tmpl->assign('emptyContent', $emptyContent); -$tmpl->assign('fileHeader', $fileHeader); $tmpl->printPage(); diff --git a/apps/files/js/breadcrumb.js b/apps/files/js/breadcrumb.js new file mode 100644 index 00000000000..5bc2fac1369 --- /dev/null +++ b/apps/files/js/breadcrumb.js @@ -0,0 +1,241 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* 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 . +* +*/ + +/* global OC */ +(function() { + /** + * Creates an breadcrumb element in the given container + */ + var BreadCrumb = function(options){ + this.$el = $(''); + options = options || {}; + if (options.onClick) { + this.onClick = options.onClick; + } + if (options.onDrop) { + this.onDrop = options.onDrop; + } + if (options.getCrumbUrl) { + this.getCrumbUrl = options.getCrumbUrl; + } + }; + BreadCrumb.prototype = { + $el: null, + dir: null, + + lastWidth: 0, + hiddenBreadcrumbs: 0, + totalWidth: 0, + breadcrumbs: [], + onClick: null, + onDrop: null, + + /** + * Sets the directory to be displayed as breadcrumb. + * This will re-render the breadcrumb. + * @param dir path to be displayed as breadcrumb + */ + setDirectory: function(dir) { + dir = dir || '/'; + if (dir !== this.dir) { + this.dir = dir; + this.render(); + } + }, + + /** + * Returns the full URL to the given directory + * @param part crumb data as map + * @param index crumb index + * @return full URL + */ + getCrumbUrl: function(part, index) { + return '#'; + }, + + /** + * Renders the breadcrumb elements + */ + render: function() { + var parts = this._makeCrumbs(this.dir || '/'); + var $crumb; + this.$el.empty(); + this.breadcrumbs = []; + + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; + var $image; + var $link = $('').attr('href', this.getCrumbUrl(part, i)); + $link.text(part.name); + $crumb = $('
'); + $crumb.append($link); + $crumb.attr('data-dir', part.dir); + + if (part.img) { + $image = $(''); + $image.attr('src', part.img); + $link.append($image); + } + this.breadcrumbs.push($crumb); + this.$el.append($crumb); + if (this.onClick) { + $crumb.on('click', this.onClick); + } + } + $crumb.addClass('last'); + + // in case svg is not supported by the browser we need to execute the fallback mechanism + if (!OC.Util.hasSVGSupport()) { + OC.Util.replaceSVG(this.$el); + } + + // setup drag and drop + if (this.onDrop) { + this.$el.find('.crumb:not(.last)').droppable({ + drop: this.onDrop, + tolerance: 'pointer' + }); + } + + this._updateTotalWidth(); + this.resize($(window).width(), true); + }, + + /** + * Makes a breadcrumb structure based on the given path + * @param dir path to split into a breadcrumb structure + * @return array of map {dir: path, name: displayName} + */ + _makeCrumbs: function(dir) { + var crumbs = []; + var pathToHere = ''; + // trim leading and trailing slashes + dir = dir.replace(/^\/+|\/+$/g, ''); + var parts = dir.split('/'); + if (dir === '') { + parts = []; + } + // root part + crumbs.push({ + dir: '/', + name: '', + img: OC.imagePath('core', 'places/home.svg') + }); + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; + pathToHere = pathToHere + '/' + part; + crumbs.push({ + dir: pathToHere, + name: part + }); + } + return crumbs; + }, + + _updateTotalWidth: function () { + var self = this; + + this.lastWidth = 0; + + // initialize with some extra space + this.totalWidth = 64; + // FIXME: this class should not know about global elements + if ( $('#navigation').length ) { + this.totalWidth += $('#navigation').get(0).offsetWidth; + } + this.hiddenBreadcrumbs = 0; + + for (var i = 0; i < this.breadcrumbs.length; i++ ) { + this.totalWidth += $(this.breadcrumbs[i]).get(0).offsetWidth; + } + + $.each($('#controls .actions>div'), function(index, action) { + self.totalWidth += $(action).get(0).offsetWidth; + }); + + }, + + /** + * Show/hide breadcrumbs to fit the given width + */ + resize: function (width, firstRun) { + var i, $crumb; + + if (width === this.lastWidth) { + return; + } + + // window was shrinked since last time or first run ? + if ((width < this.lastWidth || firstRun) && width < this.totalWidth) { + if (this.hiddenBreadcrumbs === 0 && this.breadcrumbs.length > 1) { + // start by hiding the first breadcrumb after home, + // that one will have extra three dots displayed + $crumb = this.breadcrumbs[1]; + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.find('a').addClass('hidden'); + $crumb.append('...'); + this.totalWidth += $crumb.get(0).offsetWidth; + this.hiddenBreadcrumbs = 2; + } + i = this.hiddenBreadcrumbs; + // hide subsequent breadcrumbs if the space is still not enough + while (width < this.totalWidth && i > 1 && i < this.breadcrumbs.length - 1) { + $crumb = this.breadcrumbs[i]; + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.addClass('hidden'); + this.hiddenBreadcrumbs = i; + i++; + } + // window is bigger than last time + } else if (width > this.lastWidth && this.hiddenBreadcrumbs > 0) { + i = this.hiddenBreadcrumbs; + while (width > this.totalWidth && i > 0) { + if (this.hiddenBreadcrumbs === 1) { + // special handling for last one as it has the three dots + $crumb = this.breadcrumbs[1]; + if ($crumb) { + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.find('.ellipsis').remove(); + $crumb.find('a').removeClass('hidden'); + this.totalWidth += $crumb.get(0).offsetWidth; + } + } else { + $crumb = this.breadcrumbs[i]; + $crumb.removeClass('hidden'); + this.totalWidth += $crumb.get(0).offsetWidth; + if (this.totalWidth > width) { + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.addClass('hidden'); + break; + } + } + i--; + this.hiddenBreadcrumbs = i; + } + } + + this.lastWidth = width; + } + }; + + window.BreadCrumb = BreadCrumb; +})(); + diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 371c83e742c..e5d1eacbd14 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -180,7 +180,7 @@ OC.Upload = { }, init: function() { - if ( $('#file_upload_start').exists() && $('#file_upload_start').is(':visible')) { + if ( $('#file_upload_start').exists() ) { var file_upload_param = { dropZone: $('#content'), // restrict dropZone to content div @@ -483,28 +483,6 @@ OC.Upload = { $('#file_upload_start').attr('multiple', 'multiple'); } - //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder - var crumb=$('div.crumb').first(); - while($('div.controls').height() > 40 && crumb.next('div.crumb').length > 0) { - crumb.children('a').text('...'); - crumb = crumb.next('div.crumb'); - } - //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent - var crumb = $('div.crumb').first(); - var next = crumb.next('div.crumb'); - while($('div.controls').height()>40 && next.next('div.crumb').length > 0) { - crumb.remove(); - crumb = next; - next = crumb.next('div.crumb'); - } - //still not enough, start shorting down the current folder name - var crumb=$('div.crumb>a').last(); - while($('div.controls').height() > 40 && crumb.text().length > 6) { - var text=crumb.text(); - text = text.substr(0,text.length-6)+'...'; - crumb.text(text); - } - $(document).click(function(ev) { // do not close when clicking in the dropdown if ($(ev.target).closest('#new').length){ @@ -617,21 +595,7 @@ OC.Upload = { {dir:$('#dir').val(), filename:name}, function(result) { if (result.status === 'success') { - var date = new Date(); - // TODO: ideally addFile should be able to receive - // all attributes and set them automatically, - // and also auto-load the preview - var tr = FileList.addFile(name, 0, date, false, hidden); - tr.attr('data-size', result.data.size); - tr.attr('data-mime', result.data.mime); - tr.attr('data-id', result.data.id); - tr.attr('data-etag', result.data.etag); - tr.find('.filesize').text(humanFileSize(result.data.size)); - var path = getPathForPreview(name); - Files.lazyLoadPreview(path, result.data.mime, function(previewpath) { - tr.find('td.filename').attr('style','background-image:url('+previewpath+')'); - }, null, null, result.data.etag); - FileActions.display(tr.find('td.filename'), true); + FileList.add(result.data, {hidden: hidden, insert: true}); } else { OC.dialogs.alert(result.data.message, t('core', 'Could not create file')); } @@ -644,10 +608,7 @@ OC.Upload = { {dir:$('#dir').val(), foldername:name}, function(result) { if (result.status === 'success') { - var date=new Date(); - FileList.addDir(name, 0, date, hidden); - var tr = FileList.findFileEl(name); - tr.attr('data-id', result.data.id); + FileList.add(result.data, {hidden: hidden, insert: true}); } else { OC.dialogs.alert(result.data.message, t('core', 'Could not create folder')); } @@ -682,20 +643,10 @@ OC.Upload = { } }); eventSource.listen('success',function(data) { - var mime = data.mime; - var size = data.size; - var id = data.id; + var file = data; $('#uploadprogressbar').fadeOut(); - var date = new Date(); - FileList.addFile(localName, size, date, false, hidden); - var tr = FileList.findFileEl(localName); - tr.data('mime', mime).data('id', id); - tr.attr('data-id', id); - var path = $('#dir').val()+'/'+localName; - Files.lazyLoadPreview(path, mime, function(previewpath) { - tr.find('td.filename').attr('style', 'background-image:url('+previewpath+')'); - }, null, null, data.etag); - FileActions.display(tr.find('td.filename'), true); + + FileList.add(file, {hidden: hidden, insert: true}); }); eventSource.listen('error',function(error) { $('#uploadprogressbar').fadeOut(); diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index 9a69d7b3688..631aebea954 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -8,28 +8,40 @@ * */ -/* global OC, FileList */ +/* global OC, FileList, Files */ /* global trashBinApp */ var FileActions = { actions: {}, defaults: {}, icons: {}, currentFile: null, - register: function (mime, name, permissions, icon, action) { + register: function (mime, name, permissions, icon, action, displayName) { if (!FileActions.actions[mime]) { FileActions.actions[mime] = {}; } if (!FileActions.actions[mime][name]) { FileActions.actions[mime][name] = {}; } + if (!displayName) { + displayName = t('files', name); + } FileActions.actions[mime][name]['action'] = action; FileActions.actions[mime][name]['permissions'] = permissions; + FileActions.actions[mime][name]['displayName'] = displayName; FileActions.icons[name] = icon; }, setDefault: function (mime, name) { FileActions.defaults[mime] = name; }, get: function (mime, type, permissions) { + var actions = this.getActions(mime, type, permissions); + var filteredActions = {}; + $.each(actions, function (name, action) { + filteredActions[name] = action.action; + }); + return filteredActions; + }, + getActions: function (mime, type, permissions) { var actions = {}; if (FileActions.actions.all) { actions = $.extend(actions, FileActions.actions.all); @@ -51,7 +63,7 @@ var FileActions = { var filteredActions = {}; $.each(actions, function (name, action) { if (action.permissions & permissions) { - filteredActions[name] = action.action; + filteredActions[name] = action; } }); return filteredActions; @@ -82,7 +94,7 @@ var FileActions = { */ display: function (parent, triggerEvent) { FileActions.currentFile = parent; - var actions = FileActions.get(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions()); + var actions = FileActions.getActions(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions()); var file = FileActions.getCurrentFile(); var nameLinks; if (FileList.findFileEl(file).data('renaming')) { @@ -105,15 +117,16 @@ var FileActions = { event.data.actionFunc(file); }; - var addAction = function (name, action) { + var addAction = function (name, action, displayName) { // NOTE: Temporary fix to prevent rename action in root of Shared directory if (name === 'Rename' && $('#dir').val() === '/Shared') { return true; } if ((name === 'Download' || action !== defaultAction) && name !== 'Delete') { + var img = FileActions.icons[name], - actionText = t('files', name), + actionText = displayName, actionContainer = 'a.name>span.fileactions'; if (name === 'Rename') { @@ -125,7 +138,7 @@ var FileActions = { if (img.call) { img = img(file); } - var html = ''; + var html = ''; if (img) { html += ''; } @@ -133,8 +146,7 @@ var FileActions = { var element = $(html); element.data('action', name); - //alert(element); - element.on('click', {a: null, elem: parent, actionFunc: actions[name]}, actionHandler); + element.on('click', {a: null, elem: parent, actionFunc: actions[name].action}, actionHandler); parent.find(actionContainer).append(element); } @@ -142,12 +154,15 @@ var FileActions = { $.each(actions, function (name, action) { if (name !== 'Share') { - addAction(name, action); + displayName = action.displayName; + ah = action.action; + + addAction(name, ah, displayName); } }); if(actions.Share && !($('#dir').val() === '/' && file === 'Shared')){ - // t('files', 'Share') - addAction('Share', actions.Share); + displayName = t('files', 'Share'); + addAction('Share', actions.Share, displayName); } // remove the existing delete action @@ -165,7 +180,7 @@ var FileActions = { } var element = $(html); element.data('action', actions['Delete']); - element.on('click', {a: null, elem: parent, actionFunc: actions['Delete']}, actionHandler); + element.on('click', {a: null, elem: parent, actionFunc: actions['Delete'].action}, actionHandler); parent.parent().children().last().append(element); } @@ -199,7 +214,7 @@ $(document).ready(function () { FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () { return OC.imagePath('core', 'actions/download'); }, function (filename) { - var url = FileList.getDownloadUrl(filename); + var url = Files.getDownloadUrl(filename); if (url) { OC.redirect(url); } diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 503bf681139..506741eb6ea 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -8,17 +8,104 @@ * */ -/* global OC, t, n, FileList, FileActions, Files */ -/* global procesSelection, dragOptions, SVGSupport, replaceSVG */ -window.FileList={ +/* global OC, t, n, FileList, FileActions, Files, BreadCrumb */ +/* global procesSelection, dragOptions */ +window.FileList = { appName: t('files', 'Files'), + isEmpty: true, useUndo:true, - postProcessList: function() { - $('#fileList tr').each(function() { - //little hack to set unescape filenames in attribute - $(this).attr('data-file',decodeURIComponent($(this).attr('data-file'))); + $el: $('#filestable'), + $fileList: $('#fileList'), + breadcrumb: null, + initialized: false, + + /** + * Initialize the file list and its components + */ + initialize: function() { + var self = this; + if (this.initialized) { + return; + } + + // TODO: FileList should not know about global elements + this.$el = $('#filestable'); + this.$fileList = $('#fileList'); + + this.breadcrumb = new BreadCrumb({ + onClick: this._onClickBreadCrumb, + onDrop: this._onDropOnBreadCrumb, + getCrumbUrl: function(part, index) { + return self.linkTo(part.dir); + } + }); + + $('#controls').prepend(this.breadcrumb.$el); + + $(window).resize(function() { + // TODO: debounce this ? + var width = $(this).width(); + FileList.breadcrumb.resize(width, false); }); }, + + /** + * Event handler when clicking on a bread crumb + */ + _onClickBreadCrumb: function(e) { + var $el = $(e.target).closest('.crumb'), + $targetDir = $el.data('dir'); + + if ($targetDir !== undefined) { + e.preventDefault(); + FileList.changeDirectory($targetDir); + } + }, + + /** + * Event handler when dropping on a breadcrumb + */ + _onDropOnBreadCrumb: function( event, ui ) { + var target=$(this).data('dir'); + var dir = FileList.getCurrentDirectory(); + while(dir.substr(0,1) === '/') {//remove extra leading /'s + dir=dir.substr(1); + } + dir = '/' + dir; + if (dir.substr(-1,1) !== '/') { + dir = dir + '/'; + } + if (target === dir || target+'/' === dir) { + return; + } + var files = ui.helper.find('tr'); + $(files).each(function(i,row) { + var dir = $(row).data('dir'); + var file = $(row).data('filename'); + //slapdash selector, tracking down our original element that the clone budded off of. + var origin = $('tr[data-id=' + $(row).data('origin') + ']'); + var td = origin.children('td.filename'); + var oldBackgroundImage = td.css('background-image'); + td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); + $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) { + if (result) { + if (result.status === 'success') { + FileList.remove(file); + procesSelection(); + $('#notification').hide(); + } else { + $('#notification').hide(); + $('#notification').text(result.data.message); + $('#notification').fadeIn(); + } + } else { + OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); + } + td.css('background-image', oldBackgroundImage); + }); + }); + }, + /** * Sets a new page title */ @@ -36,64 +123,117 @@ window.FileList={ }, /** * Returns the tr element for a given file name + * @param fileName file name */ findFileEl: function(fileName){ // use filterAttr to avoid escaping issues - return $('#fileList tr').filterAttr('data-file', fileName); + return this.$fileList.find('tr').filterAttr('data-file', fileName); }, - update:function(fileListHtml) { - var $fileList = $('#fileList'); - $fileList.empty().html(fileListHtml); - FileList.updateEmptyContent(); - $fileList.find('tr').each(function () { - FileActions.display($(this).children('td.filename')); - }); - $fileList.trigger(jQuery.Event("fileActionsReady")); - FileList.postProcessList(); + /** + * Sets the files to be displayed in the list. + * This operation will rerender the list and update the summary. + * @param filesArray array of file data (map) + */ + setFiles:function(filesArray) { + // detach to make adding multiple rows faster + this.$fileList.detach(); + + this.$fileList.empty(); + + this.isEmpty = filesArray.length === 0; + for (var i = 0; i < filesArray.length; i++) { + this.add(filesArray[i], {updateSummary: false}); + } + + this.$el.find('thead').after(this.$fileList); + + this.updateEmptyContent(); + this.$fileList.trigger(jQuery.Event("fileActionsReady")); // "Files" might not be loaded in extending apps if (window.Files) { Files.setupDragAndDrop(); } - FileList.updateFileSummary(); + this.updateFileSummary(); procesSelection(); - $(window).scrollTop(0); - $fileList.trigger(jQuery.Event("updated")); + + this.$fileList.trigger(jQuery.Event("updated")); }, - createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) { - var td, simpleSize, basename, extension; + /** + * Creates a new table row element using the given file data. + * @param fileData map of file attributes + * @param options map of attribute "loading" whether the entry is currently loading + * @return new tr element (not appended to the table) + */ + _createRow: function(fileData, options) { + var td, simpleSize, basename, extension, sizeColor, + icon = OC.Util.replaceSVGIcon(fileData.icon), + name = fileData.name, + type = fileData.type || 'file', + mtime = parseInt(fileData.mtime, 10) || new Date().getTime(), + mime = fileData.mimetype, + linkUrl; + options = options || {}; + + if (type === 'dir') { + mime = mime || 'httpd/unix-directory'; + } //containing tr var tr = $('').attr({ + "data-id" : fileData.id, "data-type": type, - "data-size": size, + "data-size": fileData.size, "data-file": name, - "data-permissions": permissions + "data-mime": mime, + "data-mtime": mtime, + "data-etag": fileData.etag, + "data-permissions": fileData.permissions || this.getDirectoryPermissions() }); + + if (type === 'dir') { + // use default folder icon + icon = icon || OC.imagePath('core', 'filetypes/folder'); + } + else { + icon = icon || OC.imagePath('core', 'filetypes/file'); + } + // filename td td = $('').attr({ "class": "filename", - "style": 'background-image:url('+iconurl+'); background-size: 32px;' + "style": 'background-image:url(' + icon + '); background-size: 32px;' }); - var rand = Math.random().toString(16).slice(2); - td.append(''); + + // linkUrl + if (type === 'dir') { + linkUrl = FileList.linkTo(FileList.getCurrentDirectory() + '/' + name); + } + else { + linkUrl = Files.getDownloadUrl(name, FileList.getCurrentDirectory()); + } + td.append(''); var link_elem = $('').attr({ "class": "name", - "href": linktarget + "href": linkUrl }); - //split extension from filename for non dirs + + // from here work on the display name + name = fileData.displayName || name; + + // split extension from filename for non dirs if (type !== 'dir' && name.indexOf('.') !== -1) { - basename=name.substr(0,name.lastIndexOf('.')); - extension=name.substr(name.lastIndexOf('.')); + basename = name.substr(0, name.lastIndexOf('.')); + extension = name.substr(name.lastIndexOf('.')); } else { - basename=name; - extension=false; + basename = name; + extension = false; } var name_span=$('').addClass('nametext').text(basename); link_elem.append(name_span); if (extension) { name_span.append($('').addClass('extension').text(extension)); } - //dirs can show the number of uploaded files + // dirs can show the number of uploaded files if (type === 'dir') { link_elem.append($('').attr({ 'class': 'uploadtext', @@ -103,98 +243,122 @@ window.FileList={ td.append(link_elem); tr.append(td); - //size column - if (size !== t('files', 'Pending')) { - simpleSize = humanFileSize(size); + // size column + if (typeof(fileData.size) !== 'undefined' && fileData.size >= 0) { + simpleSize = humanFileSize(parseInt(fileData.size, 10)); + sizeColor = Math.round(160-Math.pow((fileData.size/(1024*1024)),2)); } else { - simpleSize=t('files', 'Pending'); + simpleSize = t('files', 'Pending'); } - var sizeColor = Math.round(160-Math.pow((size/(1024*1024)),2)); - var lastModifiedTime = Math.round(lastModified.getTime() / 1000); + var lastModifiedTime = Math.round(mtime / 1000); td = $('').attr({ "class": "filesize", - "style": 'color:rgb('+sizeColor+','+sizeColor+','+sizeColor+')' + "style": 'color:rgb(' + sizeColor + ',' + sizeColor + ',' + sizeColor + ')' }).text(simpleSize); tr.append(td); // date column - var modifiedColor = Math.round((Math.round((new Date()).getTime() / 1000)-lastModifiedTime)/60/60/24*5); + var modifiedColor = Math.round((Math.round((new Date()).getTime() / 1000) - mtime)/60/60/24*5); td = $('').attr({ "class": "date" }); td.append($('').attr({ "class": "modified", - "title": formatDate(lastModified), + "title": formatDate(mtime), "style": 'color:rgb('+modifiedColor+','+modifiedColor+','+modifiedColor+')' - }).text( relative_modified_date(lastModified.getTime() / 1000) )); + }).text( relative_modified_date(mtime / 1000) )); + tr.find('.filesize').text(simpleSize); tr.append(td); return tr; }, - addFile:function(name, size, lastModified, loading, hidden, param) { - var imgurl; + /** + * Adds an entry to the files table using the data from the given file data + * @param fileData map of file attributes + * @param options map of attributes: + * - "insert" true to insert in a sorted manner, false to append (default) + * - "updateSummary" true to update the summary after adding (default), false otherwise + * @return new tr element (not appended to the table) + */ + add: function(fileData, options) { + options = options || {}; + var type = fileData.type || 'file', + mime = fileData.mimetype, + permissions = parseInt(fileData.permissions, 10) || 0; - if (!param) { - param = {}; + if (type === 'dir') { + mime = mime || 'httpd/unix-directory'; } + var tr = this._createRow( + fileData, + options + ); + var filenameTd = tr.find('td.filename'); - var download_url = null; - if (!param.download_url) { - download_url = OC.generateUrl( - 'apps/files/download{file}', - { file: $('#dir').val()+'/'+name }); - } else { - download_url = param.download_url; + // sorted insert is expensive, so needs to be explicitly + // requested + if (options.insert) { + this.insertElement(fileData.name, type, tr); } + else { + this.$fileList.append(tr); + } + FileList.isEmpty = false; - if (loading) { - imgurl = OC.imagePath('core', 'loading.gif'); - } else { - imgurl = OC.imagePath('core', 'filetypes/file'); - } - var tr = this.createRow( - 'file', - name, - imgurl, - download_url, - size, - lastModified, - $('#permissions').val() - ); + // TODO: move dragging to FileActions ? + // enable drag only for deletable files + if (permissions & OC.PERMISSION_DELETE) { + filenameTd.draggable(dragOptions); + } + // allow dropping on folders + if (fileData.type === 'dir') { + filenameTd.droppable(folderDropOptions); + } - FileList.insertElement(name, 'file', tr); - if (loading) { - tr.data('loading', true); - } else { - tr.find('td.filename').draggable(dragOptions); + if (options.hidden) { + tr.addClass('hidden'); } - if (hidden) { - tr.hide(); + + // display actions + FileActions.display(filenameTd, false); + + if (fileData.isPreviewAvailable) { + // lazy load / newly inserted td ? + if (!fileData.icon) { + Files.lazyLoadPreview(getPathForPreview(fileData.name), mime, function(url) { + filenameTd.css('background-image', 'url(' + url + ')'); + }, null, null, fileData.etag); + } + else { + // set the preview URL directly + var urlSpec = { + file: FileList.getCurrentDirectory() + '/' + fileData.name, + c: fileData.etag + }; + var previewUrl = Files.generatePreviewUrl(urlSpec); + previewUrl = previewUrl.replace('(', '%28').replace(')', '%29'); + filenameTd.css('background-image', 'url(' + previewUrl + ')'); + } } - return tr; - }, - addDir:function(name, size, lastModified, hidden) { - - var tr = this.createRow( - 'dir', - name, - OC.imagePath('core', 'filetypes/folder'), - OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent($('#dir').val()+'/'+name).replace(/%2F/g, '/'), - size, - lastModified, - $('#permissions').val() - ); - FileList.insertElement(name, 'dir', tr); - var td = tr.find('td.filename'); - td.draggable(dragOptions); - td.droppable(folderDropOptions); - if (hidden) { - tr.hide(); + // defaults to true if not defined + if (typeof(options.updateSummary) === 'undefined' || !!options.updateSummary) { + this.updateFileSummary(); + this.updateEmptyContent(); } - FileActions.display(tr.find('td.filename'), true); return tr; }, + /** + * Returns the current directory + * @return current directory + */ getCurrentDirectory: function(){ return $('#dir').val() || '/'; }, + /** + * Returns the directory permissions + * @return permission value as integer + */ + getDirectoryPermissions: function() { + return parseInt($('#permissions').val(), 10); + }, /** * @brief Changes the current directory and reload the file list. * @param targetDir target directory (non URL encoded) @@ -209,7 +373,7 @@ window.FileList={ if (!force && currentDir === targetDir) { return; } - FileList.setCurrentDir(targetDir, changeUrl); + FileList._setCurrentDir(targetDir, changeUrl); $('#fileList').trigger( jQuery.Event('changeDirectory', { dir: targetDir, @@ -221,7 +385,13 @@ window.FileList={ linkTo: function(dir) { return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); }, - setCurrentDir: function(targetDir, changeUrl) { + + /** + * Sets the current directory name and updates the breadcrumb. + * @param targetDir directory to display + * @param changeUrl true to also update the URL, false otherwise (default) + */ + _setCurrentDir: function(targetDir, changeUrl) { var url, baseDir = OC.basename(targetDir); @@ -243,6 +413,7 @@ window.FileList={ window.location.hash = '?dir='+ encodeURIComponent(targetDir).replace(/%2F/g, '/'); } } + this.breadcrumb.setDirectory(this.getCurrentDirectory()); }, /** * @brief Reloads the file list using ajax call @@ -253,10 +424,9 @@ window.FileList={ FileList._reloadCall.abort(); } FileList._reloadCall = $.ajax({ - url: OC.filePath('files','ajax','list.php'), + url: Files.getAjaxUrl('list'), data: { - dir : $('#dir').val(), - breadcrumb: true + dir : $('#dir').val() }, error: function(result) { FileList.reloadCallback(result); @@ -269,8 +439,8 @@ window.FileList={ reloadCallback: function(result) { var $controls = $('#controls'); - delete FileList._reloadCall; - FileList.hideMask(); + delete this._reloadCall; + this.hideMask(); if (!result || result.status === 'error') { OC.Notification.show(result.data.message); @@ -279,7 +449,11 @@ window.FileList={ if (result.status === 404) { // go back home - FileList.changeDirectory('/'); + this.changeDirectory('/'); + return; + } + // aborted ? + if (result.status === 0){ return; } @@ -288,24 +462,10 @@ window.FileList={ Files.updateStorageStatistics(true); if (result.data.permissions) { - FileList.setDirectoryPermissions(result.data.permissions); + this.setDirectoryPermissions(result.data.permissions); } - if (typeof(result.data.breadcrumb) !== 'undefined') { - $controls.find('.crumb').remove(); - $controls.prepend(result.data.breadcrumb); - - var width = $(window).width(); - Files.initBreadCrumbs(); - Files.resizeBreadcrumbs(width, true); - - // in case svg is not supported by the browser we need to execute the fallback mechanism - if (!SVGSupport()) { - replaceSVG(); - } - } - - FileList.update(result.data.files); + this.setFiles(result.data.files); }, setDirectoryPermissions: function(permissions) { var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; @@ -322,10 +482,14 @@ window.FileList={ $('.actions,#file_action_panel').toggleClass('hidden', !show); if (show){ // make sure to display according to permissions - var permissions = $('#permissions').val(); + var permissions = this.getDirectoryPermissions(); var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; $('.creatable').toggleClass('hidden', !isCreatable); $('.notCreatable').toggleClass('hidden', isCreatable); + // remove old style breadcrumbs (some apps might create them) + $('#controls .crumb').remove(); + // refresh breadcrumbs in case it was replaced by an app + this.breadcrumb.render(); } else{ $('.creatable, .notCreatable').addClass('hidden'); @@ -341,22 +505,32 @@ window.FileList={ this.showActions(!show); $('#filestable').toggleClass('hidden', show); }, - remove:function(name){ + /** + * Removes a file entry from the list + * @param name name of the file to remove + * @param options optional options as map: + * "updateSummary": true to update the summary (default), false otherwise + */ + remove:function(name, options){ + options = options || {}; var fileEl = FileList.findFileEl(name); if (fileEl.data('permissions') & OC.PERMISSION_DELETE) { // file is only draggable when delete permissions are set fileEl.find('td.filename').draggable('destroy'); } fileEl.remove(); - FileList.updateFileSummary(); - if ( ! $('tr[data-file]').exists() ) { - $('#emptycontent').removeClass('hidden'); - $('#filescontent th').addClass('hidden'); + // TODO: improve performance on batch update + FileList.isEmpty = !this.$fileList.find('tr:not(.summary)').length; + if (typeof(options.updateSummary) === 'undefined' || !!options.updateSummary) { + FileList.updateEmptyContent(); + FileList.updateFileSummary(); } + return fileEl; }, insertElement:function(name, type, element) { - //find the correct spot to insert the file or folder - var pos, fileElements=$('tr[data-file][data-type="'+type+'"]:visible'); + // find the correct spot to insert the file or folder + var pos, + fileElements = this.$fileList.find('tr[data-file][data-type="'+type+'"]:not(.hidden)'); if (name.localeCompare($(fileElements[0]).attr('data-file')) < 0) { pos = -1; } else if (name.localeCompare($(fileElements[fileElements.length-1]).attr('data-file')) > 0) { @@ -376,35 +550,18 @@ window.FileList={ } else { $(fileElements[pos]).after(element); } - } else if (type === 'dir' && $('tr[data-file]').exists()) { - $('tr[data-file]').first().before(element); - } else if (type === 'file' && $('tr[data-file]').exists()) { - $('tr[data-file]').last().before(element); + } else if (type === 'dir' && !FileList.isEmpty) { + this.$fileList.find('tr[data-file]:first').before(element); + } else if (type === 'file' && !FileList.isEmpty) { + this.$fileList.find('tr[data-file]:last').before(element); } else { - $('#fileList').append(element); + this.$fileList.append(element); } - $('#emptycontent').addClass('hidden'); - $('#filestable th').removeClass('hidden'); + FileList.isEmpty = false; + FileList.updateEmptyContent(); FileList.updateFileSummary(); }, - loadingDone:function(name, id) { - var mime, tr = FileList.findFileEl(name); - tr.data('loading', false); - mime = tr.data('mime'); - tr.attr('data-mime', mime); - if (id) { - tr.attr('data-id', id); - } - var path = getPathForPreview(name); - Files.lazyLoadPreview(path, mime, function(previewpath) { - tr.find('td.filename').attr('style','background-image:url('+previewpath+')'); - }, null, null, tr.attr('data-etag')); - tr.find('td.filename').draggable(dragOptions); - }, - isLoading:function(file) { - return FileList.findFileEl(file).data('loading'); - }, - rename:function(oldname) { + rename: function(oldname) { var tr, td, input, form; tr = FileList.findFileEl(oldname); tr.data('renaming',true); @@ -438,6 +595,7 @@ window.FileList={ event.preventDefault(); try { var newname = input.val(); + var directory = FileList.getCurrentDirectory(); if (newname !== oldname) { checkInput(); // save background image, because it's replaced by a spinner while async request @@ -480,12 +638,16 @@ window.FileList={ tr.attr('data-mime', fileInfo.mime); tr.attr('data-etag', fileInfo.etag); if (fileInfo.isPreviewAvailable) { - Files.lazyLoadPreview(fileInfo.directory + '/' + fileInfo.name, result.data.mime, function(previewpath) { + Files.lazyLoadPreview(directory + '/' + fileInfo.name, result.data.mime, function(previewpath) { tr.find('td.filename').attr('style','background-image:url('+previewpath+')'); }, null, null, result.data.etag); } else { - tr.find('td.filename').removeClass('preview').attr('style','background-image:url('+fileInfo.icon+')'); + tr.find('td.filename') + .removeClass('preview') + .attr('style','background-image:url(' + + OC.Util.replaceSVGIcon(fileInfo.icon) + + ')'); } } // reinsert row @@ -554,58 +716,12 @@ window.FileList={ inList:function(file) { return FileList.findFileEl(file).length; }, - replace:function(oldName, newName, isNewFile) { - // Finish any existing actions - var oldFileEl = FileList.findFileEl(oldName); - var newFileEl = FileList.findFileEl(newName); - oldFileEl.hide(); - newFileEl.hide(); - var tr = oldFileEl.clone(); - tr.attr('data-replace', 'true'); - tr.attr('data-file', newName); - var td = tr.children('td.filename'); - td.children('a.name .span').text(newName); - var path = td.children('a.name').attr('href'); - td.children('a.name').attr('href', path.replace(encodeURIComponent(oldName), encodeURIComponent(newName))); - var basename = newName; - if (newName.indexOf('.') > 0) { - basename = newName.substr(0, newName.lastIndexOf('.')); - } - td.children('a.name').empty(); - var span = $(''); - span.text(basename); - td.children('a.name').append(span); - if (newName.indexOf('.') > 0) { - span.append($(''+newName.substr(newName.lastIndexOf('.'))+'')); - } - FileList.insertElement(newName, tr.data('type'), tr); - tr.show(); - FileList.replaceCanceled = false; - FileList.replaceOldName = oldName; - FileList.replaceNewName = newName; - FileList.replaceIsNewFile = isNewFile; - FileList.lastAction = function() { - FileList.finishReplace(); - }; - if (!isNewFile) { - OC.Notification.showHtml(t('files', 'replaced {new_name} with {old_name}', {new_name: newName}, {old_name: oldName})+''+t('files', 'undo')+''); - } - }, - finishReplace:function() { - if (!FileList.replaceCanceled && FileList.replaceOldName && FileList.replaceNewName) { - $.ajax({url: OC.filePath('files', 'ajax', 'rename.php'), async: false, data: { dir: $('#dir').val(), newname: FileList.replaceNewName, file: FileList.replaceOldName }, success: function(result) { - if (result && result.status === 'success') { - $('tr[data-replace="true"').removeAttr('data-replace'); - } else { - OC.dialogs.alert(result.data.message, 'Error moving file'); - } - FileList.replaceCanceled = true; - FileList.replaceOldName = null; - FileList.replaceNewName = null; - FileList.lastAction = null; - }}); - } - }, + /** + * Delete the given files from the given dir + * @param files file names list (without path) + * @param dir directory in which to delete the files, defaults to the current + * directory + */ do_delete:function(files, dir) { var params; if (files && files.substr) { @@ -622,7 +738,7 @@ window.FileList={ FileList.lastAction(); } - var params = { + params = { dir: dir || FileList.getCurrentDirectory() }; if (files) { @@ -643,10 +759,9 @@ window.FileList={ } else { $.each(files,function(index,file) { - var files = FileList.findFileEl(file); - files.remove(); - files.find('input[type="checkbox"]').removeAttr('checked'); - files.removeClass('selected'); + var fileEl = FileList.remove(file, {updateSummary: false}); + fileEl.find('input[type="checkbox"]').prop('checked', false); + fileEl.removeClass('selected'); }); } procesSelection(); @@ -680,7 +795,7 @@ window.FileList={ }); }, createFileSummary: function() { - if( $('#fileList tr').exists() ) { + if ( !FileList.isEmpty ) { var summary = this._calculateFileSummary(); // Get translations @@ -702,7 +817,7 @@ window.FileList={ } var $summary = $(''+info+''+fileSize+''); - $('#fileList').append($summary); + this.$fileList.append($summary); var $dirInfo = $summary.find('.dirinfo'); var $fileInfo = $summary.find('.fileinfo'); @@ -710,12 +825,12 @@ window.FileList={ // Show only what's necessary, e.g.: no files: don't show "0 files" if (summary.totalDirs === 0) { - $dirInfo.hide(); - $connector.hide(); + $dirInfo.addClass('hidden'); + $connector.addClass('hidden'); } if (summary.totalFiles === 0) { - $fileInfo.hide(); - $connector.hide(); + $fileInfo.addClass('hidden'); + $connector.addClass('hidden'); } } }, @@ -740,10 +855,13 @@ window.FileList={ return result; }, updateFileSummary: function() { - var $summary = $('.summary'); + var $summary = this.$el.find('.summary'); + + // always make it the last element + this.$fileList.append($summary.detach()); // Check if we should remove the summary to show "Upload something" - if ($('#fileList tr').length === 1 && $summary.length === 1) { + if (this.isEmpty && $summary.length === 1) { $summary.remove(); } // If there's no summary create one (createFileSummary checks if there's data) @@ -751,7 +869,7 @@ window.FileList={ FileList.createFileSummary(); } // There's a summary and data -> Update the summary - else if ($('#fileList tr').length > 1 && $summary.length === 1) { + else if (!this.isEmpty && $summary.length === 1) { var fileSummary = this._calculateFileSummary(); var $dirInfo = $('.summary .dirinfo'); var $fileInfo = $('.summary .fileinfo'); @@ -764,19 +882,19 @@ window.FileList={ // Show only what's necessary (may be hidden) if (fileSummary.totalDirs === 0) { - $dirInfo.hide(); - $connector.hide(); + $dirInfo.addClass('hidden'); + $connector.addClass('hidden'); } else { - $dirInfo.show(); + $dirInfo.removeClass('hidden'); } if (fileSummary.totalFiles === 0) { - $fileInfo.hide(); - $connector.hide(); + $fileInfo.addClass('hidden'); + $connector.addClass('hidden'); } else { - $fileInfo.show(); + $fileInfo.removeClass('hidden'); } if (fileSummary.totalDirs > 0 && fileSummary.totalFiles > 0) { - $connector.show(); + $connector.removeClass('hidden'); } } }, @@ -784,10 +902,14 @@ window.FileList={ var $fileList = $('#fileList'); var permissions = $('#permissions').val(); var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; - var exists = $fileList.find('tr:first').exists(); - $('#emptycontent').toggleClass('hidden', !isCreatable || exists); - $('#filestable th').toggleClass('hidden', !exists); + $('#emptycontent').toggleClass('hidden', !isCreatable || !FileList.isEmpty); + $('#filestable thead th').toggleClass('hidden', FileList.isEmpty); }, + /** + * Shows the loading mask. + * + * @see #hideMask + */ showMask: function() { // in case one was shown before var $mask = $('#content .mask'); @@ -795,23 +917,23 @@ window.FileList={ return; } + this.$el.addClass('hidden'); + $mask = $('
'); $mask.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); $mask.css('background-repeat', 'no-repeat'); $('#content').append($mask); - // block UI, but only make visible in case loading takes longer - FileList._maskTimeout = window.setTimeout(function() { - // reset opacity - $mask.removeClass('transparent'); - }, 250); + $mask.removeClass('transparent'); }, + /** + * Hide the loading mask. + * @see #showMask + */ hideMask: function() { - var $mask = $('#content .mask').remove(); - if (FileList._maskTimeout) { - window.clearTimeout(FileList._maskTimeout); - } + $('#content .mask').remove(); + this.$el.removeClass('hidden'); }, scrollTo:function(file) { //scroll to and highlight preselected file @@ -850,29 +972,11 @@ window.FileList={ */ isAllSelected: function() { return $('#select_all').prop('checked'); - }, - - /** - * Returns the download URL of the given file - * @param filename file name of the file - * @param dir optional directory in which the file name is, defaults to the current directory - */ - getDownloadUrl: function(filename, dir) { - var files = filename; - if ($.isArray(filename)) { - files = JSON.stringify(filename); - } - var params = { - dir: dir || FileList.getCurrentDirectory(), - files: files - }; - return OC.filePath('files', 'ajax', 'download.php') + '?' + OC.buildQueryString(params); } }; $(document).ready(function() { - var baseDir, - isPublic = !!$('#isPublic').val(); + FileList.initialize(); // handle upload events var file_upload_start = $('#file_upload_start'); @@ -907,8 +1011,13 @@ $(document).ready(function() { {name: 'requesttoken', value: oc_requesttoken} ]; }; + } else { + // cancel uploads to current dir if no permission + var isCreatable = (FileList.getDirectoryPermissions() & OC.PERMISSION_CREATE) !== 0; + if (!isCreatable) { + return false; + } } - }); file_upload_start.on('fileuploadadd', function(e, data) { OC.Upload.log('filelist handle fileuploadadd', e, data); @@ -993,31 +1102,11 @@ $(document).ready(function() { if (data.files[0].size>=0) { size=data.files[0].size; } - var date=new Date(); - var param = {}; - if ($('#publicUploadRequestToken').exists()) { - param.download_url = document.location.href + '&download&path=/' + $('#dir').val() + '/' + file.name; - } //should the file exist in the list remove it FileList.remove(file.name); // create new file context - data.context = FileList.addFile(file.name, file.size, date, false, false, param); - - // update file data - data.context.attr('data-mime',file.mime).attr('data-id',file.id).attr('data-etag', file.etag); - - var permissions = data.context.data('permissions'); - if (permissions !== file.permissions) { - data.context.attr('data-permissions', file.permissions); - data.context.data('permissions', file.permissions); - } - FileActions.display(data.context.find('td.filename'), true); - - var path = getPathForPreview(file.name); - Files.lazyLoadPreview(path, file.mime, function(previewpath) { - data.context.find('td.filename').attr('style','background-image:url('+previewpath+')'); - }, null, null, file.etag); + data.context = FileList.add(file, {insert: true}); } } }); @@ -1049,31 +1138,6 @@ $(document).ready(function() { }); $('#notification').hide(); - $('#notification').on('click', '.undo', function() { - if (FileList.deleteFiles) { - $.each(FileList.deleteFiles,function(index,file) { - FileList.findFileEl(file).show(); - }); - FileList.deleteCanceled=true; - FileList.deleteFiles=null; - } else if (FileList.replaceOldName && FileList.replaceNewName) { - if (FileList.replaceIsNewFile) { - // Delete the new uploaded file - FileList.deleteCanceled = false; - FileList.deleteFiles = [FileList.replaceOldName]; - } else { - FileList.findFileEl(FileList.replaceOldName).show(); - } - $('tr[data-replace="true"').remove(); - FileList.findFileEl(FileList.replaceNewName).show(); - FileList.replaceCanceled = true; - FileList.replaceOldName = null; - FileList.replaceNewName = null; - FileList.replaceIsNewFile = null; - } - FileList.lastAction = null; - OC.Notification.hide(); - }); $('#notification:first-child').on('click', '.replace', function() { OC.Notification.hide(function() { FileList.replace($('#notification > span').attr('data-oldName'), $('#notification > span').attr('data-newName'), $('#notification > span').attr('data-isNewFile')); @@ -1081,7 +1145,7 @@ $(document).ready(function() { }); $('#notification:first-child').on('click', '.suggest', function() { var file = $('#notification > span').attr('data-oldName'); - FileList.findFileEl(file).show(); + FileList.findFileEl(file).removeClass('hidden'); OC.Notification.hide(); }); $('#notification:first-child').on('click', '.cancel', function() { @@ -1130,34 +1194,32 @@ $(document).ready(function() { } // disable ajax/history API for public app (TODO: until it gets ported) - if (!isPublic) { - // fallback to hashchange when no history support - if (!window.history.pushState) { - $(window).on('hashchange', function() { - FileList.changeDirectory(parseCurrentDirFromUrl(), false); - }); + // fallback to hashchange when no history support + if (!window.history.pushState) { + $(window).on('hashchange', function() { + FileList.changeDirectory(parseCurrentDirFromUrl(), false); + }); + } + window.onpopstate = function(e) { + var targetDir; + if (e.state && e.state.dir) { + targetDir = e.state.dir; } - window.onpopstate = function(e) { - var targetDir; - if (e.state && e.state.dir) { - targetDir = e.state.dir; - } - else{ - // read from URL - targetDir = parseCurrentDirFromUrl(); - } - if (targetDir) { - FileList.changeDirectory(targetDir, false); - } - }; - - if (parseInt($('#ajaxLoad').val(), 10) === 1) { - // need to initially switch the dir to the one from the hash (IE8) - FileList.changeDirectory(parseCurrentDirFromUrl(), false, true); + else{ + // read from URL + targetDir = parseCurrentDirFromUrl(); + } + if (targetDir) { + FileList.changeDirectory(targetDir, false); } + }; - FileList.setCurrentDir(parseCurrentDirFromUrl(), false); - } + var dir = parseCurrentDirFromUrl(); + // trigger ajax load, deferred to let sub-apps do their overrides first + setTimeout(function() { + FileList.changeDirectory(dir, false, true); + }, 0); FileList.createFileSummary(); }); + diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 1186a72a44f..ac10191618b 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -131,15 +131,15 @@ var Files = { var encryptedFiles = $('#encryptedFiles').val(); var initStatus = $('#encryptionInitStatus').val(); if (initStatus === '0') { // enc not initialized, but should be - OC.Notification.show(t('files_encryption', 'Encryption App is enabled but your keys are not initialized, please log-out and log-in again')); + OC.Notification.show(t('files', 'Encryption App is enabled but your keys are not initialized, please log-out and log-in again')); return; } if (initStatus === '1') { // encryption tried to init but failed - OC.Notification.showHtml(t('files_encryption', 'Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files.')); + OC.Notification.showHtml(t('files', 'Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files.')); return; } if (encryptedFiles === '1') { - OC.Notification.show(t('files_encryption', 'Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files.')); + OC.Notification.show(t('files', 'Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files.')); return; } }, @@ -161,77 +161,33 @@ var Files = { }); }, - lastWidth: 0, - - initBreadCrumbs: function () { - var $controls = $('#controls'); - - Files.lastWidth = 0; - Files.breadcrumbs = []; - - // initialize with some extra space - Files.breadcrumbsWidth = 64; - if ( document.getElementById("navigation") ) { - Files.breadcrumbsWidth += $('#navigation').get(0).offsetWidth; + /** + * Returns the download URL of the given file(s) + * @param filename string or array of file names to download + * @param dir optional directory in which the file name is, defaults to the current directory + */ + getDownloadUrl: function(filename, dir) { + if ($.isArray(filename)) { + filename = JSON.stringify(filename); } - Files.hiddenBreadcrumbs = 0; - - $.each($('.crumb'), function(index, breadcrumb) { - Files.breadcrumbs[index] = breadcrumb; - Files.breadcrumbsWidth += $(breadcrumb).get(0).offsetWidth; - }); - - $.each($('#controls .actions>div'), function(index, action) { - Files.breadcrumbsWidth += $(action).get(0).offsetWidth; - }); - - // event handlers for breadcrumb items - $controls.find('.crumb a').on('click', onClickBreadcrumb); - - // setup drag and drop - $controls.find('.crumb:not(.last)').droppable(crumbDropOptions); + var params = { + dir: dir || FileList.getCurrentDirectory(), + files: filename + }; + return this.getAjaxUrl('download', params); }, - resizeBreadcrumbs: function (width, firstRun) { - if (width !== Files.lastWidth) { - if ((width < Files.lastWidth || firstRun) && width < Files.breadcrumbsWidth) { - if (Files.hiddenBreadcrumbs === 0) { - Files.breadcrumbsWidth -= $(Files.breadcrumbs[1]).get(0).offsetWidth; - $(Files.breadcrumbs[1]).find('a').hide(); - $(Files.breadcrumbs[1]).append('...'); - Files.breadcrumbsWidth += $(Files.breadcrumbs[1]).get(0).offsetWidth; - Files.hiddenBreadcrumbs = 2; - } - var i = Files.hiddenBreadcrumbs; - while (width < Files.breadcrumbsWidth && i > 1 && i < Files.breadcrumbs.length - 1) { - Files.breadcrumbsWidth -= $(Files.breadcrumbs[i]).get(0).offsetWidth; - $(Files.breadcrumbs[i]).hide(); - Files.hiddenBreadcrumbs = i; - i++; - } - } else if (width > Files.lastWidth && Files.hiddenBreadcrumbs > 0) { - var i = Files.hiddenBreadcrumbs; - while (width > Files.breadcrumbsWidth && i > 0) { - if (Files.hiddenBreadcrumbs === 1) { - Files.breadcrumbsWidth -= $(Files.breadcrumbs[1]).get(0).offsetWidth; - $(Files.breadcrumbs[1]).find('span').remove(); - $(Files.breadcrumbs[1]).find('a').show(); - Files.breadcrumbsWidth += $(Files.breadcrumbs[1]).get(0).offsetWidth; - } else { - $(Files.breadcrumbs[i]).show(); - Files.breadcrumbsWidth += $(Files.breadcrumbs[i]).get(0).offsetWidth; - if (Files.breadcrumbsWidth > width) { - Files.breadcrumbsWidth -= $(Files.breadcrumbs[i]).get(0).offsetWidth; - $(Files.breadcrumbs[i]).hide(); - break; - } - } - i--; - Files.hiddenBreadcrumbs = i; - } - } - Files.lastWidth = width; + /** + * Returns the ajax URL for a given action + * @param action action string + * @param params optional params map + */ + getAjaxUrl: function(action, params) { + var q = ''; + if (params) { + q = '?' + OC.buildQueryString(params); } + return OC.filePath('files', 'ajax', action + '.php') + q; } }; $(document).ready(function() { @@ -242,14 +198,10 @@ $(document).ready(function() { Files.displayEncryptionWarning(); Files.bindKeyboardShortcuts(document, jQuery); - FileList.postProcessList(); Files.setupDragAndDrop(); $('#file_action_panel').attr('activeAction', false); - // allow dropping on the "files" app icon - $('ul#apps li:first-child').data('dir','').droppable(crumbDropOptions); - // Triggers invisible file input $('#upload a').on('click', function() { $(this).parent().children('#file_upload_start').trigger('click'); @@ -308,7 +260,7 @@ $(document).ready(function() { var filename=$(this).parent().parent().attr('data-file'); var tr = FileList.findFileEl(filename); var renaming=tr.data('renaming'); - if (!renaming && !FileList.isLoading(filename)) { + if (!renaming) { FileActions.currentFile = $(this).parent(); var mime=FileActions.getCurrentMimeType(); var type=FileActions.getCurrentType(); @@ -374,15 +326,15 @@ $(document).ready(function() { dir = OC.dirname(dir) || '/'; } else { - files = getSelectedFilesTrash('name'); + files = Files.getSelectedFiles('name'); } OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.')); - OC.redirect(FileList.getDownloadUrl(files, dir)); + OC.redirect(Files.getDownloadUrl(files, dir)); return false; }); $('.delete-selected').click(function(event) { - var files=getSelectedFilesTrash('name'); + var files = Files.getSelectedFiles('name'); event.preventDefault(); if (FileList.isAllSelected()) { files = null; @@ -400,16 +352,6 @@ $(document).ready(function() { //do a background scan if needed scanFiles(); - Files.initBreadCrumbs(); - - $(window).resize(function() { - var width = $(this).width(); - Files.resizeBreadcrumbs(width, false); - }); - - var width = $(this).width(); - Files.resizeBreadcrumbs(width, true); - // display storage warnings setTimeout(Files.displayStorageWarnings, 100); OC.Notification.setDefault(Files.displayStorageWarnings); @@ -500,7 +442,7 @@ var createDragShadow = function(event) { $(event.target).parents('tr').find('td input:first').prop('checked',true); } - var selectedFiles = getSelectedFilesTrash(); + var selectedFiles = Files.getSelectedFiles(); if (!isDragSelected && selectedFiles.length === 1) { //revert the selection @@ -616,52 +558,8 @@ var folderDropOptions={ tolerance: 'pointer' }; -var crumbDropOptions={ - drop: function( event, ui ) { - var target=$(this).data('dir'); - var dir = $('#dir').val(); - while(dir.substr(0,1) === '/') {//remove extra leading /'s - dir=dir.substr(1); - } - dir = '/' + dir; - if (dir.substr(-1,1) !== '/') { - dir = dir + '/'; - } - if (target === dir || target+'/' === dir) { - return; - } - var files = ui.helper.find('tr'); - $(files).each(function(i,row) { - var dir = $(row).data('dir'); - var file = $(row).data('filename'); - //slapdash selector, tracking down our original element that the clone budded off of. - var origin = $('tr[data-id=' + $(row).data('origin') + ']'); - var td = origin.children('td.filename'); - var oldBackgroundImage = td.css('background-image'); - td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); - $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) { - if (result) { - if (result.status === 'success') { - FileList.remove(file); - procesSelection(); - $('#notification').hide(); - } else { - $('#notification').hide(); - $('#notification').text(result.data.message); - $('#notification').fadeIn(); - } - } else { - OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); - } - td.css('background-image', oldBackgroundImage); - }); - }); - }, - tolerance: 'pointer' -}; - function procesSelection() { - var selected = getSelectedFilesTrash(); + var selected = Files.getSelectedFiles(); var selectedFiles = selected.filter(function(el) { return el.type==='file'; }); @@ -711,7 +609,7 @@ function procesSelection() { * if property is set, an array with that property for each file is returnd * if it's ommited an array of objects with all properties is returned */ -function getSelectedFilesTrash(property) { +Files.getSelectedFiles = function(property) { var elements=$('td.filename input:checkbox:checked').parent().parent(); var files=[]; elements.each(function(i,element) { @@ -737,7 +635,7 @@ Files.getMimeIcon = function(mime, ready) { ready(Files.getMimeIcon.cache[mime]); } else { $.get( OC.filePath('files','ajax','mimeicon.php'), {mime: mime}, function(path) { - if(SVGSupport()){ + if(OC.Util.hasSVGSupport()){ path = path.substr(0, path.length-4) + '.svg'; } Files.getMimeIcon.cache[mime]=path; @@ -752,25 +650,32 @@ function getPathForPreview(name) { return path; } +/** + * Generates a preview URL based on the URL space. + * @param urlSpec map with {x: width, y: height, file: file path} + * @return preview URL + */ +Files.generatePreviewUrl = function(urlSpec) { + urlSpec = urlSpec || {}; + if (!urlSpec.x) { + urlSpec.x = $('#filestable').data('preview-x'); + } + if (!urlSpec.y) { + urlSpec.y = $('#filestable').data('preview-y'); + } + urlSpec.y *= window.devicePixelRatio; + urlSpec.x *= window.devicePixelRatio; + urlSpec.forceIcon = 0; + return OC.generateUrl('/core/preview.png?') + $.param(urlSpec); +} + Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { // get mime icon url Files.getMimeIcon(mime, function(iconURL) { - var urlSpec = {}; - var previewURL; + var previewURL, + urlSpec = {}; ready(iconURL); // set mimeicon URL - // now try getting a preview thumbnail URL - if ( ! width ) { - width = $('#filestable').data('preview-x'); - } - if ( ! height ) { - height = $('#filestable').data('preview-y'); - } - // note: the order of arguments must match the one - // from the server's template so that the browser - // knows it's the same file for caching - urlSpec.x = width; - urlSpec.y = height; urlSpec.file = Files.fixPath(path); if (etag){ @@ -781,15 +686,9 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { console.warn('Files.lazyLoadPreview(): missing etag argument'); } - if ( $('#isPublic').length ) { - urlSpec.t = $('#dirToken').val(); - previewURL = OC.generateUrl('/publicpreview.png?') + $.param(urlSpec); - } else { - previewURL = OC.generateUrl('/core/preview.png?') + $.param(urlSpec); - } + previewURL = Files.generatePreviewUrl(urlSpec); previewURL = previewURL.replace('(', '%28'); previewURL = previewURL.replace(')', '%29'); - previewURL += '&forceIcon=0'; // preload image to prevent delay // this will make the browser cache the image @@ -799,7 +698,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { if (img.width > 5) { ready(previewURL); } - } + }; img.src = previewURL; }); }; @@ -838,14 +737,8 @@ function checkTrashStatus() { }); } -function onClickBreadcrumb(e) { - var $el = $(e.target).closest('.crumb'), - $targetDir = $el.data('dir'), - isPublic = !!$('#isPublic').val(); - - if ($targetDir !== undefined && !isPublic) { - e.preventDefault(); - FileList.changeDirectory(decodeURIComponent($targetDir)); - } +// override core's fileDownloadPath (legacy) +function fileDownloadPath(dir, file) { + return Files.getDownloadUrl(file, dir); } diff --git a/apps/files/l10n/ar.php b/apps/files/l10n/ar.php index 147d77d4cb0..e7c081b1c47 100644 --- a/apps/files/l10n/ar.php +++ b/apps/files/l10n/ar.php @@ -27,9 +27,9 @@ $TRANSLATIONS = array( "Share" => "شارك", "Delete permanently" => "حذف بشكل دائم", "Rename" => "إعادة تسميه", +"Error moving file" => "حدث خطأ أثناء نقل الملف", +"Error" => "خطأ", "Pending" => "قيد الانتظار", -"replaced {new_name} with {old_name}" => "استبدل {new_name} بـ {old_name}", -"undo" => "تراجع", "_%n folder_::_%n folders_" => array("لا يوجد مجلدات %n","1 مجلد %n","2 مجلد %n","عدد قليل من مجلدات %n","عدد كبير من مجلدات %n","مجلدات %n"), "_%n file_::_%n files_" => array("لا يوجد ملفات %n","ملف %n","2 ملف %n","قليل من ملفات %n","الكثير من ملفات %n"," ملفات %n"), "{dirs} and {files}" => "{dirs} و {files}", @@ -40,8 +40,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "المفتاح الخاص بتشفير التطبيقات غير صالح. يرجى تحديث كلمة السر الخاصة بالمفتاح الخاص من الإعدادت الشخصية حتى تتمكن من الوصول للملفات المشفرة.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "تم تعطيل التشفير لكن ملفاتك لا تزال مشفرة. فضلا اذهب إلى الإعدادات الشخصية لإزالة التشفير عن ملفاتك.", "Your download is being prepared. This might take some time if the files are big." => "جاري تجهيز عملية التحميل. قد تستغرق بعض الوقت اذا كان حجم الملفات كبير.", -"Error moving file" => "حدث خطأ أثناء نقل الملف", -"Error" => "خطأ", "Name" => "اسم", "Size" => "حجم", "Modified" => "معدل", diff --git a/apps/files/l10n/ast.php b/apps/files/l10n/ast.php new file mode 100644 index 00000000000..93ae47b25c5 --- /dev/null +++ b/apps/files/l10n/ast.php @@ -0,0 +1,29 @@ + "El nome de ficheru nun pue quedar baleru.", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nome inválidu, los caráuteres \"\\\", \"/\", \"<\", \">\", \":\", \"\", \"|\" \"?\" y \"*\" nun tán permitíos.", +"No file was uploaded. Unknown error" => "Nun se xubió dengún ficheru. Fallu desconocíu", +"There is no error, the file uploaded with success" => "Nun hai dengún fallu, el ficheru xubióse ensin problemes", +"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "El ficheru xubíu perpasa la direutiva \"MAX_FILE_SIZE\" especificada nel formulariu HTML", +"The uploaded file was only partially uploaded" => "El ficheru xubióse de mou parcial", +"No file was uploaded" => "Nun se xubió dengún ficheru", +"Missing a temporary folder" => "Falta una carpeta temporal", +"Failed to write to disk" => "Fallu al escribir al discu", +"Not enough storage available" => "Nun hai abondu espaciu disponible", +"Files" => "Ficheros", +"Share" => "Compartir", +"Rename" => "Renomar", +"Error" => "Fallu", +"_%n folder_::_%n folders_" => array("",""), +"_%n file_::_%n files_" => array("",""), +"_Uploading %n file_::_Uploading %n files_" => array("",""), +"Name" => "Nome", +"Size" => "Tamañu", +"Upload" => "Xubir", +"Save" => "Guardar", +"New folder" => "Nueva carpeta", +"Cancel upload" => "Encaboxar xuba", +"Download" => "Descargar", +"Delete" => "Desaniciar" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files/l10n/be.php b/apps/files/l10n/be.php index 830400b93fb..f97fc27e2d1 100644 --- a/apps/files/l10n/be.php +++ b/apps/files/l10n/be.php @@ -1,8 +1,8 @@ "Памылка", "_%n folder_::_%n folders_" => array("","","",""), "_%n file_::_%n files_" => array("","","",""), -"_Uploading %n file_::_Uploading %n files_" => array("","","",""), -"Error" => "Памылка" +"_Uploading %n file_::_Uploading %n files_" => array("","","","") ); $PLURAL_FORMS = "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/apps/files/l10n/bg_BG.php b/apps/files/l10n/bg_BG.php index 12e699064be..2418010cdd9 100644 --- a/apps/files/l10n/bg_BG.php +++ b/apps/files/l10n/bg_BG.php @@ -12,12 +12,11 @@ $TRANSLATIONS = array( "Share" => "Споделяне", "Delete permanently" => "Изтриване завинаги", "Rename" => "Преименуване", +"Error" => "Грешка", "Pending" => "Чакащо", -"undo" => "възтановяване", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "Грешка", "Name" => "Име", "Size" => "Размер", "Modified" => "Променено", diff --git a/apps/files/l10n/bn_BD.php b/apps/files/l10n/bn_BD.php index 11f3525690b..667a68bb627 100644 --- a/apps/files/l10n/bn_BD.php +++ b/apps/files/l10n/bn_BD.php @@ -19,13 +19,11 @@ $TRANSLATIONS = array( "{new_name} already exists" => "{new_name} টি বিদ্যমান", "Share" => "ভাগাভাগি কর", "Rename" => "পূনঃনামকরণ", +"Error" => "সমস্যা", "Pending" => "মুলতুবি", -"replaced {new_name} with {old_name}" => "{new_name} কে {old_name} নামে প্রতিস্থাপন করা হয়েছে", -"undo" => "ক্রিয়া প্রত্যাহার", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "সমস্যা", "Name" => "রাম", "Size" => "আকার", "Modified" => "পরিবর্তিত", diff --git a/apps/files/l10n/ca.php b/apps/files/l10n/ca.php index a4418b1be50..8ef9b764484 100644 --- a/apps/files/l10n/ca.php +++ b/apps/files/l10n/ca.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Comparteix", "Delete permanently" => "Esborra permanentment", "Rename" => "Reanomena", +"Error moving file" => "Error en moure el fitxer", +"Error" => "Error", "Pending" => "Pendent", "Could not rename file" => "No es pot canviar el nom de fitxer", -"replaced {new_name} with {old_name}" => "s'ha substituït {old_name} per {new_name}", -"undo" => "desfés", "Error deleting file." => "Error en esborrar el fitxer.", "_%n folder_::_%n folders_" => array("%n carpeta","%n carpetes"), "_%n file_::_%n files_" => array("%n fitxer","%n fitxers"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "La clau privada de l'aplicació d'encriptació no és vàlida! Actualitzeu la contrasenya de la clau privada a l'arranjament personal per recuperar els fitxers encriptats.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "L'encriptació s'ha desactivat però els vostres fitxers segueixen encriptats. Aneu a la vostra configuració personal per desencriptar els vostres fitxers.", "Your download is being prepared. This might take some time if the files are big." => "S'està preparant la baixada. Pot trigar una estona si els fitxers són grans.", -"Error moving file" => "Error en moure el fitxer", -"Error" => "Error", "Name" => "Nom", "Size" => "Mida", "Modified" => "Modificat", diff --git a/apps/files/l10n/cs_CZ.php b/apps/files/l10n/cs_CZ.php index 5bcf1087b9c..8aea17a7051 100644 --- a/apps/files/l10n/cs_CZ.php +++ b/apps/files/l10n/cs_CZ.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Sdílet", "Delete permanently" => "Trvale odstranit", "Rename" => "Přejmenovat", +"Error moving file" => "Chyba při přesunu souboru", +"Error" => "Chyba", "Pending" => "Nevyřízené", "Could not rename file" => "Nepodařilo se přejmenovat soubor", -"replaced {new_name} with {old_name}" => "nahrazeno {new_name} s {old_name}", -"undo" => "vrátit zpět", "Error deleting file." => "Chyba při mazání souboru.", "_%n folder_::_%n folders_" => array("%n složka","%n složky","%n složek"), "_%n file_::_%n files_" => array("%n soubor","%n soubory","%n souborů"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Chybný soukromý klíč pro šifrovací aplikaci. Aktualizujte prosím heslo svého soukromého klíče ve vašem osobním nastavení, abyste znovu získali přístup k vašim zašifrovaným souborům.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Šifrování bylo vypnuto, vaše soubory jsou však stále zašifrované. Běžte prosím do osobního nastavení, kde soubory odšifrujete.", "Your download is being prepared. This might take some time if the files are big." => "Vaše soubory ke stažení se připravují. Pokud jsou velké, může to chvíli trvat.", -"Error moving file" => "Chyba při přesunu souboru", -"Error" => "Chyba", "Name" => "Název", "Size" => "Velikost", "Modified" => "Upraveno", diff --git a/apps/files/l10n/cy_GB.php b/apps/files/l10n/cy_GB.php index df93ca507b1..b27e4c3bfc2 100644 --- a/apps/files/l10n/cy_GB.php +++ b/apps/files/l10n/cy_GB.php @@ -21,16 +21,14 @@ $TRANSLATIONS = array( "Share" => "Rhannu", "Delete permanently" => "Dileu'n barhaol", "Rename" => "Ailenwi", +"Error" => "Gwall", "Pending" => "I ddod", -"replaced {new_name} with {old_name}" => "newidiwyd {new_name} yn lle {old_name}", -"undo" => "dadwneud", "_%n folder_::_%n folders_" => array("","","",""), "_%n file_::_%n files_" => array("","","",""), "_Uploading %n file_::_Uploading %n files_" => array("","","",""), "Your storage is full, files can not be updated or synced anymore!" => "Mae eich storfa'n llawn, ni ellir diweddaru a chydweddu ffeiliau mwyach!", "Your storage is almost full ({usedSpacePercent}%)" => "Mae eich storfa bron a bod yn llawn ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "Wrthi'n paratoi i lwytho i lawr. Gall gymryd peth amser os yw'r ffeiliau'n fawr.", -"Error" => "Gwall", "Name" => "Enw", "Size" => "Maint", "Modified" => "Addaswyd", diff --git a/apps/files/l10n/da.php b/apps/files/l10n/da.php index 7069849b430..6a7ea4745cc 100644 --- a/apps/files/l10n/da.php +++ b/apps/files/l10n/da.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Del", "Delete permanently" => "Slet permanent", "Rename" => "Omdøb", +"Error moving file" => "Fejl ved flytning af fil", +"Error" => "Fejl", "Pending" => "Afventer", "Could not rename file" => "Kunne ikke omdøbe filen", -"replaced {new_name} with {old_name}" => "erstattede {new_name} med {old_name}", -"undo" => "fortryd", "Error deleting file." => "Fejl ved sletnign af fil.", "_%n folder_::_%n folders_" => array("%n mappe","%n mapper"), "_%n file_::_%n files_" => array("%n fil","%n filer"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Ugyldig privat nøgle for krypteringsprogrammet. Opdater venligst dit kodeord for den private nøgle i dine personlige indstillinger. Det kræves for at få adgang til dine krypterede filer.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Krypteringen blev deaktiveret, men dine filer er stadig krypteret. Gå venligst til dine personlige indstillinger for at dekryptere dine filer. ", "Your download is being prepared. This might take some time if the files are big." => "Dit download forberedes. Dette kan tage lidt tid ved større filer.", -"Error moving file" => "Fejl ved flytning af fil", -"Error" => "Fejl", "Name" => "Navn", "Size" => "Størrelse", "Modified" => "Ændret", diff --git a/apps/files/l10n/de.php b/apps/files/l10n/de.php index 376cbaa4e25..401ee243f28 100644 --- a/apps/files/l10n/de.php +++ b/apps/files/l10n/de.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Teilen", "Delete permanently" => "Endgültig löschen", "Rename" => "Umbenennen", +"Error moving file" => "Fehler beim Verschieben der Datei", +"Error" => "Fehler", "Pending" => "Ausstehend", "Could not rename file" => "Die Datei konnte nicht umbenannt werden", -"replaced {new_name} with {old_name}" => "{old_name} ersetzt durch {new_name}", -"undo" => "rückgängig machen", "Error deleting file." => "Fehler beim Löschen der Datei.", "_%n folder_::_%n folders_" => array("%n Ordner","%n Ordner"), "_%n file_::_%n files_" => array("%n Datei","%n Dateien"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Ungültiger privater Schlüssel für die Verschlüsselung-App. Bitte aktualisiere Dein privates Schlüssel-Passwort, um den Zugriff auf Deine verschlüsselten Dateien wiederherzustellen.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Die Verschlüsselung wurde deaktiviert, jedoch sind Deine Dateien nach wie vor verschlüsselt. Bitte gehe zu Deinen persönlichen Einstellungen, um Deine Dateien zu entschlüsseln.", "Your download is being prepared. This might take some time if the files are big." => "Dein Download wird vorbereitet. Dies kann bei größeren Dateien etwas dauern.", -"Error moving file" => "Fehler beim Verschieben der Datei", -"Error" => "Fehler", "Name" => "Name", "Size" => "Größe", "Modified" => "Geändert", diff --git a/apps/files/l10n/de_CH.php b/apps/files/l10n/de_CH.php index 8b70d7f0f06..f797be99e98 100644 --- a/apps/files/l10n/de_CH.php +++ b/apps/files/l10n/de_CH.php @@ -23,9 +23,8 @@ $TRANSLATIONS = array( "Share" => "Teilen", "Delete permanently" => "Endgültig löschen", "Rename" => "Umbenennen", +"Error" => "Fehler", "Pending" => "Ausstehend", -"replaced {new_name} with {old_name}" => "{old_name} wurde ersetzt durch {new_name}", -"undo" => "rückgängig machen", "_%n folder_::_%n folders_" => array("","%n Ordner"), "_%n file_::_%n files_" => array("","%n Dateien"), "_Uploading %n file_::_Uploading %n files_" => array("%n Datei wird hochgeladen","%n Dateien werden hochgeladen"), @@ -33,7 +32,6 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Ihr Speicher ist fast voll ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Die Verschlüsselung wurde deaktiviert, jedoch sind Ihre Dateien nach wie vor verschlüsselt. Bitte gehen Sie zu Ihren persönlichen Einstellungen, um Ihre Dateien zu entschlüsseln.", "Your download is being prepared. This might take some time if the files are big." => "Ihr Download wird vorbereitet. Dies kann bei grösseren Dateien etwas dauern.", -"Error" => "Fehler", "Name" => "Name", "Size" => "Grösse", "Modified" => "Geändert", diff --git a/apps/files/l10n/de_DE.php b/apps/files/l10n/de_DE.php index 0df0f46dc24..4768faa97da 100644 --- a/apps/files/l10n/de_DE.php +++ b/apps/files/l10n/de_DE.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Teilen", "Delete permanently" => "Endgültig löschen", "Rename" => "Umbenennen", +"Error moving file" => "Fehler beim Verschieben der Datei", +"Error" => "Fehler", "Pending" => "Ausstehend", "Could not rename file" => "Die Datei konnte nicht umbenannt werden", -"replaced {new_name} with {old_name}" => "{old_name} wurde ersetzt durch {new_name}", -"undo" => "rückgängig machen", "Error deleting file." => "Fehler beim Löschen der Datei.", "_%n folder_::_%n folders_" => array("%n Ordner","%n Ordner"), "_%n file_::_%n files_" => array("%n Datei","%n Dateien"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Ungültiger privater Schlüssel für die Verschlüsselung-App. Bitte aktualisieren Sie Ihr privates Schlüssel-Passwort, um den Zugriff auf Ihre verschlüsselten Dateien wiederherzustellen.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Die Verschlüsselung wurde deaktiviert, jedoch sind Ihre Dateien nach wie vor verschlüsselt. Bitte gehen Sie zu Ihren persönlichen Einstellungen, um Ihre Dateien zu entschlüsseln.", "Your download is being prepared. This might take some time if the files are big." => "Ihr Download wird vorbereitet. Dies kann bei größeren Dateien etwas dauern.", -"Error moving file" => "Fehler beim Verschieben der Datei", -"Error" => "Fehler", "Name" => "Name", "Size" => "Größe", "Modified" => "Geändert", diff --git a/apps/files/l10n/el.php b/apps/files/l10n/el.php index 9144cf3ea10..713072d3e0e 100644 --- a/apps/files/l10n/el.php +++ b/apps/files/l10n/el.php @@ -5,6 +5,7 @@ $TRANSLATIONS = array( "File name cannot be empty." => "Το όνομα αρχείου δεν μπορεί να είναι κενό.", "\"%s\" is an invalid file name." => "Το \"%s\" είναι ένα μη έγκυρο όνομα αρχείου.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Μη έγκυρο όνομα, '\\', '/', '<', '>', ':', '\"', '|', '?' και '*' δεν επιτρέπονται.", +"The target folder has been moved or deleted." => "Ο φάκελος προορισμού έχει μετακινηθεί ή διαγραφεί.", "The name %s is already used in the folder %s. Please choose a different name." => "Το όνομα %s χρησιμοποιείτε ήδη στον φάκελο %s. Παρακαλώ επιλέξτε ένα άλλο όνομα.", "Not a valid source" => "Μη έγκυρη πηγή", "Server is not allowed to open URLs, please check the server configuration" => "Ο διακομιστής δεν επιτρέπεται να ανοίγει URL, παρακαλώ ελέγξτε τις ρυθμίσεις του διακομιστή", @@ -28,6 +29,8 @@ $TRANSLATIONS = array( "Invalid directory." => "Μη έγκυρος φάκελος.", "Files" => "Αρχεία", "Unable to upload {filename} as it is a directory or has 0 bytes" => "Αδυναμία φόρτωσης {filename} καθώς είναι κατάλογος αρχείων ή έχει 0 bytes", +"Total file size {size1} exceeds upload limit {size2}" => "Το συνολικό μέγεθος αρχείου {size1} υπερβαίνει το όριο μεταφόρτωσης {size2}", +"Not enough free space, you are uploading {size1} but only {size2} is left" => "Δεν υπάρχει αρκετός ελεύθερος χώρος, μεταφορτώνετε μέγεθος {size1} αλλά υπάρχει χώρος μόνο {size2}", "Upload cancelled." => "Η αποστολή ακυρώθηκε.", "Could not get result from server." => "Αδυναμία λήψης αποτελέσματος από το διακομιστή.", "File upload is in progress. Leaving the page now will cancel the upload." => "Η αποστολή του αρχείου βρίσκεται σε εξέλιξη. Το κλείσιμο της σελίδας θα ακυρώσει την αποστολή.", @@ -40,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Διαμοιρασμός", "Delete permanently" => "Μόνιμη διαγραφή", "Rename" => "Μετονομασία", +"Error moving file" => "Σφάλμα κατά τη μετακίνηση του αρχείου", +"Error" => "Σφάλμα", "Pending" => "Εκκρεμεί", "Could not rename file" => "Αδυναμία μετονομασίας αρχείου", -"replaced {new_name} with {old_name}" => "αντικαταστάθηκε το {new_name} με {old_name}", -"undo" => "αναίρεση", "Error deleting file." => "Σφάλμα διαγραφής αρχείου.", "_%n folder_::_%n folders_" => array("%n φάκελος","%n φάκελοι"), "_%n file_::_%n files_" => array("%n αρχείο","%n αρχεία"), @@ -56,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Άκυρο προσωπικό κλειδί για την εφαρμογή κρυπτογράφησης. Παρακαλώ ενημερώστε τον κωδικό του προσωπικού κλειδίου σας στις προσωπικές ρυθμίσεις για να επανακτήσετε πρόσβαση στα κρυπτογραφημένα σας αρχεία.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Η κρυπτογράφηση απενεργοποιήθηκε, αλλά τα αρχεία σας είναι ακόμα κρυπτογραφημένα. Παρακαλούμε απενεργοποιήσετε την κρυπτογράφηση αρχείων από τις προσωπικές σας ρυθμίσεις", "Your download is being prepared. This might take some time if the files are big." => "Η λήψη προετοιμάζεται. Αυτό μπορεί να πάρει ώρα εάν τα αρχεία έχουν μεγάλο μέγεθος.", -"Error moving file" => "Σφάλμα κατά τη μετακίνηση του αρχείου", -"Error" => "Σφάλμα", "Name" => "Όνομα", "Size" => "Μέγεθος", "Modified" => "Τροποποιήθηκε", diff --git a/apps/files/l10n/en_GB.php b/apps/files/l10n/en_GB.php index 3fb2cb62e60..705f6b99b0b 100644 --- a/apps/files/l10n/en_GB.php +++ b/apps/files/l10n/en_GB.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Share", "Delete permanently" => "Delete permanently", "Rename" => "Rename", +"Error moving file" => "Error moving file", +"Error" => "Error", "Pending" => "Pending", "Could not rename file" => "Could not rename file", -"replaced {new_name} with {old_name}" => "replaced {new_name} with {old_name}", -"undo" => "undo", "Error deleting file." => "Error deleting file.", "_%n folder_::_%n folders_" => array("%n folder","%n folders"), "_%n file_::_%n files_" => array("%n file","%n files"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files.", "Your download is being prepared. This might take some time if the files are big." => "Your download is being prepared. This might take some time if the files are big.", -"Error moving file" => "Error moving file", -"Error" => "Error", "Name" => "Name", "Size" => "Size", "Modified" => "Modified", diff --git a/apps/files/l10n/eo.php b/apps/files/l10n/eo.php index b92fef50006..a6e0d553177 100644 --- a/apps/files/l10n/eo.php +++ b/apps/files/l10n/eo.php @@ -35,10 +35,10 @@ $TRANSLATIONS = array( "Share" => "Kunhavigi", "Delete permanently" => "Forigi por ĉiam", "Rename" => "Alinomigi", +"Error moving file" => "Eraris movo de dosiero", +"Error" => "Eraro", "Pending" => "Traktotaj", "Could not rename file" => "Ne povis alinomiĝi dosiero", -"replaced {new_name} with {old_name}" => "anstataŭiĝis {new_name} per {old_name}", -"undo" => "malfari", "_%n folder_::_%n folders_" => array("%n dosierujo","%n dosierujoj"), "_%n file_::_%n files_" => array("%n dosiero","%n dosieroj"), "{dirs} and {files}" => "{dirs} kaj {files}", @@ -46,8 +46,6 @@ $TRANSLATIONS = array( "Your storage is full, files can not be updated or synced anymore!" => "Via memoro plenas, ne plu eblas ĝisdatigi aŭ sinkronigi dosierojn!", "Your storage is almost full ({usedSpacePercent}%)" => "Via memoro preskaŭ plenas ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "Via elŝuto pretiĝatas. Ĉi tio povas daŭri iom da tempo se la dosieroj grandas.", -"Error moving file" => "Eraris movo de dosiero", -"Error" => "Eraro", "Name" => "Nomo", "Size" => "Grando", "Modified" => "Modifita", diff --git a/apps/files/l10n/es.php b/apps/files/l10n/es.php index 6083ab2a5d6..10a378c371b 100644 --- a/apps/files/l10n/es.php +++ b/apps/files/l10n/es.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Compartir", "Delete permanently" => "Eliminar permanentemente", "Rename" => "Renombrar", +"Error moving file" => "Error moviendo archivo", +"Error" => "Error", "Pending" => "Pendiente", "Could not rename file" => "No se pudo renombrar el archivo", -"replaced {new_name} with {old_name}" => "reemplazado {new_name} con {old_name}", -"undo" => "deshacer", "Error deleting file." => "Error al borrar el archivo", "_%n folder_::_%n folders_" => array("%n carpeta","%n carpetas"), "_%n file_::_%n files_" => array("%n archivo","%n archivos"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "La clave privada no es válida para la app de cifrado. Por favor, actualiza la contraseña de tu clave privada en tus ajustes personales para recuperar el acceso a tus archivos cifrados.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "El cifrado ha sido deshabilitado pero tus archivos permanecen cifrados. Por favor, ve a tus ajustes personales para descifrar tus archivos.", "Your download is being prepared. This might take some time if the files are big." => "Su descarga está siendo preparada. Esto podría tardar algo de tiempo si los archivos son grandes.", -"Error moving file" => "Error moviendo archivo", -"Error" => "Error", "Name" => "Nombre", "Size" => "Tamaño", "Modified" => "Modificado", diff --git a/apps/files/l10n/es_AR.php b/apps/files/l10n/es_AR.php index 105321276c1..f78615fc923 100644 --- a/apps/files/l10n/es_AR.php +++ b/apps/files/l10n/es_AR.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "Compartir", "Delete permanently" => "Borrar permanentemente", "Rename" => "Cambiar nombre", +"Error moving file" => "Error moviendo el archivo", +"Error" => "Error", "Pending" => "Pendientes", "Could not rename file" => "No se pudo renombrar el archivo", -"replaced {new_name} with {old_name}" => "se reemplazó {new_name} con {old_name}", -"undo" => "deshacer", "Error deleting file." => "Error al borrar el archivo.", "_%n folder_::_%n folders_" => array("%n carpeta","%n carpetas"), "_%n file_::_%n files_" => array("%n archivo","%n archivos"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Llave privada inválida para la aplicación de encriptación. Por favor actualice la clave de la llave privada en las configuraciones personales para recobrar el acceso a sus archivos encriptados.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "El proceso de cifrado se ha desactivado, pero los archivos aún están encriptados. Por favor, vaya a la configuración personal para descifrar los archivos.", "Your download is being prepared. This might take some time if the files are big." => "Tu descarga se está preparando. Esto puede demorar si los archivos son muy grandes.", -"Error moving file" => "Error moviendo el archivo", -"Error" => "Error", "Name" => "Nombre", "Size" => "Tamaño", "Modified" => "Modificado", diff --git a/apps/files/l10n/es_CL.php b/apps/files/l10n/es_CL.php index 4f5e35bd887..8e051d1c389 100644 --- a/apps/files/l10n/es_CL.php +++ b/apps/files/l10n/es_CL.php @@ -2,10 +2,10 @@ $TRANSLATIONS = array( "Files" => "Archivos", "Share" => "Compartir", +"Error" => "Error", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "Error", "Upload" => "Subir", "Download" => "Descargar" ); diff --git a/apps/files/l10n/es_MX.php b/apps/files/l10n/es_MX.php index f8a72f95d85..ea7db0d7b9c 100644 --- a/apps/files/l10n/es_MX.php +++ b/apps/files/l10n/es_MX.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "Compartir", "Delete permanently" => "Eliminar permanentemente", "Rename" => "Renombrar", +"Error moving file" => "Error moviendo archivo", +"Error" => "Error", "Pending" => "Pendiente", "Could not rename file" => "No se pudo renombrar el archivo", -"replaced {new_name} with {old_name}" => "reemplazado {new_name} con {old_name}", -"undo" => "deshacer", "Error deleting file." => "Error borrando el archivo.", "_%n folder_::_%n folders_" => array("%n carpeta","%n carpetas"), "_%n file_::_%n files_" => array("%n archivo","%n archivos"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "La clave privada no es válida para la aplicación de cifrado. Por favor, actualiza la contraseña de tu clave privada en tus ajustes personales para recuperar el acceso a tus archivos cifrados.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "El cifrado ha sido deshabilitado pero tus archivos permanecen cifrados. Por favor, ve a tus ajustes personales para descifrar tus archivos.", "Your download is being prepared. This might take some time if the files are big." => "Su descarga está siendo preparada. Esto podría tardar algo de tiempo si los archivos son grandes.", -"Error moving file" => "Error moviendo archivo", -"Error" => "Error", "Name" => "Nombre", "Size" => "Tamaño", "Modified" => "Modificado", diff --git a/apps/files/l10n/et_EE.php b/apps/files/l10n/et_EE.php index f1fdc82673c..4f0614feb5e 100644 --- a/apps/files/l10n/et_EE.php +++ b/apps/files/l10n/et_EE.php @@ -3,7 +3,9 @@ $TRANSLATIONS = array( "Could not move %s - File with this name already exists" => "Ei saa liigutada faili %s - samanimeline fail on juba olemas", "Could not move %s" => "%s liigutamine ebaõnnestus", "File name cannot be empty." => "Faili nimi ei saa olla tühi.", +"\"%s\" is an invalid file name." => "\"%s\" on vigane failinimi.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Vigane nimi, '\\', '/', '<', '>', ':', '\"', '|', '?' ja '*' pole lubatud.", +"The target folder has been moved or deleted." => "Sihtkataloog on ümber tõstetud või kustutatud.", "The name %s is already used in the folder %s. Please choose a different name." => "Nimi %s on juba kasutusel kataloogis %s. Palun vali mõni teine nimi.", "Not a valid source" => "Pole korrektne lähteallikas", "Server is not allowed to open URLs, please check the server configuration" => "Server ei võimalda URL-ide avamist, palun kontrolli serveri seadistust", @@ -27,6 +29,8 @@ $TRANSLATIONS = array( "Invalid directory." => "Vigane kaust.", "Files" => "Failid", "Unable to upload {filename} as it is a directory or has 0 bytes" => "Ei saa üles laadida {filename}, kuna see on kataloog või selle suurus on 0 baiti", +"Total file size {size1} exceeds upload limit {size2}" => "Faili suurus {size1} ületab faili üleslaadimise mahu piirangu {size2}.", +"Not enough free space, you are uploading {size1} but only {size2} is left" => "Pole piisavalt vaba ruumi. Sa laadid üles {size1}, kuid ainult {size2} on saadaval.", "Upload cancelled." => "Üleslaadimine tühistati.", "Could not get result from server." => "Serverist ei saadud tulemusi", "File upload is in progress. Leaving the page now will cancel the upload." => "Faili üleslaadimine on töös. Lehelt lahkumine katkestab selle üleslaadimise.", @@ -39,23 +43,22 @@ $TRANSLATIONS = array( "Share" => "Jaga", "Delete permanently" => "Kustuta jäädavalt", "Rename" => "Nimeta ümber", +"Error moving file" => "Viga faili eemaldamisel", +"Error" => "Viga", "Pending" => "Ootel", "Could not rename file" => "Ei suuda faili ümber nimetada", -"replaced {new_name} with {old_name}" => "asendas nime {old_name} nimega {new_name}", -"undo" => "tagasi", "Error deleting file." => "Viga faili kustutamisel.", "_%n folder_::_%n folders_" => array("%n kataloog","%n kataloogi"), "_%n file_::_%n files_" => array("%n fail","%n faili"), "{dirs} and {files}" => "{dirs} ja {files}", "_Uploading %n file_::_Uploading %n files_" => array("Laadin üles %n faili","Laadin üles %n faili"), +"\"{name}\" is an invalid file name." => "\"{name}\" on vigane failinimi.", "Your storage is full, files can not be updated or synced anymore!" => "Sinu andmemaht on täis! Faile ei uuendata ega sünkroniseerita!", "Your storage is almost full ({usedSpacePercent}%)" => "Su andmemaht on peaaegu täis ({usedSpacePercent}%)", "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "Krüpteerimisrakend on lubatud, kuid võtmeid pole lähtestatud. Palun logi välja ning uuesti sisse.", "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Vigane Krüpteerimisrakendi privaatvõti . Palun uuenda oma privaatse võtme parool oma personaasete seadete all taastamaks ligipääsu oma krüpteeritud failidele.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Krüpteering on keelatud, kuid sinu failid on endiselt krüpteeritud. Palun vaata oma personaalseid seadeid oma failide dekrüpteerimiseks.", "Your download is being prepared. This might take some time if the files are big." => "Valmistatakse allalaadimist. See võib võtta veidi aega, kui on tegu suurte failidega. ", -"Error moving file" => "Viga faili eemaldamisel", -"Error" => "Viga", "Name" => "Nimi", "Size" => "Suurus", "Modified" => "Muudetud", diff --git a/apps/files/l10n/eu.php b/apps/files/l10n/eu.php index be601eecfbf..d59dd396283 100644 --- a/apps/files/l10n/eu.php +++ b/apps/files/l10n/eu.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "Elkarbanatu", "Delete permanently" => "Ezabatu betirako", "Rename" => "Berrizendatu", +"Error moving file" => "Errorea fitxategia mugitzean", +"Error" => "Errorea", "Pending" => "Zain", "Could not rename file" => "Ezin izan da fitxategia berrizendatu", -"replaced {new_name} with {old_name}" => " {new_name}-k {old_name} ordezkatu du", -"undo" => "desegin", "Error deleting file." => "Errorea fitxategia ezabatzerakoan.", "_%n folder_::_%n folders_" => array("karpeta %n","%n karpeta"), "_%n file_::_%n files_" => array("fitxategi %n","%n fitxategi"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Enkriptazio aplikaziorako gako pribatu okerra. Mesedez eguneratu zure gako pribatuaren pasahitza zure ezarpen pertsonaletan zure enkriptatuko fitxategietarako sarrera berreskuratzeko.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Enkriptazioa desgaitua izan da baina zure fitxategiak oraindik enkriptatuta daude. Mesedez jo zure ezarpen pertsonaletara zure fitxategiak dekodifikatzeko.", "Your download is being prepared. This might take some time if the files are big." => "Zure deskarga prestatu egin behar da. Denbora bat har lezake fitxategiak handiak badira. ", -"Error moving file" => "Errorea fitxategia mugitzean", -"Error" => "Errorea", "Name" => "Izena", "Size" => "Tamaina", "Modified" => "Aldatuta", diff --git a/apps/files/l10n/fa.php b/apps/files/l10n/fa.php index e1142aba160..2e8f6255e24 100644 --- a/apps/files/l10n/fa.php +++ b/apps/files/l10n/fa.php @@ -23,16 +23,14 @@ $TRANSLATIONS = array( "Share" => "اشتراک‌گذاری", "Delete permanently" => "حذف قطعی", "Rename" => "تغییرنام", +"Error" => "خطا", "Pending" => "در انتظار", -"replaced {new_name} with {old_name}" => "{نام_جدید} با { نام_قدیمی} جایگزین شد.", -"undo" => "بازگشت", "_%n folder_::_%n folders_" => array(""), "_%n file_::_%n files_" => array(""), "_Uploading %n file_::_Uploading %n files_" => array("در حال بارگذاری %n فایل"), "Your storage is full, files can not be updated or synced anymore!" => "فضای ذخیره ی شما کاملا پر است، بیش از این فایلها بهنگام یا همگام سازی نمی توانند بشوند!", "Your storage is almost full ({usedSpacePercent}%)" => "فضای ذخیره ی شما تقریبا پر است ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "دانلود شما در حال آماده شدن است. در صورتیکه پرونده ها بزرگ باشند ممکن است مدتی طول بکشد.", -"Error" => "خطا", "Name" => "نام", "Size" => "اندازه", "Modified" => "تاریخ", diff --git a/apps/files/l10n/fi_FI.php b/apps/files/l10n/fi_FI.php index 6b94d8b4fae..b6383c144de 100644 --- a/apps/files/l10n/fi_FI.php +++ b/apps/files/l10n/fi_FI.php @@ -41,9 +41,10 @@ $TRANSLATIONS = array( "Share" => "Jaa", "Delete permanently" => "Poista pysyvästi", "Rename" => "Nimeä uudelleen", +"Error moving file" => "Virhe tiedostoa siirrettäessä", +"Error" => "Virhe", "Pending" => "Odottaa", "Could not rename file" => "Tiedoston nimeäminen uudelleen epäonnistui", -"undo" => "kumoa", "Error deleting file." => "Virhe tiedostoa poistaessa.", "_%n folder_::_%n folders_" => array("%n kansio","%n kansiota"), "_%n file_::_%n files_" => array("%n tiedosto","%n tiedostoa"), @@ -54,8 +55,6 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Tallennustila on melkein loppu ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Salaus poistettiin käytöstä, mutta tiedostosi ovat edelleen salattuina. Siirry henkilökohtaisiin asetuksiin avataksesi tiedostojesi salauksen.", "Your download is being prepared. This might take some time if the files are big." => "Lataustasi valmistellaan. Tämä saattaa kestää hetken, jos tiedostot ovat suuria kooltaan.", -"Error moving file" => "Virhe tiedostoa siirrettäessä", -"Error" => "Virhe", "Name" => "Nimi", "Size" => "Koko", "Modified" => "Muokattu", diff --git a/apps/files/l10n/fr.php b/apps/files/l10n/fr.php index ad768f03de7..0eed6a70f91 100644 --- a/apps/files/l10n/fr.php +++ b/apps/files/l10n/fr.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Partager", "Delete permanently" => "Supprimer de façon définitive", "Rename" => "Renommer", +"Error moving file" => "Erreur lors du déplacement du fichier", +"Error" => "Erreur", "Pending" => "En attente", "Could not rename file" => "Impossible de renommer le fichier", -"replaced {new_name} with {old_name}" => "{new_name} a été remplacé par {old_name}", -"undo" => "annuler", "Error deleting file." => "Erreur pendant la suppression du fichier.", "_%n folder_::_%n folders_" => array("%n dossier","%n dossiers"), "_%n file_::_%n files_" => array("%n fichier","%n fichiers"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Votre clef privée pour l'application de chiffrement est invalide ! Veuillez mettre à jour le mot de passe de votre clef privée dans vos paramètres personnels pour récupérer l'accès à vos fichiers chiffrés.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement était désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos Paramètres personnels pour déchiffrer vos fichiers.", "Your download is being prepared. This might take some time if the files are big." => "Votre téléchargement est cours de préparation. Ceci peut nécessiter un certain temps si les fichiers sont volumineux.", -"Error moving file" => "Erreur lors du déplacement du fichier", -"Error" => "Erreur", "Name" => "Nom", "Size" => "Taille", "Modified" => "Modifié", diff --git a/apps/files/l10n/gl.php b/apps/files/l10n/gl.php index 7ea8181dc71..9fe6546de51 100644 --- a/apps/files/l10n/gl.php +++ b/apps/files/l10n/gl.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Compartir", "Delete permanently" => "Eliminar permanentemente", "Rename" => "Renomear", +"Error moving file" => "Produciuse un erro ao mover o ficheiro", +"Error" => "Erro", "Pending" => "Pendentes", "Could not rename file" => "Non foi posíbel renomear o ficheiro", -"replaced {new_name} with {old_name}" => "substituír {new_name} por {old_name}", -"undo" => "desfacer", "Error deleting file." => "Produciuse un erro ao eliminar o ficheiro.", "_%n folder_::_%n folders_" => array("%n cartafol","%n cartafoles"), "_%n file_::_%n files_" => array("%n ficheiro","%n ficheiros"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "A chave privada para o aplicativo de cifrado non é correcta. Actualice o contrasinal da súa chave privada nos seus axustes persoais para recuperar o acceso aos seus ficheiros cifrados.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "O cifrado foi desactivado, mais os ficheiros están cifrados. Vaia á configuración persoal para descifrar os ficheiros.", "Your download is being prepared. This might take some time if the files are big." => "Está a prepararse a súa descarga. Isto pode levar bastante tempo se os ficheiros son grandes.", -"Error moving file" => "Produciuse un erro ao mover o ficheiro", -"Error" => "Erro", "Name" => "Nome", "Size" => "Tamaño", "Modified" => "Modificado", diff --git a/apps/files/l10n/he.php b/apps/files/l10n/he.php index 2035c8488bd..ab8640a91d1 100644 --- a/apps/files/l10n/he.php +++ b/apps/files/l10n/he.php @@ -23,14 +23,12 @@ $TRANSLATIONS = array( "Share" => "שתף", "Delete permanently" => "מחק לצמיתות", "Rename" => "שינוי שם", +"Error" => "שגיאה", "Pending" => "ממתין", -"replaced {new_name} with {old_name}" => "{new_name} הוחלף ב־{old_name}", -"undo" => "ביטול", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), "Your storage is almost full ({usedSpacePercent}%)" => "שטח האחסון שלך כמעט מלא ({usedSpacePercent}%)", -"Error" => "שגיאה", "Name" => "שם", "Size" => "גודל", "Modified" => "זמן שינוי", diff --git a/apps/files/l10n/hi.php b/apps/files/l10n/hi.php index ae01bfc47e1..b4234b51376 100644 --- a/apps/files/l10n/hi.php +++ b/apps/files/l10n/hi.php @@ -1,10 +1,10 @@ "साझा करें", +"Error" => "त्रुटि", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "त्रुटि", "Upload" => "अपलोड ", "Save" => "सहेजें" ); diff --git a/apps/files/l10n/hr.php b/apps/files/l10n/hr.php index 5048a15c8bb..ef978e6cfb7 100644 --- a/apps/files/l10n/hr.php +++ b/apps/files/l10n/hr.php @@ -11,12 +11,11 @@ $TRANSLATIONS = array( "File upload is in progress. Leaving the page now will cancel the upload." => "Učitavanje datoteke. Napuštanjem stranice će prekinuti učitavanje.", "Share" => "Podijeli", "Rename" => "Promjeni ime", +"Error" => "Greška", "Pending" => "U tijeku", -"undo" => "vrati", "_%n folder_::_%n folders_" => array("","",""), "_%n file_::_%n files_" => array("","",""), "_Uploading %n file_::_Uploading %n files_" => array("","",""), -"Error" => "Greška", "Name" => "Ime", "Size" => "Veličina", "Modified" => "Zadnja promjena", diff --git a/apps/files/l10n/hu_HU.php b/apps/files/l10n/hu_HU.php index 6f5ba9b4724..e4ab355c9b1 100644 --- a/apps/files/l10n/hu_HU.php +++ b/apps/files/l10n/hu_HU.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "Megosztás", "Delete permanently" => "Végleges törlés", "Rename" => "Átnevezés", +"Error moving file" => "Az állomány áthelyezése nem sikerült.", +"Error" => "Hiba", "Pending" => "Folyamatban", "Could not rename file" => "Az állomány nem nevezhető át", -"replaced {new_name} with {old_name}" => "{new_name} fájlt kicseréltük ezzel: {old_name}", -"undo" => "visszavonás", "Error deleting file." => "Hiba a file törlése közben.", "_%n folder_::_%n folders_" => array("%n mappa","%n mappa"), "_%n file_::_%n files_" => array("%n állomány","%n állomány"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Az állományok titkosításához használt titkos kulcsa érvénytelen. Kérjük frissítse a titkos kulcs jelszót a személyes beállításokban, hogy ismét hozzáférjen a titkosított állományaihoz!", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "A titkosítási funkciót kikapcsolták, de az Ön állományai még mindig titkosított állapotban vannak. A személyes beállításoknál tudja a titkosítást feloldani.", "Your download is being prepared. This might take some time if the files are big." => "Készül a letöltendő állomány. Ez eltarthat egy ideig, ha nagyok a fájlok.", -"Error moving file" => "Az állomány áthelyezése nem sikerült.", -"Error" => "Hiba", "Name" => "Név", "Size" => "Méret", "Modified" => "Módosítva", diff --git a/apps/files/l10n/ia.php b/apps/files/l10n/ia.php index 82fd2e658d7..420e48395c7 100644 --- a/apps/files/l10n/ia.php +++ b/apps/files/l10n/ia.php @@ -5,10 +5,10 @@ $TRANSLATIONS = array( "Missing a temporary folder" => "Manca un dossier temporari", "Files" => "Files", "Share" => "Compartir", +"Error" => "Error", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "Error", "Name" => "Nomine", "Size" => "Dimension", "Modified" => "Modificate", diff --git a/apps/files/l10n/id.php b/apps/files/l10n/id.php index 45bc05c9182..8356c5465eb 100644 --- a/apps/files/l10n/id.php +++ b/apps/files/l10n/id.php @@ -37,10 +37,10 @@ $TRANSLATIONS = array( "Share" => "Bagikan", "Delete permanently" => "Hapus secara permanen", "Rename" => "Ubah nama", +"Error moving file" => "Galat saat memindahkan berkas", +"Error" => "Galat", "Pending" => "Menunggu", "Could not rename file" => "Tidak dapat mengubah nama berkas", -"replaced {new_name} with {old_name}" => "mengganti {new_name} dengan {old_name}", -"undo" => "urungkan", "Error deleting file." => "Galat saat menghapus berkas.", "_%n folder_::_%n folders_" => array("%n folder"), "_%n file_::_%n files_" => array("%n berkas"), @@ -52,8 +52,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Kunci privat tidak sah untuk Aplikasi Enskripsi. Silakan perbarui sandi kunci privat anda pada pengaturan pribadi untuk memulihkan akses ke berkas anda yang dienskripsi.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Enskripi telah dinonaktifkan tetapi berkas anda tetap dienskripsi. Silakan menuju ke pengaturan pribadi untuk deskrip berkas anda.", "Your download is being prepared. This might take some time if the files are big." => "Unduhan Anda sedang disiapkan. Prosesnya dapat berlangsung agak lama jika ukuran berkasnya besar.", -"Error moving file" => "Galat saat memindahkan berkas", -"Error" => "Galat", "Name" => "Nama", "Size" => "Ukuran", "Modified" => "Dimodifikasi", diff --git a/apps/files/l10n/is.php b/apps/files/l10n/is.php index 088cdefa304..00503028e0e 100644 --- a/apps/files/l10n/is.php +++ b/apps/files/l10n/is.php @@ -19,13 +19,11 @@ $TRANSLATIONS = array( "{new_name} already exists" => "{new_name} er þegar til", "Share" => "Deila", "Rename" => "Endurskýra", +"Error" => "Villa", "Pending" => "Bíður", -"replaced {new_name} with {old_name}" => "yfirskrifaði {new_name} með {old_name}", -"undo" => "afturkalla", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "Villa", "Name" => "Nafn", "Size" => "Stærð", "Modified" => "Breytt", diff --git a/apps/files/l10n/it.php b/apps/files/l10n/it.php index e1a34e646fb..9539496a3fc 100644 --- a/apps/files/l10n/it.php +++ b/apps/files/l10n/it.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Condividi", "Delete permanently" => "Elimina definitivamente", "Rename" => "Rinomina", +"Error moving file" => "Errore durante lo spostamento del file", +"Error" => "Errore", "Pending" => "In corso", "Could not rename file" => "Impossibile rinominare il file", -"replaced {new_name} with {old_name}" => "sostituito {new_name} con {old_name}", -"undo" => "annulla", "Error deleting file." => "Errore durante l'eliminazione del file.", "_%n folder_::_%n folders_" => array("%n cartella","%n cartelle"), "_%n file_::_%n files_" => array("%n file","%n file"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Chiave privata non valida per l'applicazione di cifratura. Aggiorna la password della chiave privata nelle impostazioni personali per ripristinare l'accesso ai tuoi file cifrati.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "La cifratura è stata disabilitata ma i tuoi file sono ancora cifrati. Vai nelle impostazioni personali per decifrare i file.", "Your download is being prepared. This might take some time if the files are big." => "Il tuo scaricamento è in fase di preparazione. Ciò potrebbe richiedere del tempo se i file sono grandi.", -"Error moving file" => "Errore durante lo spostamento del file", -"Error" => "Errore", "Name" => "Nome", "Size" => "Dimensione", "Modified" => "Modificato", diff --git a/apps/files/l10n/ja.php b/apps/files/l10n/ja.php index eb6cb0efc50..dd8d4e4e3f6 100644 --- a/apps/files/l10n/ja.php +++ b/apps/files/l10n/ja.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "共有", "Delete permanently" => "完全に削除する", "Rename" => "名前の変更", +"Error moving file" => "ファイルの移動エラー", +"Error" => "エラー", "Pending" => "中断", "Could not rename file" => "ファイルの名前変更ができませんでした", -"replaced {new_name} with {old_name}" => "{old_name} を {new_name} に置換", -"undo" => "元に戻す", "Error deleting file." => "ファイルの削除エラー。", "_%n folder_::_%n folders_" => array("%n 個のフォルダー"), "_%n file_::_%n files_" => array("%n 個のファイル"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "暗号化アプリの無効なプライベートキーです。あなたの暗号化されたファイルへアクセスするために、個人設定からプライベートキーのパスワードを更新してください。", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "暗号化の機能は無効化されましたが、ファイルはすでに暗号化されています。個人設定からファイルを複合を行ってください。", "Your download is being prepared. This might take some time if the files are big." => "ダウンロードの準備中です。ファイルサイズが大きい場合は少し時間がかかるかもしれません。", -"Error moving file" => "ファイルの移動エラー", -"Error" => "エラー", "Name" => "名前", "Size" => "サイズ", "Modified" => "更新日時", diff --git a/apps/files/l10n/jv.php b/apps/files/l10n/jv.php new file mode 100644 index 00000000000..cfab5af7d1c --- /dev/null +++ b/apps/files/l10n/jv.php @@ -0,0 +1,8 @@ + array("",""), +"_%n file_::_%n files_" => array("",""), +"_Uploading %n file_::_Uploading %n files_" => array("",""), +"Download" => "Njipuk" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files/l10n/ka_GE.php b/apps/files/l10n/ka_GE.php index 230c2e4ede2..f9749d72bb4 100644 --- a/apps/files/l10n/ka_GE.php +++ b/apps/files/l10n/ka_GE.php @@ -21,16 +21,14 @@ $TRANSLATIONS = array( "Share" => "გაზიარება", "Delete permanently" => "სრულად წაშლა", "Rename" => "გადარქმევა", +"Error" => "შეცდომა", "Pending" => "მოცდის რეჟიმში", -"replaced {new_name} with {old_name}" => "{new_name} შეცვლილია {old_name}–ით", -"undo" => "დაბრუნება", "_%n folder_::_%n folders_" => array(""), "_%n file_::_%n files_" => array(""), "_Uploading %n file_::_Uploading %n files_" => array(""), "Your storage is full, files can not be updated or synced anymore!" => "თქვენი საცავი გადაივსო. ფაილების განახლება და სინქრონიზირება ვერ მოხერხდება!", "Your storage is almost full ({usedSpacePercent}%)" => "თქვენი საცავი თითქმის გადაივსო ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "გადმოწერის მოთხოვნა მუშავდება. ის მოითხოვს გარკვეულ დროს რაგდან ფაილები არის დიდი ზომის.", -"Error" => "შეცდომა", "Name" => "სახელი", "Size" => "ზომა", "Modified" => "შეცვლილია", diff --git a/apps/files/l10n/km.php b/apps/files/l10n/km.php index 702c811ecf2..a7a01ccab9d 100644 --- a/apps/files/l10n/km.php +++ b/apps/files/l10n/km.php @@ -2,11 +2,10 @@ $TRANSLATIONS = array( "Files" => "ឯកសារ", "Share" => "ចែក​រំលែក", -"undo" => "មិន​ធ្វើ​វិញ", +"Error" => "កំហុស", "_%n folder_::_%n folders_" => array(""), "_%n file_::_%n files_" => array(""), "_Uploading %n file_::_Uploading %n files_" => array(""), -"Error" => "កំហុស", "Name" => "ឈ្មោះ", "Size" => "ទំហំ", "Upload" => "ផ្ទុក​ឡើង", diff --git a/apps/files/l10n/ko.php b/apps/files/l10n/ko.php index 92a2578074c..c0f0d7d4454 100644 --- a/apps/files/l10n/ko.php +++ b/apps/files/l10n/ko.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "공유", "Delete permanently" => "영구히 삭제", "Rename" => "이름 바꾸기", +"Error moving file" => "파일 이동 오류", +"Error" => "오류", "Pending" => "대기 중", "Could not rename file" => "이름을 변경할 수 없음", -"replaced {new_name} with {old_name}" => "{old_name}이(가) {new_name}(으)로 대체됨", -"undo" => "실행 취소", "Error deleting file." => "파일 삭제 오류.", "_%n folder_::_%n folders_" => array("폴더 %n개"), "_%n file_::_%n files_" => array("파일 %n개"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "암호화 앱의 개인 키가 잘못되었습니다. 암호화된 파일에 다시 접근하려면 개인 설정에서 개인 키 암호를 업데이트해야 합니다.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "암호화는 해제되어 있지만, 파일은 아직 암호화되어 있습니다. 개인 설정에서 파일을 복호화하십시오.", "Your download is being prepared. This might take some time if the files are big." => "다운로드 준비 중입니다. 파일 크기가 크면 시간이 오래 걸릴 수도 있습니다.", -"Error moving file" => "파일 이동 오류", -"Error" => "오류", "Name" => "이름", "Size" => "크기", "Modified" => "수정됨", diff --git a/apps/files/l10n/ku_IQ.php b/apps/files/l10n/ku_IQ.php index c0141656f5d..6ec5819d380 100644 --- a/apps/files/l10n/ku_IQ.php +++ b/apps/files/l10n/ku_IQ.php @@ -2,10 +2,10 @@ $TRANSLATIONS = array( "Files" => "په‌ڕگەکان", "Share" => "هاوبەشی کردن", +"Error" => "هه‌ڵه", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "هه‌ڵه", "Name" => "ناو", "Upload" => "بارکردن", "Save" => "پاشکه‌وتکردن", diff --git a/apps/files/l10n/lb.php b/apps/files/l10n/lb.php index 822ca7e2d02..38b5d672d02 100644 --- a/apps/files/l10n/lb.php +++ b/apps/files/l10n/lb.php @@ -11,11 +11,10 @@ $TRANSLATIONS = array( "File upload is in progress. Leaving the page now will cancel the upload." => "File Upload am gaang. Wann's de des Säit verléiss gëtt den Upload ofgebrach.", "Share" => "Deelen", "Rename" => "Ëm-benennen", -"undo" => "réckgängeg man", +"Error" => "Fehler", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "Fehler", "Name" => "Numm", "Size" => "Gréisst", "Modified" => "Geännert", diff --git a/apps/files/l10n/lt_LT.php b/apps/files/l10n/lt_LT.php index 14c48621174..50097e5f362 100644 --- a/apps/files/l10n/lt_LT.php +++ b/apps/files/l10n/lt_LT.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "Dalintis", "Delete permanently" => "Ištrinti negrįžtamai", "Rename" => "Pervadinti", +"Error moving file" => "Klaida perkeliant failą", +"Error" => "Klaida", "Pending" => "Laukiantis", "Could not rename file" => "Neįmanoma pervadinti failo", -"replaced {new_name} with {old_name}" => "pakeiskite {new_name} į {old_name}", -"undo" => "anuliuoti", "Error deleting file." => "Klaida trinant failą.", "_%n folder_::_%n folders_" => array("%n aplankas","%n aplankai","%n aplankų"), "_%n file_::_%n files_" => array("%n failas","%n failai","%n failų"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Netinkamas privatus raktas Šifravimo programai. Prašome atnaujinti savo privataus rakto slaptažodį asmeniniuose nustatymuose, kad atkurti prieigą prie šifruotų failų.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Šifravimas buvo išjungtas, bet Jūsų failai vis dar užšifruoti. Prašome eiti į asmeninius nustatymus ir iššifruoti savo failus.", "Your download is being prepared. This might take some time if the files are big." => "Jūsų atsisiuntimas yra paruošiamas. tai gali užtrukti jei atsisiunčiamas didelis failas.", -"Error moving file" => "Klaida perkeliant failą", -"Error" => "Klaida", "Name" => "Pavadinimas", "Size" => "Dydis", "Modified" => "Pakeista", diff --git a/apps/files/l10n/lv.php b/apps/files/l10n/lv.php index 0d2ebf281ab..fcb1a59aa38 100644 --- a/apps/files/l10n/lv.php +++ b/apps/files/l10n/lv.php @@ -23,9 +23,8 @@ $TRANSLATIONS = array( "Share" => "Dalīties", "Delete permanently" => "Dzēst pavisam", "Rename" => "Pārsaukt", +"Error" => "Kļūda", "Pending" => "Gaida savu kārtu", -"replaced {new_name} with {old_name}" => "aizvietoja {new_name} ar {old_name}", -"undo" => "atsaukt", "_%n folder_::_%n folders_" => array("%n mapes","%n mape","%n mapes"), "_%n file_::_%n files_" => array("%n faili","%n fails","%n faili"), "_Uploading %n file_::_Uploading %n files_" => array("%n","Augšupielāde %n failu","Augšupielāde %n failus"), @@ -33,7 +32,6 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Jūsu krātuve ir gandrīz pilna ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Šifrēšana tika atslēgta, tomēr jūsu faili joprojām ir šifrēti. Atšifrēt failus var Personiskajos uzstādījumos.", "Your download is being prepared. This might take some time if the files are big." => "Tiek sagatavota lejupielāde. Tas var aizņemt kādu laiciņu, ja datnes ir lielas.", -"Error" => "Kļūda", "Name" => "Nosaukums", "Size" => "Izmērs", "Modified" => "Mainīts", diff --git a/apps/files/l10n/mk.php b/apps/files/l10n/mk.php index bc9ee15823c..fa6efd1aff3 100644 --- a/apps/files/l10n/mk.php +++ b/apps/files/l10n/mk.php @@ -34,10 +34,10 @@ $TRANSLATIONS = array( "Share" => "Сподели", "Delete permanently" => "Трајно избришани", "Rename" => "Преименувај", +"Error moving file" => "Грешка при префрлање на датотека", +"Error" => "Грешка", "Pending" => "Чека", "Could not rename file" => "Не можам да ја преименувам датотеката", -"replaced {new_name} with {old_name}" => "заменета {new_name} со {old_name}", -"undo" => "врати", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "{dirs} and {files}" => "{dirs} и {files}", @@ -45,8 +45,6 @@ $TRANSLATIONS = array( "Your storage is full, files can not be updated or synced anymore!" => "Вашиот сториџ е полн, датотеките веќе не можат да се освежуваат или синхронизираат!", "Your storage is almost full ({usedSpacePercent}%)" => "Вашиот сториџ е скоро полн ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "Вашето преземање се подготвува. Ова може да потрае до колку датотеките се големи.", -"Error moving file" => "Грешка при префрлање на датотека", -"Error" => "Грешка", "Name" => "Име", "Size" => "Големина", "Modified" => "Променето", diff --git a/apps/files/l10n/ms_MY.php b/apps/files/l10n/ms_MY.php index 0a7a50abb1a..df0054c3d00 100644 --- a/apps/files/l10n/ms_MY.php +++ b/apps/files/l10n/ms_MY.php @@ -11,11 +11,11 @@ $TRANSLATIONS = array( "Upload cancelled." => "Muatnaik dibatalkan.", "Share" => "Kongsi", "Rename" => "Namakan", +"Error" => "Ralat", "Pending" => "Dalam proses", "_%n folder_::_%n folders_" => array(""), "_%n file_::_%n files_" => array(""), "_Uploading %n file_::_Uploading %n files_" => array(""), -"Error" => "Ralat", "Name" => "Nama", "Size" => "Saiz", "Modified" => "Dimodifikasi", diff --git a/apps/files/l10n/nb_NO.php b/apps/files/l10n/nb_NO.php index b90bee38f99..f1e2c2edeeb 100644 --- a/apps/files/l10n/nb_NO.php +++ b/apps/files/l10n/nb_NO.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "Del", "Delete permanently" => "Slett permanent", "Rename" => "Gi nytt navn", +"Error moving file" => "Feil ved flytting av fil", +"Error" => "Feil", "Pending" => "Ventende", "Could not rename file" => "Klarte ikke å gi nytt navn til fil", -"replaced {new_name} with {old_name}" => "erstattet {new_name} med {old_name}", -"undo" => "angre", "Error deleting file." => "Feil ved sletting av fil.", "_%n folder_::_%n folders_" => array("%n mappe","%n mapper"), "_%n file_::_%n files_" => array("%n fil","%n filer"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Ugyldig privat nøkkel for Krypterings-app. Oppdater passordet for din private nøkkel i dine personlige innstillinger for å gjenopprette tilgang til de krypterte filene dine.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Kryptering ble slått av men filene dine er fremdeles kryptert. Gå til dine personlige innstillinger for å dekryptere filene dine.", "Your download is being prepared. This might take some time if the files are big." => "Nedlastingen din klargjøres. Hvis filene er store kan dette ta litt tid.", -"Error moving file" => "Feil ved flytting av fil", -"Error" => "Feil", "Name" => "Navn", "Size" => "Størrelse", "Modified" => "Endret", diff --git a/apps/files/l10n/nl.php b/apps/files/l10n/nl.php index c617f0bfdde..946c7905b23 100644 --- a/apps/files/l10n/nl.php +++ b/apps/files/l10n/nl.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Delen", "Delete permanently" => "Verwijder definitief", "Rename" => "Hernoem", +"Error moving file" => "Fout bij verplaatsen bestand", +"Error" => "Fout", "Pending" => "In behandeling", "Could not rename file" => "Kon niet hernoemen bestand", -"replaced {new_name} with {old_name}" => "verving {new_name} met {old_name}", -"undo" => "ongedaan maken", "Error deleting file." => "Fout bij verwijderen bestand.", "_%n folder_::_%n folders_" => array("","%n mappen"), "_%n file_::_%n files_" => array("","%n bestanden"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Ongeldige privésleutel voor crypto app. Werk het privésleutel wachtwoord bij in uw persoonlijke instellingen om opnieuw toegang te krijgen tot uw versleutelde bestanden.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Encryptie is uitgeschakeld maar uw bestanden zijn nog steeds versleuteld. Ga naar uw persoonlijke instellingen om uw bestanden te decoderen.", "Your download is being prepared. This might take some time if the files are big." => "Uw download wordt voorbereid. Dit kan enige tijd duren bij grote bestanden.", -"Error moving file" => "Fout bij verplaatsen bestand", -"Error" => "Fout", "Name" => "Naam", "Size" => "Grootte", "Modified" => "Aangepast", diff --git a/apps/files/l10n/nn_NO.php b/apps/files/l10n/nn_NO.php index 4f74167d9ad..bd17fa3386a 100644 --- a/apps/files/l10n/nn_NO.php +++ b/apps/files/l10n/nn_NO.php @@ -27,9 +27,9 @@ $TRANSLATIONS = array( "Share" => "Del", "Delete permanently" => "Slett for godt", "Rename" => "Endra namn", +"Error moving file" => "Feil ved flytting av fil", +"Error" => "Feil", "Pending" => "Under vegs", -"replaced {new_name} with {old_name}" => "bytte ut {new_name} med {old_name}", -"undo" => "angre", "_%n folder_::_%n folders_" => array("%n mappe","%n mapper"), "_%n file_::_%n files_" => array("%n fil","%n filer"), "{dirs} and {files}" => "{dirs} og {files}", @@ -38,8 +38,6 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Lagringa di er nesten full ({usedSpacePercent} %)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Kryptering er skrudd av, men filene dine er enno krypterte. Du kan dekryptera filene i personlege innstillingar.", "Your download is being prepared. This might take some time if the files are big." => "Gjer klar nedlastinga di. Dette kan ta ei stund viss filene er store.", -"Error moving file" => "Feil ved flytting av fil", -"Error" => "Feil", "Name" => "Namn", "Size" => "Storleik", "Modified" => "Endra", diff --git a/apps/files/l10n/oc.php b/apps/files/l10n/oc.php index eb1a9038b08..7a24c81974e 100644 --- a/apps/files/l10n/oc.php +++ b/apps/files/l10n/oc.php @@ -11,12 +11,11 @@ $TRANSLATIONS = array( "File upload is in progress. Leaving the page now will cancel the upload." => "Un amontcargar es a se far. Daissar aquesta pagina ara tamparà lo cargament. ", "Share" => "Parteja", "Rename" => "Torna nomenar", +"Error" => "Error", "Pending" => "Al esperar", -"undo" => "defar", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "Error", "Name" => "Nom", "Size" => "Talha", "Modified" => "Modificat", diff --git a/apps/files/l10n/pa.php b/apps/files/l10n/pa.php index 63fcbe12dda..b18d2071e08 100644 --- a/apps/files/l10n/pa.php +++ b/apps/files/l10n/pa.php @@ -3,11 +3,10 @@ $TRANSLATIONS = array( "Files" => "ਫਾਇਲਾਂ", "Share" => "ਸਾਂਝਾ ਕਰੋ", "Rename" => "ਨਾਂ ਬਦਲੋ", -"undo" => "ਵਾਪਸ", +"Error" => "ਗਲਤੀ", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "ਗਲਤੀ", "Upload" => "ਅੱਪਲੋਡ", "Cancel upload" => "ਅੱਪਲੋਡ ਰੱਦ ਕਰੋ", "Download" => "ਡਾਊਨਲੋਡ", diff --git a/apps/files/l10n/pl.php b/apps/files/l10n/pl.php index 3e93dc881e9..83126b3ea03 100644 --- a/apps/files/l10n/pl.php +++ b/apps/files/l10n/pl.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Udostępnij", "Delete permanently" => "Trwale usuń", "Rename" => "Zmień nazwę", +"Error moving file" => "Błąd prz przenoszeniu pliku", +"Error" => "Błąd", "Pending" => "Oczekujące", "Could not rename file" => "Nie można zmienić nazwy pliku", -"replaced {new_name} with {old_name}" => "zastąpiono {new_name} przez {old_name}", -"undo" => "cofnij", "Error deleting file." => "Błąd podczas usuwania pliku", "_%n folder_::_%n folders_" => array("%n katalog","%n katalogi","%n katalogów"), "_%n file_::_%n files_" => array("%n plik","%n pliki","%n plików"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Klucz prywatny nie jest poprawny! Może Twoje hasło zostało zmienione z zewnątrz. Można zaktualizować hasło klucza prywatnego w ustawieniach osobistych w celu odzyskania dostępu do plików", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Szyfrowanie zostało wyłączone, ale nadal pliki są zaszyfrowane. Przejdź do ustawień osobistych i tam odszyfruj pliki.", "Your download is being prepared. This might take some time if the files are big." => "Pobieranie jest przygotowywane. Może to zająć trochę czasu jeśli pliki są duże.", -"Error moving file" => "Błąd prz przenoszeniu pliku", -"Error" => "Błąd", "Name" => "Nazwa", "Size" => "Rozmiar", "Modified" => "Modyfikacja", diff --git a/apps/files/l10n/pl_PL.php b/apps/files/l10n/pl_PL.php deleted file mode 100644 index b67f67b972e..00000000000 --- a/apps/files/l10n/pl_PL.php +++ /dev/null @@ -1,5 +0,0 @@ - "Zapisz" -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/apps/files/l10n/pt_BR.php b/apps/files/l10n/pt_BR.php index d0c27431daa..48c32e8887f 100644 --- a/apps/files/l10n/pt_BR.php +++ b/apps/files/l10n/pt_BR.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Compartilhar", "Delete permanently" => "Excluir permanentemente", "Rename" => "Renomear", +"Error moving file" => "Erro movendo o arquivo", +"Error" => "Erro", "Pending" => "Pendente", "Could not rename file" => "Não foi possível renomear o arquivo", -"replaced {new_name} with {old_name}" => "Substituído {old_name} por {new_name} ", -"undo" => "desfazer", "Error deleting file." => "Erro eliminando o arquivo.", "_%n folder_::_%n folders_" => array("%n pasta","%n pastas"), "_%n file_::_%n files_" => array("%n arquivo","%n arquivos"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Chave do App de Encriptação é inválida. Por favor, atualize sua senha de chave privada em suas configurações pessoais para recuperar o acesso a seus arquivos criptografados.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Encriptação foi desabilitada mas seus arquivos continuam encriptados. Por favor vá a suas configurações pessoais para descriptar seus arquivos.", "Your download is being prepared. This might take some time if the files are big." => "Seu download está sendo preparado. Isto pode levar algum tempo se os arquivos forem grandes.", -"Error moving file" => "Erro movendo o arquivo", -"Error" => "Erro", "Name" => "Nome", "Size" => "Tamanho", "Modified" => "Modificado", diff --git a/apps/files/l10n/pt_PT.php b/apps/files/l10n/pt_PT.php index 3b3c2f842bd..0afb6b50157 100644 --- a/apps/files/l10n/pt_PT.php +++ b/apps/files/l10n/pt_PT.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "Partilhar", "Delete permanently" => "Eliminar permanentemente", "Rename" => "Renomear", +"Error moving file" => "Erro ao mover o ficheiro", +"Error" => "Erro", "Pending" => "Pendente", "Could not rename file" => "Não pôde renomear o ficheiro", -"replaced {new_name} with {old_name}" => "substituido {new_name} por {old_name}", -"undo" => "desfazer", "Error deleting file." => "Erro ao apagar o ficheiro.", "_%n folder_::_%n folders_" => array("%n pasta","%n pastas"), "_%n file_::_%n files_" => array("%n ficheiro","%n ficheiros"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Chave privada inválida da Aplicação de Encriptação. Por favor atualize a sua senha de chave privada nas definições pessoais, para recuperar o acesso aos seus ficheiros encriptados.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "A encriptação foi desactivada mas os seus ficheiros continuam encriptados. Por favor consulte as suas definições pessoais para desencriptar os ficheiros.", "Your download is being prepared. This might take some time if the files are big." => "O seu download está a ser preparado. Este processo pode demorar algum tempo se os ficheiros forem grandes.", -"Error moving file" => "Erro ao mover o ficheiro", -"Error" => "Erro", "Name" => "Nome", "Size" => "Tamanho", "Modified" => "Modificado", diff --git a/apps/files/l10n/ro.php b/apps/files/l10n/ro.php index 7686025e35c..6cda724df43 100644 --- a/apps/files/l10n/ro.php +++ b/apps/files/l10n/ro.php @@ -4,7 +4,9 @@ $TRANSLATIONS = array( "Could not move %s" => "Nu se poate muta %s", "File name cannot be empty." => "Numele fișierului nu poate rămâne gol.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nume nevalide, '\\', '/', '<', '>', ':', '\"', '|', '?' și '*' nu sunt permise.", +"Error while downloading %s to %s" => "Eroare la descarcarea %s in %s", "Error when creating the file" => "Eroare la crearea fisierului", +"Folder name cannot be empty." => "Numele folderului nu poate fi liber.", "Error when creating the folder" => "Eroare la crearea folderului", "Unable to set upload directory." => "Imposibil de a seta directorul pentru incărcare.", "Invalid Token" => "Jeton Invalid", @@ -32,10 +34,10 @@ $TRANSLATIONS = array( "Share" => "Partajează", "Delete permanently" => "Șterge permanent", "Rename" => "Redenumește", +"Error moving file" => "Eroare la mutarea fișierului", +"Error" => "Eroare", "Pending" => "În așteptare", "Could not rename file" => "Nu s-a putut redenumi fisierul", -"replaced {new_name} with {old_name}" => "{new_name} a fost înlocuit cu {old_name}", -"undo" => "desfă", "_%n folder_::_%n folders_" => array("%n director","%n directoare","%n directoare"), "_%n file_::_%n files_" => array("%n fișier","%n fișiere","%n fișiere"), "{dirs} and {files}" => "{dirs} și {files}", @@ -44,8 +46,6 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Spațiul de stocare este aproape plin ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "criptarea a fost disactivata dar fisierele sant inca criptate.va rog intrati in setarile personale pentru a decripta fisierele", "Your download is being prepared. This might take some time if the files are big." => "Se pregătește descărcarea. Aceasta poate dura ceva timp dacă fișierele sunt mari.", -"Error moving file" => "Eroare la mutarea fișierului", -"Error" => "Eroare", "Name" => "Nume", "Size" => "Mărime", "Modified" => "Modificat", diff --git a/apps/files/l10n/ru.php b/apps/files/l10n/ru.php index 2c0335f3cc3..17f06c6a200 100644 --- a/apps/files/l10n/ru.php +++ b/apps/files/l10n/ru.php @@ -3,7 +3,9 @@ $TRANSLATIONS = array( "Could not move %s - File with this name already exists" => "Невозможно переместить %s - файл с таким именем уже существует", "Could not move %s" => "Невозможно переместить %s", "File name cannot be empty." => "Имя файла не может быть пустым.", +"\"%s\" is an invalid file name." => "\"%s\" это не правильное имя файла.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Неправильное имя: символы '\\', '/', '<', '>', ':', '\"', '|', '?' и '*' недопустимы.", +"The target folder has been moved or deleted." => "Целевой каталог был перемещен или удален.", "The name %s is already used in the folder %s. Please choose a different name." => "Имя %s уже используется для каталога %s. Пожалуйста, выберите другое имя.", "Not a valid source" => "Неправильный источник", "Server is not allowed to open URLs, please check the server configuration" => "Сервер не позволяет открывать URL-адреса, пожалуйста, проверьте настройки сервера", @@ -27,6 +29,8 @@ $TRANSLATIONS = array( "Invalid directory." => "Неверный каталог.", "Files" => "Файлы", "Unable to upload {filename} as it is a directory or has 0 bytes" => "Невозможно загрузить {filename}, так как это либо каталог, либо файл нулевого размера", +"Total file size {size1} exceeds upload limit {size2}" => "Полный размер файла {size1} превышает лимит по загрузке {size2}", +"Not enough free space, you are uploading {size1} but only {size2} is left" => "Не достаточно свободного места, Вы загружаете {size1} но осталось только {size2}", "Upload cancelled." => "Загрузка отменена.", "Could not get result from server." => "Не удалось получить ответ от сервера.", "File upload is in progress. Leaving the page now will cancel the upload." => "Идёт загрузка файла. Покинув страницу, вы прервёте загрузку.", @@ -39,23 +43,22 @@ $TRANSLATIONS = array( "Share" => "Открыть доступ", "Delete permanently" => "Удалить окончательно", "Rename" => "Переименовать", +"Error moving file" => "Ошибка при перемещении файла", +"Error" => "Ошибка", "Pending" => "Ожидание", "Could not rename file" => "Не удалось переименовать файл", -"replaced {new_name} with {old_name}" => "заменено {new_name} на {old_name}", -"undo" => "отмена", "Error deleting file." => "Ошибка при удалении файла.", "_%n folder_::_%n folders_" => array("%n каталог","%n каталога","%n каталогов"), "_%n file_::_%n files_" => array("%n файл","%n файла","%n файлов"), "{dirs} and {files}" => "{dirs} и {files}", "_Uploading %n file_::_Uploading %n files_" => array("Закачка %n файла","Закачка %n файлов","Закачка %n файлов"), +"\"{name}\" is an invalid file name." => "\"{name}\" это не правильное имя файла.", "Your storage is full, files can not be updated or synced anymore!" => "Ваше хранилище заполнено, произведите очистку перед загрузкой новых файлов.", "Your storage is almost full ({usedSpacePercent}%)" => "Ваше хранилище почти заполнено ({usedSpacePercent}%)", "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "Приложение для шифрования активно, но ваши ключи не инициализированы, пожалуйста, перелогиньтесь", "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Закрытый ключ приложения шифрования недействителен. Обновите закрытый ключ в личных настройках, чтобы восстановить доступ к зашифрованным файлам.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Шифрование было отключено, но ваши файлы остались зашифрованными. Зайдите на страницу личных настроек для того, чтобы расшифровать их.", "Your download is being prepared. This might take some time if the files are big." => "Идёт подготовка к скачиванию. Это может занять некоторое время, если файлы большого размера.", -"Error moving file" => "Ошибка при перемещении файла", -"Error" => "Ошибка", "Name" => "Имя", "Size" => "Размер", "Modified" => "Дата изменения", diff --git a/apps/files/l10n/si_LK.php b/apps/files/l10n/si_LK.php index 44decfef1b0..a2809ee2f5d 100644 --- a/apps/files/l10n/si_LK.php +++ b/apps/files/l10n/si_LK.php @@ -12,11 +12,10 @@ $TRANSLATIONS = array( "File upload is in progress. Leaving the page now will cancel the upload." => "උඩුගතකිරීමක් සිදුවේ. පිටුව හැර යාමෙන් එය නැවතෙනු ඇත", "Share" => "බෙදා හදා ගන්න", "Rename" => "නැවත නම් කරන්න", -"undo" => "නිෂ්ප්‍රභ කරන්න", +"Error" => "දෝෂයක්", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "දෝෂයක්", "Name" => "නම", "Size" => "ප්‍රමාණය", "Modified" => "වෙනස් කළ", diff --git a/apps/files/l10n/sk_SK.php b/apps/files/l10n/sk_SK.php index e80ca0186cb..cffb89c294d 100644 --- a/apps/files/l10n/sk_SK.php +++ b/apps/files/l10n/sk_SK.php @@ -3,7 +3,9 @@ $TRANSLATIONS = array( "Could not move %s - File with this name already exists" => "Nie je možné presunúť %s - súbor s týmto menom už existuje", "Could not move %s" => "Nie je možné presunúť %s", "File name cannot be empty." => "Meno súboru nemôže byť prázdne", +"\"%s\" is an invalid file name." => "\"%s\" je neplatné meno súboru.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nesprávne meno, '\\', '/', '<', '>', ':', '\"', '|', '?' a '*' nie sú povolené hodnoty.", +"The target folder has been moved or deleted." => "Cieľový priečinok bol premiestnený alebo odstránený.", "The name %s is already used in the folder %s. Please choose a different name." => "Názov %s už používa priečinok s%. Prosím zvoľte iný názov.", "Not a valid source" => "Neplatný zdroj", "Server is not allowed to open URLs, please check the server configuration" => "Server nie je oprávnený otvárať adresy URL. Overte nastavenia servera.", @@ -27,6 +29,8 @@ $TRANSLATIONS = array( "Invalid directory." => "Neplatný priečinok.", "Files" => "Súbory", "Unable to upload {filename} as it is a directory or has 0 bytes" => "Nemožno nahrať súbor {filename}, pretože je to priečinok, alebo má 0 bitov", +"Total file size {size1} exceeds upload limit {size2}" => "Celková veľkosť súboru {size1} prekračuje upload limit {size2}", +"Not enough free space, you are uploading {size1} but only {size2} is left" => "Nie je dostatok voľného miesta, chcete nahrať {size1} ale k dispozíciji je len {size2}", "Upload cancelled." => "Odosielanie zrušené.", "Could not get result from server." => "Nepodarilo sa dostať výsledky zo servera.", "File upload is in progress. Leaving the page now will cancel the upload." => "Opustenie stránky zruší práve prebiehajúce odosielanie súboru.", @@ -39,23 +43,22 @@ $TRANSLATIONS = array( "Share" => "Zdieľať", "Delete permanently" => "Zmazať trvalo", "Rename" => "Premenovať", +"Error moving file" => "Chyba pri presúvaní súboru", +"Error" => "Chyba", "Pending" => "Prebieha", "Could not rename file" => "Nemožno premenovať súbor", -"replaced {new_name} with {old_name}" => "prepísaný {new_name} súborom {old_name}", -"undo" => "vrátiť", "Error deleting file." => "Chyba pri mazaní súboru.", "_%n folder_::_%n folders_" => array("%n priečinok","%n priečinky","%n priečinkov"), "_%n file_::_%n files_" => array("%n súbor","%n súbory","%n súborov"), "{dirs} and {files}" => "{dirs} a {files}", "_Uploading %n file_::_Uploading %n files_" => array("Nahrávam %n súbor","Nahrávam %n súbory","Nahrávam %n súborov"), +"\"{name}\" is an invalid file name." => "\"{name}\" je neplatné meno súboru.", "Your storage is full, files can not be updated or synced anymore!" => "Vaše úložisko je plné. Súbory nemožno aktualizovať ani synchronizovať!", "Your storage is almost full ({usedSpacePercent}%)" => "Vaše úložisko je takmer plné ({usedSpacePercent}%)", "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "Aplikácia na šifrovanie je zapnutá, ale vaše kľúče nie sú inicializované. Odhláste sa a znovu sa prihláste.", "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Chybný súkromný kľúč na šifrovanie aplikácií. Zaktualizujte si heslo súkromného kľúča v svojom osobnom nastavení, aby ste znovu získali prístup k svojim zašifrovaným súborom.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Šifrovanie bolo zakázané, ale vaše súbory sú stále zašifrované. Prosím, choďte do osobného nastavenia pre dešifrovanie súborov.", "Your download is being prepared. This might take some time if the files are big." => "Vaše sťahovanie sa pripravuje. Ak sú sťahované súbory veľké, môže to chvíľu trvať.", -"Error moving file" => "Chyba pri presúvaní súboru", -"Error" => "Chyba", "Name" => "Názov", "Size" => "Veľkosť", "Modified" => "Upravené", diff --git a/apps/files/l10n/sl.php b/apps/files/l10n/sl.php index ae54ace12da..fcb358bd7bd 100644 --- a/apps/files/l10n/sl.php +++ b/apps/files/l10n/sl.php @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Souporaba", "Delete permanently" => "Izbriši dokončno", "Rename" => "Preimenuj", +"Error moving file" => "Napaka premikanja datoteke", +"Error" => "Napaka", "Pending" => "V čakanju ...", "Could not rename file" => "Ni mogoče preimenovati datoteke", -"replaced {new_name} with {old_name}" => "preimenovano ime {new_name} z imenom {old_name}", -"undo" => "razveljavi", "Error deleting file." => "Napaka brisanja datoteke.", "_%n folder_::_%n folders_" => array("%n mapa","%n mapi","%n mape","%n map"), "_%n file_::_%n files_" => array("%n datoteka","%n datoteki","%n datoteke","%n datotek"), @@ -59,8 +59,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Ni ustreznega osebnega ključa za program za šifriranje. Posodobite osebni ključ za dostop do šifriranih datotek med nastavitvami.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Šifriranje je onemogočeno, datoteke pa so še vedno šifrirane. Odšifrirajte jih med nastavitvami.", "Your download is being prepared. This might take some time if the files are big." => "Postopek priprave datoteke za prejem je lahko dolgotrajen, kadar je datoteka zelo velika.", -"Error moving file" => "Napaka premikanja datoteke", -"Error" => "Napaka", "Name" => "Ime", "Size" => "Velikost", "Modified" => "Spremenjeno", diff --git a/apps/files/l10n/sq.php b/apps/files/l10n/sq.php index 073f2def624..ade4f769faa 100644 --- a/apps/files/l10n/sq.php +++ b/apps/files/l10n/sq.php @@ -25,9 +25,9 @@ $TRANSLATIONS = array( "Share" => "Ndaj", "Delete permanently" => "Fshi përfundimisht", "Rename" => "Riemëro", +"Error moving file" => "Gabim lëvizjen dokumentave", +"Error" => "Gabim", "Pending" => "Në vijim", -"replaced {new_name} with {old_name}" => "u zëvendësua {new_name} me {old_name}", -"undo" => "anullo", "_%n folder_::_%n folders_" => array("%n dosje","%n dosje"), "_%n file_::_%n files_" => array("%n skedar","%n skedarë"), "{dirs} and {files}" => "{dirs} dhe {files}", @@ -36,8 +36,6 @@ $TRANSLATIONS = array( "Your storage is almost full ({usedSpacePercent}%)" => "Hapsira juaj e arkivimit është pothuajse në fund ({usedSpacePercent}%)", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Kodifikimi u çaktivizua por skedarët tuaj vazhdojnë të jenë të kodifikuar. Ju lutem shkoni tek parametrat personale për të dekodifikuar skedarët tuaj.", "Your download is being prepared. This might take some time if the files are big." => "Shkarkimi juaj është duke u përgatitur. Kjo mund të kërkojë kohë nëse skedarët janë të mëdhenj.", -"Error moving file" => "Gabim lëvizjen dokumentave", -"Error" => "Gabim", "Name" => "Emri", "Size" => "Madhësia", "Modified" => "Ndryshuar", diff --git a/apps/files/l10n/sr.php b/apps/files/l10n/sr.php index 2a1b478b2ae..44669e8167a 100644 --- a/apps/files/l10n/sr.php +++ b/apps/files/l10n/sr.php @@ -21,16 +21,14 @@ $TRANSLATIONS = array( "Share" => "Дели", "Delete permanently" => "Обриши за стално", "Rename" => "Преименуј", +"Error" => "Грешка", "Pending" => "На чекању", -"replaced {new_name} with {old_name}" => "замењено {new_name} са {old_name}", -"undo" => "опозови", "_%n folder_::_%n folders_" => array("","",""), "_%n file_::_%n files_" => array("","",""), "_Uploading %n file_::_Uploading %n files_" => array("","",""), "Your storage is full, files can not be updated or synced anymore!" => "Ваше складиште је пуно. Датотеке више не могу бити ажуриране ни синхронизоване.", "Your storage is almost full ({usedSpacePercent}%)" => "Ваше складиште је скоро па пуно ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "Припремам преузимање. Ово може да потраје ако су датотеке велике.", -"Error" => "Грешка", "Name" => "Име", "Size" => "Величина", "Modified" => "Измењено", diff --git a/apps/files/l10n/sr@latin.php b/apps/files/l10n/sr@latin.php index 67bf30d8606..a5c74860f78 100644 --- a/apps/files/l10n/sr@latin.php +++ b/apps/files/l10n/sr@latin.php @@ -8,10 +8,10 @@ $TRANSLATIONS = array( "Files" => "Fajlovi", "Share" => "Podeli", "Rename" => "Preimenij", +"Error" => "Greška", "_%n folder_::_%n folders_" => array("","",""), "_%n file_::_%n files_" => array("","",""), "_Uploading %n file_::_Uploading %n files_" => array("","",""), -"Error" => "Greška", "Name" => "Ime", "Size" => "Veličina", "Modified" => "Zadnja izmena", diff --git a/apps/files/l10n/sv.php b/apps/files/l10n/sv.php index fa88a1e966d..f420216228c 100644 --- a/apps/files/l10n/sv.php +++ b/apps/files/l10n/sv.php @@ -3,9 +3,12 @@ $TRANSLATIONS = array( "Could not move %s - File with this name already exists" => "Kunde inte flytta %s - Det finns redan en fil med detta namn", "Could not move %s" => "Kan inte flytta %s", "File name cannot be empty." => "Filnamn kan inte vara tomt.", +"\"%s\" is an invalid file name." => "\"%s\" är ett ogiltigt filnamn.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ogiltigt namn, '\\', '/', '<', '>', ':', '\"', '|', '?' och '*' är inte tillåtet.", +"The target folder has been moved or deleted." => "Målmappen har flyttats eller tagits bort.", "The name %s is already used in the folder %s. Please choose a different name." => "Namnet %s används redan i katalogen %s. Välj ett annat namn.", "Not a valid source" => "Inte en giltig källa", +"Server is not allowed to open URLs, please check the server configuration" => "Servern är inte tillåten att öppna URL:er, vänligen kontrollera server konfigurationen", "Error while downloading %s to %s" => "Fel under nerladdning från %s till %s", "Error when creating the file" => "Fel under skapande utav filen", "Folder name cannot be empty." => "Katalognamn kan ej vara tomt.", @@ -26,6 +29,8 @@ $TRANSLATIONS = array( "Invalid directory." => "Felaktig mapp.", "Files" => "Filer", "Unable to upload {filename} as it is a directory or has 0 bytes" => "Kan inte ladda upp {filename} eftersom den antingen är en mapp eller har 0 bytes.", +"Total file size {size1} exceeds upload limit {size2}" => "Totala filstorleken {size1} överskrider uppladdningsgränsen {size2}", +"Not enough free space, you are uploading {size1} but only {size2} is left" => "Inte tillräckligt med ledigt utrymme, du laddar upp {size1} men endast {size2} finns kvar.", "Upload cancelled." => "Uppladdning avbruten.", "Could not get result from server." => "Gick inte att hämta resultat från server.", "File upload is in progress. Leaving the page now will cancel the upload." => "Filuppladdning pågår. Lämnar du sidan så avbryts uppladdningen.", @@ -34,26 +39,26 @@ $TRANSLATIONS = array( "{new_name} already exists" => "{new_name} finns redan", "Could not create file" => "Kunde ej skapa fil", "Could not create folder" => "Kunde ej skapa katalog", +"Error fetching URL" => "Fel vid hämtning av URL", "Share" => "Dela", "Delete permanently" => "Radera permanent", "Rename" => "Byt namn", +"Error moving file" => "Fel uppstod vid flyttning av fil", +"Error" => "Fel", "Pending" => "Väntar", "Could not rename file" => "Kan ej byta filnamn", -"replaced {new_name} with {old_name}" => "ersatt {new_name} med {old_name}", -"undo" => "ångra", "Error deleting file." => "Kunde inte ta bort filen.", "_%n folder_::_%n folders_" => array("%n mapp","%n mappar"), "_%n file_::_%n files_" => array("%n fil","%n filer"), "{dirs} and {files}" => "{dirs} och {files}", "_Uploading %n file_::_Uploading %n files_" => array("Laddar upp %n fil","Laddar upp %n filer"), +"\"{name}\" is an invalid file name." => "\"{name}\" är ett ogiltligt filnamn.", "Your storage is full, files can not be updated or synced anymore!" => "Ditt lagringsutrymme är fullt, filer kan inte längre uppdateras eller synkroniseras!", "Your storage is almost full ({usedSpacePercent}%)" => "Ditt lagringsutrymme är nästan fullt ({usedSpacePercent}%)", "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "Krypteringsprogrammet är aktiverat men dina nycklar är inte initierade. Vänligen logga ut och in igen", "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Ogiltig privat nyckel i krypteringsprogrammet. Vänligen uppdatera lösenordet till din privata nyckel under dina personliga inställningar för att återfå tillgång till dina krypterade filer.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Kryptering inaktiverades men dina filer är fortfarande krypterade. Vänligen gå till sidan för dina personliga inställningar för att dekryptera dina filer.", "Your download is being prepared. This might take some time if the files are big." => "Din nedladdning förbereds. Det kan ta tid om det är stora filer.", -"Error moving file" => "Fel uppstod vid flyttning av fil", -"Error" => "Fel", "Name" => "Namn", "Size" => "Storlek", "Modified" => "Ändrad", @@ -69,6 +74,7 @@ $TRANSLATIONS = array( "Maximum input size for ZIP files" => "Största tillåtna storlek för ZIP-filer", "Save" => "Spara", "New" => "Ny", +"New text file" => "Ny textfil", "Text file" => "Textfil", "New folder" => "Ny mapp", "Folder" => "Mapp", diff --git a/apps/files/l10n/ta_LK.php b/apps/files/l10n/ta_LK.php index c0589feecea..257aacf1471 100644 --- a/apps/files/l10n/ta_LK.php +++ b/apps/files/l10n/ta_LK.php @@ -14,13 +14,11 @@ $TRANSLATIONS = array( "{new_name} already exists" => "{new_name} ஏற்கனவே உள்ளது", "Share" => "பகிர்வு", "Rename" => "பெயர்மாற்றம்", +"Error" => "வழு", "Pending" => "நிலுவையிலுள்ள", -"replaced {new_name} with {old_name}" => "{new_name} ஆனது {old_name} இனால் மாற்றப்பட்டது", -"undo" => "முன் செயல் நீக்கம் ", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "வழு", "Name" => "பெயர்", "Size" => "அளவு", "Modified" => "மாற்றப்பட்டது", diff --git a/apps/files/l10n/te.php b/apps/files/l10n/te.php index 155e4b5c201..b2cf4c01d8a 100644 --- a/apps/files/l10n/te.php +++ b/apps/files/l10n/te.php @@ -1,10 +1,10 @@ "శాశ్వతంగా తొలగించు", +"Error" => "పొరపాటు", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), "_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "పొరపాటు", "Name" => "పేరు", "Size" => "పరిమాణం", "Save" => "భద్రపరచు", diff --git a/apps/files/l10n/th_TH.php b/apps/files/l10n/th_TH.php index 110b84cad5e..8f5f15f2a34 100644 --- a/apps/files/l10n/th_TH.php +++ b/apps/files/l10n/th_TH.php @@ -20,16 +20,14 @@ $TRANSLATIONS = array( "{new_name} already exists" => "{new_name} มีอยู่แล้วในระบบ", "Share" => "แชร์", "Rename" => "เปลี่ยนชื่อ", +"Error" => "ข้อผิดพลาด", "Pending" => "อยู่ระหว่างดำเนินการ", -"replaced {new_name} with {old_name}" => "แทนที่ {new_name} ด้วย {old_name} แล้ว", -"undo" => "เลิกทำ", "_%n folder_::_%n folders_" => array(""), "_%n file_::_%n files_" => array(""), "_Uploading %n file_::_Uploading %n files_" => array(""), "Your storage is full, files can not be updated or synced anymore!" => "พื้นที่จัดเก็บข้อมูลของคุณเต็มแล้ว ไม่สามารถอัพเดทหรือผสานไฟล์ต่างๆได้อีกต่อไป", "Your storage is almost full ({usedSpacePercent}%)" => "พื้นที่จัดเก็บข้อมูลของคุณใกล้เต็มแล้ว ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "กำลังเตรียมดาวน์โหลดข้อมูล หากไฟล์มีขนาดใหญ่ อาจใช้เวลาสักครู่", -"Error" => "ข้อผิดพลาด", "Name" => "ชื่อ", "Size" => "ขนาด", "Modified" => "แก้ไขแล้ว", diff --git a/apps/files/l10n/tr.php b/apps/files/l10n/tr.php index a2570e002ac..87c664cc171 100644 --- a/apps/files/l10n/tr.php +++ b/apps/files/l10n/tr.php @@ -29,7 +29,7 @@ $TRANSLATIONS = array( "Invalid directory." => "Geçersiz dizin.", "Files" => "Dosyalar", "Unable to upload {filename} as it is a directory or has 0 bytes" => "Bir dizin veya 0 bayt olduğundan {filename} yüklenemedi", -"Total file size {size1} exceeds upload limit {size2}" => "Toplam dosya boyutu {size1} gönderme sınırını {size2} aşıyor", +"Total file size {size1} exceeds upload limit {size2}" => "Toplam dosya boyutu {size1}, {size2} gönderme sınırını aşıyor", "Not enough free space, you are uploading {size1} but only {size2} is left" => "Yeterince boş alan yok. Gönderdiğiniz boyut {size1} ancak {size2} alan mevcut", "Upload cancelled." => "Yükleme iptal edildi.", "Could not get result from server." => "Sunucudan sonuç alınamadı.", @@ -43,10 +43,10 @@ $TRANSLATIONS = array( "Share" => "Paylaş", "Delete permanently" => "Kalıcı olarak sil", "Rename" => "İsim değiştir.", +"Error moving file" => "Dosya taşıma hatası", +"Error" => "Hata", "Pending" => "Bekliyor", "Could not rename file" => "Dosya adlandırılamadı", -"replaced {new_name} with {old_name}" => "{new_name} ismi {old_name} ile değiştirildi", -"undo" => "geri al", "Error deleting file." => "Dosya silinirken hata.", "_%n folder_::_%n folders_" => array("%n dizin","%n dizin"), "_%n file_::_%n files_" => array("%n dosya","%n dosya"), @@ -59,12 +59,10 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Şifreleme Uygulaması için geçersiz özel anahtar. Lütfen şifreli dosyalarınıza erişimi tekrar kazanabilmek için kişisel ayarlarınızdan özel anahtar parolanızı güncelleyin.", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Şifreleme işlemi durduruldu ancak dosyalarınız şifreli. Dosyalarınızın şifresini kaldırmak için lütfen kişisel ayarlar kısmına geçin.", "Your download is being prepared. This might take some time if the files are big." => "İndirmeniz hazırlanıyor. Dosya büyük ise biraz zaman alabilir.", -"Error moving file" => "Dosya taşıma hatası", -"Error" => "Hata", "Name" => "İsim", "Size" => "Boyut", "Modified" => "Değiştirilme", -"Invalid folder name. Usage of 'Shared' is reserved." => "Geçersiz dizin adı. 'Shared' ismi ayrılmıştır.", +"Invalid folder name. Usage of 'Shared' is reserved." => "Geçersiz klasör adı. 'Shared' ismi ayrılmıştır.", "%s could not be renamed" => "%s yeniden adlandırılamadı", "Upload" => "Yükle", "File handling" => "Dosya işlemleri", diff --git a/apps/files/l10n/ug.php b/apps/files/l10n/ug.php index ee188d927ef..13354c153b2 100644 --- a/apps/files/l10n/ug.php +++ b/apps/files/l10n/ug.php @@ -13,12 +13,11 @@ $TRANSLATIONS = array( "Share" => "ھەمبەھىر", "Delete permanently" => "مەڭگۈلۈك ئۆچۈر", "Rename" => "ئات ئۆزگەرت", +"Error" => "خاتالىق", "Pending" => "كۈتۈۋاتىدۇ", -"undo" => "يېنىۋال", "_%n folder_::_%n folders_" => array(""), "_%n file_::_%n files_" => array(""), "_Uploading %n file_::_Uploading %n files_" => array(""), -"Error" => "خاتالىق", "Name" => "ئاتى", "Size" => "چوڭلۇقى", "Modified" => "ئۆزگەرتكەن", diff --git a/apps/files/l10n/uk.php b/apps/files/l10n/uk.php index b74126c446d..905d27c3ee2 100644 --- a/apps/files/l10n/uk.php +++ b/apps/files/l10n/uk.php @@ -26,18 +26,16 @@ $TRANSLATIONS = array( "Share" => "Поділитися", "Delete permanently" => "Видалити назавжди", "Rename" => "Перейменувати", +"Error moving file" => "Помилка переміщення файлу", +"Error" => "Помилка", "Pending" => "Очікування", "Could not rename file" => "Неможливо перейменувати файл", -"replaced {new_name} with {old_name}" => "замінено {new_name} на {old_name}", -"undo" => "відмінити", "_%n folder_::_%n folders_" => array("%n тека","%n тека","%n теки"), "_%n file_::_%n files_" => array("%n файл","%n файлів","%n файли"), "_Uploading %n file_::_Uploading %n files_" => array("","",""), "Your storage is full, files can not be updated or synced anymore!" => "Ваше сховище переповнене, файли більше не можуть бути оновлені або синхронізовані !", "Your storage is almost full ({usedSpacePercent}%)" => "Ваше сховище майже повне ({usedSpacePercent}%)", "Your download is being prepared. This might take some time if the files are big." => "Ваше завантаження готується. Це може зайняти деякий час, якщо файли завеликі.", -"Error moving file" => "Помилка переміщення файлу", -"Error" => "Помилка", "Name" => "Ім'я", "Size" => "Розмір", "Modified" => "Змінено", diff --git a/apps/files/l10n/ur_PK.php b/apps/files/l10n/ur_PK.php index 3e13a7f516d..b9548acde92 100644 --- a/apps/files/l10n/ur_PK.php +++ b/apps/files/l10n/ur_PK.php @@ -1,8 +1,8 @@ "ایرر", "_%n folder_::_%n folders_" => array("",""), "_%n file_::_%n files_" => array("",""), -"_Uploading %n file_::_Uploading %n files_" => array("",""), -"Error" => "ایرر" +"_Uploading %n file_::_Uploading %n files_" => array("","") ); $PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files/l10n/vi.php b/apps/files/l10n/vi.php index 8812bb1b209..55f9bd25942 100644 --- a/apps/files/l10n/vi.php +++ b/apps/files/l10n/vi.php @@ -37,10 +37,10 @@ $TRANSLATIONS = array( "Share" => "Chia sẻ", "Delete permanently" => "Xóa vĩnh vễn", "Rename" => "Sửa tên", +"Error moving file" => "Lỗi di chuyển tập tin", +"Error" => "Lỗi", "Pending" => "Đang chờ", "Could not rename file" => "Không thể đổi tên file", -"replaced {new_name} with {old_name}" => "đã thay thế {new_name} bằng {old_name}", -"undo" => "lùi lại", "Error deleting file." => "Lỗi xóa file,", "_%n folder_::_%n folders_" => array("%n thư mục"), "_%n file_::_%n files_" => array("%n tập tin"), @@ -51,8 +51,6 @@ $TRANSLATIONS = array( "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "Ứng dụng mã hóa đã được kích hoạt nhưng bạn chưa khởi tạo khóa. Vui lòng đăng xuất ra và đăng nhập lại", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Mã hóa đã bị vô hiệu nhưng những tập tin của bạn vẫn được mã hóa. Vui lòng vào phần thiết lập cá nhân để giải mã chúng.", "Your download is being prepared. This might take some time if the files are big." => "Your download is being prepared. This might take some time if the files are big.", -"Error moving file" => "Lỗi di chuyển tập tin", -"Error" => "Lỗi", "Name" => "Tên", "Size" => "Kích cỡ", "Modified" => "Thay đổi", diff --git a/apps/files/l10n/zh_CN.php b/apps/files/l10n/zh_CN.php index 87f8138697e..068f97c1ddf 100644 --- a/apps/files/l10n/zh_CN.php +++ b/apps/files/l10n/zh_CN.php @@ -39,10 +39,10 @@ $TRANSLATIONS = array( "Share" => "分享", "Delete permanently" => "永久删除", "Rename" => "重命名", +"Error moving file" => "移动文件错误", +"Error" => "错误", "Pending" => "等待", "Could not rename file" => "不能重命名文件", -"replaced {new_name} with {old_name}" => "已将 {old_name}替换成 {new_name}", -"undo" => "撤销", "Error deleting file." => "删除文件出错。", "_%n folder_::_%n folders_" => array("%n 文件夹"), "_%n file_::_%n files_" => array("%n个文件"), @@ -54,8 +54,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "无效的私有密钥。请到您的个人配置里去更新私有密钥,来恢复对加密文件的访问。", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "加密是被禁用的,但是您的文件还是被加密了。请到您的个人配置里设置文件加密选项。", "Your download is being prepared. This might take some time if the files are big." => "下载正在准备中。如果文件较大可能会花费一些时间。", -"Error moving file" => "移动文件错误", -"Error" => "错误", "Name" => "名称", "Size" => "大小", "Modified" => "修改日期", diff --git a/apps/files/l10n/zh_HK.php b/apps/files/l10n/zh_HK.php index 4885500ce43..eaa32cd537a 100644 --- a/apps/files/l10n/zh_HK.php +++ b/apps/files/l10n/zh_HK.php @@ -2,10 +2,10 @@ $TRANSLATIONS = array( "Files" => "文件", "Share" => "分享", +"Error" => "錯誤", "_%n folder_::_%n folders_" => array(""), "_%n file_::_%n files_" => array(""), "_Uploading %n file_::_Uploading %n files_" => array(""), -"Error" => "錯誤", "Name" => "名稱", "Upload" => "上傳", "Save" => "儲存", diff --git a/apps/files/l10n/zh_TW.php b/apps/files/l10n/zh_TW.php index caf8b184a35..154efd563fd 100644 --- a/apps/files/l10n/zh_TW.php +++ b/apps/files/l10n/zh_TW.php @@ -37,10 +37,10 @@ $TRANSLATIONS = array( "Share" => "分享", "Delete permanently" => "永久刪除", "Rename" => "重新命名", +"Error moving file" => "移動檔案失敗", +"Error" => "錯誤", "Pending" => "等候中", "Could not rename file" => "無法重新命名", -"replaced {new_name} with {old_name}" => "使用 {new_name} 取代 {old_name}", -"undo" => "復原", "_%n folder_::_%n folders_" => array("%n 個資料夾"), "_%n file_::_%n files_" => array("%n 個檔案"), "{dirs} and {files}" => "{dirs} 和 {files}", @@ -51,8 +51,6 @@ $TRANSLATIONS = array( "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "無效的檔案加密私鑰,請在個人設定中更新您的私鑰密語以存取加密的檔案。", "Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "加密已經被停用,但是您的舊檔案還是處於已加密的狀態,請前往個人設定以解密這些檔案。", "Your download is being prepared. This might take some time if the files are big." => "正在準備您的下載,若您的檔案較大,將會需要更多時間。", -"Error moving file" => "移動檔案失敗", -"Error" => "錯誤", "Name" => "名稱", "Size" => "大小", "Modified" => "修改時間", diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php index fea88faa92a..adfca669577 100644 --- a/apps/files/lib/app.php +++ b/apps/files/lib/app.php @@ -84,25 +84,7 @@ class App { ) { // successful rename $meta = $this->view->getFileInfo($dir . '/' . $newname); - if ($meta['mimetype'] === 'httpd/unix-directory') { - $meta['type'] = 'dir'; - } - else { - $meta['type'] = 'file'; - } - // these need to be set for determineIcon() - $meta['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']); - $meta['directory'] = $dir; - $fileinfo = array( - 'id' => $meta['fileid'], - 'mime' => $meta['mimetype'], - 'size' => $meta['size'], - 'etag' => $meta['etag'], - 'directory' => $meta['directory'], - 'name' => $newname, - 'isPreviewAvailable' => $meta['isPreviewAvailable'], - 'icon' => \OCA\Files\Helper::determineIcon($meta) - ); + $fileinfo = \OCA\Files\Helper::formatFileInfo($meta); $result['success'] = true; $result['data'] = $fileinfo; } else { diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index c41e2d15581..b765fdaf3e3 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -19,11 +19,17 @@ class Helper 'usedSpacePercent' => (int)$storageInfo['relative']); } + /** + * Determine icon for a given file + * + * @param \OC\Files\FileInfo $file file info + * @return string icon URL + */ public static function determineIcon($file) { if($file['type'] === 'dir') { $dir = $file['directory']; $icon = \OC_Helper::mimetypeIcon('dir'); - $absPath = \OC\Files\Filesystem::getView()->getAbsolutePath($dir.'/'.$file['name']); + $absPath = $file->getPath(); $mount = \OC\Files\Filesystem::getMountManager()->find($absPath); if (!is_null($mount)) { $sid = $mount->getStorageId(); @@ -38,11 +44,7 @@ class Helper } } }else{ - if($file['isPreviewAvailable']) { - $pathForPreview = $file['directory'] . '/' . $file['name']; - return \OC_Helper::previewIcon($pathForPreview) . '&c=' . $file['etag']; - } - $icon = \OC_Helper::mimetypeIcon($file['mimetype']); + $icon = \OC_Helper::mimetypeIcon($file->getMimetype()); } return substr($icon, 0, -3) . 'svg'; @@ -69,52 +71,58 @@ class Helper } /** - * Retrieves the contents of the given directory and - * returns it as a sorted array. - * @param string $dir path to the directory - * @return array of files + * Formats the file info to be returned as JSON to the client. + * + * @param \OCP\Files\FileInfo file info + * @return array formatted file info */ - public static function getFiles($dir) { - $content = \OC\Files\Filesystem::getDirectoryContent($dir); - $files = array(); + public static function formatFileInfo($i) { + $entry = array(); - foreach ($content as $i) { - $i['date'] = \OCP\Util::formatDate($i['mtime']); - if ($i['type'] === 'file') { - $fileinfo = pathinfo($i['name']); - $i['basename'] = $fileinfo['filename']; - if (!empty($fileinfo['extension'])) { - $i['extension'] = '.' . $fileinfo['extension']; - } else { - $i['extension'] = ''; - } - } - $i['directory'] = $dir; - $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']); - $i['icon'] = \OCA\Files\Helper::determineIcon($i); - $files[] = $i; + $entry['id'] = $i['fileid']; + $entry['date'] = \OCP\Util::formatDate($i['mtime']); + $entry['mtime'] = $i['mtime'] * 1000; + // only pick out the needed attributes + $entry['icon'] = \OCA\Files\Helper::determineIcon($i); + if (\OC::$server->getPreviewManager()->isMimeSupported($i['mimetype'])) { + $entry['isPreviewAvailable'] = true; + } + $entry['name'] = $i['name']; + $entry['permissions'] = $i['permissions']; + $entry['mimetype'] = $i['mimetype']; + $entry['size'] = $i['size']; + $entry['type'] = $i['type']; + $entry['etag'] = $i['etag']; + if (isset($i['displayname_owner'])) { + $entry['shareOwner'] = $i['displayname_owner']; } + return $entry; + } - usort($files, array('\OCA\Files\Helper', 'fileCmp')); + /** + * Format file info for JSON + * @param \OCP\Files\FileInfo[] $fileInfos file infos + */ + public static function formatFileInfos($fileInfos) { + $files = array(); + foreach ($fileInfos as $i) { + $files[] = self::formatFileInfo($i); + } return $files; } /** - * Splits the given path into a breadcrumb structure. - * @param string $dir path to process - * @return array where each entry is a hash of the absolute - * directory path and its name + * Retrieves the contents of the given directory and + * returns it as a sorted array of FileInfo. + * + * @param string $dir path to the directory + * @return \OCP\Files\FileInfo[] files */ - public static function makeBreadcrumb($dir){ - $breadcrumb = array(); - $pathtohere = ''; - foreach (explode('/', $dir) as $i) { - if ($i !== '') { - $pathtohere .= '/' . $i; - $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i); - } - } - return $breadcrumb; + public static function getFiles($dir) { + $content = \OC\Files\Filesystem::getDirectoryContent($dir); + + usort($content, array('\OCA\Files\Helper', 'fileCmp')); + return $content; } } diff --git a/apps/files/templates/admin.php b/apps/files/templates/admin.php index a5afd55fbc3..5f7d3261d6c 100644 --- a/apps/files/templates/admin.php +++ b/apps/files/templates/admin.php @@ -1,28 +1,26 @@ -
-
-

t('File handling')); ?>

- - - '/> - - (t('max. possible: ')); p($_['maxPossibleUploadSize']) ?>) - -
+ +

t('File handling')); ?>

+ + + '/> + + (t('max. possible: ')); p($_['maxPossibleUploadSize']) ?>) - checked="checked" /> -
+
+ + checked="checked" /> +
- ' - title="t( '0 is unlimited' )); ?>" - disabled="disabled" />
- t( 'Maximum input size for ZIP files' )); ?>
+ ' + title="t( '0 is unlimited' )); ?>" + disabled="disabled" />
+ t( 'Maximum input size for ZIP files' )); ?>
- - -
+ +
diff --git a/apps/files/templates/fileexists.html b/apps/files/templates/fileexists.html index 662177ac7ed..79beccef3e5 100644 --- a/apps/files/templates/fileexists.html +++ b/apps/files/templates/fileexists.html @@ -3,8 +3,8 @@ {what}

- - + +
diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 5b0bad7f341..95edd625cb3 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -1,19 +1,18 @@
- -
+
-
+
-
class="hidden">t('Nothing in here. Upload something!'))?>
+ - - - + -
class="hidden" id='headerName'> + class="hidden" id="headerSize">t('Size')); ?>class="hidden" id="headerDate"> +
@@ -111,7 +109,6 @@ - diff --git a/apps/files/templates/part.breadcrumb.php b/apps/files/templates/part.breadcrumb.php deleted file mode 100644 index 2a0df622767..00000000000 --- a/apps/files/templates/part.breadcrumb.php +++ /dev/null @@ -1,17 +0,0 @@ -
" data-dir=''> - - - - - -
- -
svg" - data-dir=''> - -
- -160) $relative_date_color = 160; - $name = \OCP\Util::encodePath($file['name']); - $directory = \OCP\Util::encodePath($file['directory']); ?> - - data-share-owner="" - - > - - - - - style="background-image:url()" - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - -viewMock->expects($this->any()) ->method('getFileInfo') - ->will($this->returnValue(array( + ->will($this->returnValue(new \OC\Files\FileInfo( + '/test', + null, + '/test', + array( 'fileid' => 123, 'type' => 'dir', 'mimetype' => 'httpd/unix-directory', + 'mtime' => 0, + 'permissions' => 31, 'size' => 18, 'etag' => 'abcdef', 'directory' => '/', 'name' => 'new_name', - ))); + )))); $result = $this->files->rename($dir, $oldname, $newname); $this->assertTrue($result['success']); $this->assertEquals(123, $result['data']['id']); $this->assertEquals('new_name', $result['data']['name']); - $this->assertEquals('/test', $result['data']['directory']); $this->assertEquals(18, $result['data']['size']); - $this->assertEquals('httpd/unix-directory', $result['data']['mime']); + $this->assertEquals('httpd/unix-directory', $result['data']['mimetype']); $icon = \OC_Helper::mimetypeIcon('dir'); $icon = substr($icon, 0, -3) . 'svg'; $this->assertEquals($icon, $result['data']['icon']); - $this->assertFalse($result['data']['isPreviewAvailable']); } /** @@ -148,29 +152,33 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $this->viewMock->expects($this->any()) ->method('getFileInfo') - ->will($this->returnValue(array( + ->will($this->returnValue(new \OC\Files\FileInfo( + '/', + null, + '/', + array( 'fileid' => 123, 'type' => 'dir', 'mimetype' => 'httpd/unix-directory', + 'mtime' => 0, + 'permissions' => 31, 'size' => 18, 'etag' => 'abcdef', 'directory' => '/', 'name' => 'new_name', - ))); + )))); $result = $this->files->rename($dir, $oldname, $newname); $this->assertTrue($result['success']); $this->assertEquals(123, $result['data']['id']); - $this->assertEquals('newname', $result['data']['name']); - $this->assertEquals('/', $result['data']['directory']); + $this->assertEquals('new_name', $result['data']['name']); $this->assertEquals(18, $result['data']['size']); - $this->assertEquals('httpd/unix-directory', $result['data']['mime']); + $this->assertEquals('httpd/unix-directory', $result['data']['mimetype']); $this->assertEquals('abcdef', $result['data']['etag']); $icon = \OC_Helper::mimetypeIcon('dir'); $icon = substr($icon, 0, -3) . 'svg'; $this->assertEquals($icon, $result['data']['icon']); - $this->assertFalse($result['data']['isPreviewAvailable']); } /** diff --git a/apps/files/tests/js/breadcrumbSpec.js b/apps/files/tests/js/breadcrumbSpec.js new file mode 100644 index 00000000000..1bfe5308a27 --- /dev/null +++ b/apps/files/tests/js/breadcrumbSpec.js @@ -0,0 +1,248 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry +* +* 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 . +* +*/ + +/* global BreadCrumb */ +describe('BreadCrumb tests', function() { + describe('Rendering', function() { + var bc; + beforeEach(function() { + bc = new BreadCrumb({ + getCrumbUrl: function(part, index) { + // for testing purposes + return part.dir + '#' + index; + } + }); + }); + afterEach(function() { + bc = null; + }); + it('Renders its own container', function() { + bc.render(); + expect(bc.$el.hasClass('breadcrumb')).toEqual(true); + }); + it('Renders root by default', function() { + var $crumbs; + bc.render(); + $crumbs = bc.$el.find('.crumb'); + expect($crumbs.length).toEqual(1); + expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0'); + expect($crumbs.eq(0).find('img').length).toEqual(1); + expect($crumbs.eq(0).attr('data-dir')).toEqual('/'); + }); + it('Renders root when switching to root', function() { + var $crumbs; + bc.setDirectory('/somedir'); + bc.setDirectory('/'); + $crumbs = bc.$el.find('.crumb'); + expect($crumbs.length).toEqual(1); + expect($crumbs.eq(0).attr('data-dir')).toEqual('/'); + }); + it('Renders last crumb with "last" class', function() { + bc.setDirectory('/abc/def'); + expect(bc.$el.find('.crumb:last').hasClass('last')).toEqual(true); + }); + it('Renders single path section', function() { + var $crumbs; + bc.setDirectory('/somedir'); + $crumbs = bc.$el.find('.crumb'); + expect($crumbs.length).toEqual(2); + expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0'); + expect($crumbs.eq(0).find('img').length).toEqual(1); + expect($crumbs.eq(0).attr('data-dir')).toEqual('/'); + expect($crumbs.eq(1).find('a').attr('href')).toEqual('/somedir#1'); + expect($crumbs.eq(1).find('img').length).toEqual(0); + expect($crumbs.eq(1).attr('data-dir')).toEqual('/somedir'); + }); + it('Renders multiple path sections and special chars', function() { + var $crumbs; + bc.setDirectory('/somedir/with space/abc'); + $crumbs = bc.$el.find('.crumb'); + expect($crumbs.length).toEqual(4); + expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0'); + expect($crumbs.eq(0).find('img').length).toEqual(1); + expect($crumbs.eq(0).attr('data-dir')).toEqual('/'); + + expect($crumbs.eq(1).find('a').attr('href')).toEqual('/somedir#1'); + expect($crumbs.eq(1).find('img').length).toEqual(0); + expect($crumbs.eq(1).attr('data-dir')).toEqual('/somedir'); + + expect($crumbs.eq(2).find('a').attr('href')).toEqual('/somedir/with space#2'); + expect($crumbs.eq(2).find('img').length).toEqual(0); + expect($crumbs.eq(2).attr('data-dir')).toEqual('/somedir/with space'); + + expect($crumbs.eq(3).find('a').attr('href')).toEqual('/somedir/with space/abc#3'); + expect($crumbs.eq(3).find('img').length).toEqual(0); + expect($crumbs.eq(3).attr('data-dir')).toEqual('/somedir/with space/abc'); + }); + }); + describe('Events', function() { + it('Calls onClick handler when clicking on a crumb', function() { + var handler = sinon.stub(); + var bc = new BreadCrumb({ + onClick: handler + }); + bc.setDirectory('/one/two/three/four'); + bc.$el.find('.crumb:eq(3)').click(); + expect(handler.calledOnce).toEqual(true); + expect(handler.getCall(0).thisValue).toEqual(bc.$el.find('.crumb').get(3)); + + handler.reset(); + bc.$el.find('.crumb:eq(0) a').click(); + expect(handler.calledOnce).toEqual(true); + expect(handler.getCall(0).thisValue).toEqual(bc.$el.find('.crumb').get(0)); + }); + it('Calls onDrop handler when dropping on a crumb', function() { + var droppableStub = sinon.stub($.fn, 'droppable'); + var handler = sinon.stub(); + var bc = new BreadCrumb({ + onDrop: handler + }); + bc.setDirectory('/one/two/three/four'); + expect(droppableStub.calledOnce).toEqual(true); + + expect(droppableStub.getCall(0).args[0].drop).toBeDefined(); + // simulate drop + droppableStub.getCall(0).args[0].drop({dummy: true}); + + expect(handler.calledOnce).toEqual(true); + expect(handler.getCall(0).args[0]).toEqual({dummy: true}); + + droppableStub.restore(); + }); + }); + describe('Resizing', function() { + var bc, widthStub, dummyDir, + oldUpdateTotalWidth; + + beforeEach(function() { + dummyDir = '/short name/longer name/looooooooooooonger/even longer long long long longer long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/last one'; + + oldUpdateTotalWidth = BreadCrumb.prototype._updateTotalWidth; + BreadCrumb.prototype._updateTotalWidth = function() { + // need to set display:block for correct offsetWidth (no CSS loaded here) + $('div.crumb').css({ + 'display': 'block', + 'float': 'left' + }); + + return oldUpdateTotalWidth.apply(this, arguments); + }; + + bc = new BreadCrumb(); + widthStub = sinon.stub($.fn, 'width'); + // append dummy navigation and controls + // as they are currently used for measurements + $('#testArea').append( + '', + '
' + ); + + // make sure we know the test screen width + $('#testArea').css('width', 1280); + + // use test area as we need it for measurements + $('#controls').append(bc.$el); + $('#controls').append('
Dummy action with a given width
'); + }); + afterEach(function() { + BreadCrumb.prototype._updateTotalWidth = oldUpdateTotalWidth; + widthStub.restore(); + bc = null; + }); + it('Hides breadcrumbs to fit window', function() { + var $crumbs; + + widthStub.returns(500); + // triggers resize implicitly + bc.setDirectory(dummyDir); + $crumbs = bc.$el.find('.crumb'); + + // first one is always visible + expect($crumbs.eq(0).hasClass('hidden')).toEqual(false); + // second one has ellipsis + expect($crumbs.eq(1).hasClass('hidden')).toEqual(false); + expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1); + // there is only one ellipsis in total + expect($crumbs.find('.ellipsis').length).toEqual(1); + // subsequent elements are hidden + expect($crumbs.eq(2).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(3).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(4).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(5).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(6).hasClass('hidden')).toEqual(false); + }); + it('Updates ellipsis on window size increase', function() { + var $crumbs; + + widthStub.returns(500); + // triggers resize implicitly + bc.setDirectory(dummyDir); + $crumbs = bc.$el.find('.crumb'); + + // simulate increase + $('#testArea').css('width', 1800); + bc.resize(1800); + + // first one is always visible + expect($crumbs.eq(0).hasClass('hidden')).toEqual(false); + // second one has ellipsis + expect($crumbs.eq(1).hasClass('hidden')).toEqual(false); + expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1); + // there is only one ellipsis in total + expect($crumbs.find('.ellipsis').length).toEqual(1); + // subsequent elements are hidden + expect($crumbs.eq(2).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(3).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(4).hasClass('hidden')).toEqual(true); + // the rest is visible + expect($crumbs.eq(5).hasClass('hidden')).toEqual(false); + expect($crumbs.eq(6).hasClass('hidden')).toEqual(false); + }); + it('Updates ellipsis on window size decrease', function() { + var $crumbs; + + $('#testArea').css('width', 2000); + widthStub.returns(2000); + // triggers resize implicitly + bc.setDirectory(dummyDir); + $crumbs = bc.$el.find('.crumb'); + + // simulate decrease + bc.resize(500); + $('#testArea').css('width', 500); + + // first one is always visible + expect($crumbs.eq(0).hasClass('hidden')).toEqual(false); + // second one has ellipsis + expect($crumbs.eq(1).hasClass('hidden')).toEqual(false); + expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1); + // there is only one ellipsis in total + expect($crumbs.find('.ellipsis').length).toEqual(1); + // subsequent elements are hidden + expect($crumbs.eq(2).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(3).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(4).hasClass('hidden')).toEqual(true); + // the rest is visible + expect($crumbs.eq(5).hasClass('hidden')).toEqual(true); + expect($crumbs.eq(6).hasClass('hidden')).toEqual(false); + }); + }); +}); diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js index ef7ddcb874a..3c22c84b866 100644 --- a/apps/files/tests/js/fileactionsSpec.js +++ b/apps/files/tests/js/fileactionsSpec.js @@ -22,6 +22,7 @@ /* global OC, FileActions, FileList */ describe('FileActions tests', function() { var $filesTable; + beforeEach(function() { // init horrible parameters var $body = $('body'); @@ -34,42 +35,83 @@ describe('FileActions tests', function() { $('#dir, #permissions, #filestable').remove(); }); it('calling display() sets file actions', function() { - // note: download_url is actually the link target, not the actual download URL... - var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'}); - - // no actions before call - expect($tr.find('.action[data-action=Download]').length).toEqual(0); - expect($tr.find('.action[data-action=Rename]').length).toEqual(0); - expect($tr.find('.action.delete').length).toEqual(0); + var fileData = { + id: 18, + type: 'file', + name: 'testName.txt', + mimetype: 'plain/text', + size: '1234', + etag: 'a01234c', + mtime: '123456' + }; - FileActions.display($tr.find('td.filename'), true); + // note: FileActions.display() is called implicitly + var $tr = FileList.add(fileData); - // actions defined after cal - expect($tr.find('.action[data-action=Download]').length).toEqual(1); - expect($tr.find('.nametext .action[data-action=Rename]').length).toEqual(1); + // actions defined after call + expect($tr.find('.action.action-download').length).toEqual(1); + expect($tr.find('.action.action-download').attr('data-action')).toEqual('Download'); + expect($tr.find('.nametext .action.action-rename').length).toEqual(1); + expect($tr.find('.nametext .action.action-rename').attr('data-action')).toEqual('Rename'); expect($tr.find('.action.delete').length).toEqual(1); }); it('calling display() twice correctly replaces file actions', function() { - var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'}); + var fileData = { + id: 18, + type: 'file', + name: 'testName.txt', + mimetype: 'plain/text', + size: '1234', + etag: 'a01234c', + mtime: '123456' + }; + var $tr = FileList.add(fileData); FileActions.display($tr.find('td.filename'), true); FileActions.display($tr.find('td.filename'), true); // actions defined after cal - expect($tr.find('.action[data-action=Download]').length).toEqual(1); - expect($tr.find('.nametext .action[data-action=Rename]').length).toEqual(1); + expect($tr.find('.action.action-download').length).toEqual(1); + expect($tr.find('.nametext .action.action-rename').length).toEqual(1); expect($tr.find('.action.delete').length).toEqual(1); }); it('redirects to download URL when clicking download', function() { var redirectStub = sinon.stub(OC, 'redirect'); - // note: download_url is actually the link target, not the actual download URL... - var $tr = FileList.addFile('test download File.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'}); + var fileData = { + id: 18, + type: 'file', + name: 'testName.txt', + mimetype: 'plain/text', + size: '1234', + etag: 'a01234c', + mtime: '123456' + }; + var $tr = FileList.add(fileData); FileActions.display($tr.find('td.filename'), true); - $tr.find('.action[data-action=Download]').click(); + $tr.find('.action-download').click(); expect(redirectStub.calledOnce).toEqual(true); - expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=test%20download%20File.txt'); + expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt'); redirectStub.restore(); }); + it('deletes file when clicking delete', function() { + var deleteStub = sinon.stub(FileList, 'do_delete'); + var fileData = { + id: 18, + type: 'file', + name: 'testName.txt', + mimetype: 'plain/text', + size: '1234', + etag: 'a01234c', + mtime: '123456' + }; + var $tr = FileList.add(fileData); + FileActions.display($tr.find('td.filename'), true); + + $tr.find('.action.delete').click(); + + expect(deleteStub.calledOnce).toEqual(true); + deleteStub.restore(); + }); }); diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 8f4cb86ab4a..ca85a360cf5 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -21,6 +21,9 @@ /* global OC, FileList */ describe('FileList tests', function() { + var testFiles, alertStub, notificationStub, + pushStateStub; + beforeEach(function() { // init horrible parameters var $body = $('body'); @@ -28,45 +31,784 @@ describe('FileList tests', function() { $body.append(''); // dummy files table $body.append('
'); + + // prevents URL changes during tests + pushStateStub = sinon.stub(window.history, 'pushState'); + + alertStub = sinon.stub(OC.dialogs, 'alert'); + notificationStub = sinon.stub(OC.Notification, 'show'); + + // init parameters and test table elements + $('#testArea').append( + '' + + '' + + // dummy controls + '
' + + '
' + + '
' + + '
' + + // dummy table + '' + + '' + + '' + + '
' + + '
Empty content message
' + ); + + testFiles = [{ + id: 1, + type: 'file', + name: 'One.txt', + mimetype: 'text/plain', + size: 12 + }, { + id: 2, + type: 'file', + name: 'Two.jpg', + mimetype: 'image/jpeg', + size: 12049 + }, { + id: 3, + type: 'file', + name: 'Three.pdf', + mimetype: 'application/pdf', + size: 58009 + }, { + id: 4, + type: 'dir', + name: 'somedir', + mimetype: 'httpd/unix-directory', + size: 250 + }]; + + FileList.initialize(); }); afterEach(function() { + testFiles = undefined; + FileList.initialized = false; + FileList.isEmpty = true; + delete FileList._reloadCall; + $('#dir, #permissions, #filestable').remove(); + notificationStub.restore(); + alertStub.restore(); + pushStateStub.restore(); + }); + describe('Getters', function() { + it('Returns the current directory', function() { + $('#dir').val('/one/two/three'); + expect(FileList.getCurrentDirectory()).toEqual('/one/two/three'); + }); + it('Returns the directory permissions as int', function() { + $('#permissions').val('23'); + expect(FileList.getDirectoryPermissions()).toEqual(23); + }); + }); + describe('Adding files', function() { + var clock, now; + beforeEach(function() { + // to prevent date comparison issues + clock = sinon.useFakeTimers(); + now = new Date(); + }); + afterEach(function() { + clock.restore(); + }); + it('generates file element with correct attributes when calling add() with file data', function() { + var fileData = { + id: 18, + type: 'file', + name: 'testName.txt', + mimetype: 'plain/text', + size: '1234', + etag: 'a01234c', + mtime: '123456' + }; + var $tr = FileList.add(fileData); + + expect($tr).toBeDefined(); + expect($tr[0].tagName.toLowerCase()).toEqual('tr'); + expect($tr.attr('data-id')).toEqual('18'); + expect($tr.attr('data-type')).toEqual('file'); + expect($tr.attr('data-file')).toEqual('testName.txt'); + expect($tr.attr('data-size')).toEqual('1234'); + expect($tr.attr('data-etag')).toEqual('a01234c'); + expect($tr.attr('data-permissions')).toEqual('31'); + expect($tr.attr('data-mime')).toEqual('plain/text'); + expect($tr.attr('data-mtime')).toEqual('123456'); + expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt'); + + expect($tr.find('.filesize').text()).toEqual('1 kB'); + expect(FileList.findFileEl('testName.txt')[0]).toEqual($tr[0]); + }); + it('generates dir element with correct attributes when calling add() with dir data', function() { + var fileData = { + id: 19, + type: 'dir', + name: 'testFolder', + mimetype: 'httpd/unix-directory', + size: '1234', + etag: 'a01234c', + mtime: '123456' + }; + var $tr = FileList.add(fileData); + + expect($tr).toBeDefined(); + expect($tr[0].tagName.toLowerCase()).toEqual('tr'); + expect($tr.attr('data-id')).toEqual('19'); + expect($tr.attr('data-type')).toEqual('dir'); + expect($tr.attr('data-file')).toEqual('testFolder'); + expect($tr.attr('data-size')).toEqual('1234'); + expect($tr.attr('data-etag')).toEqual('a01234c'); + expect($tr.attr('data-permissions')).toEqual('31'); + expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); + expect($tr.attr('data-mtime')).toEqual('123456'); + + expect($tr.find('.filesize').text()).toEqual('1 kB'); + + expect(FileList.findFileEl('testFolder')[0]).toEqual($tr[0]); + }); + it('generates file element with default attributes when calling add() with minimal data', function() { + var fileData = { + type: 'file', + name: 'testFile.txt' + }; + + clock.tick(123456); + var $tr = FileList.add(fileData); + + expect($tr).toBeDefined(); + expect($tr[0].tagName.toLowerCase()).toEqual('tr'); + expect($tr.attr('data-id')).toEqual(null); + expect($tr.attr('data-type')).toEqual('file'); + expect($tr.attr('data-file')).toEqual('testFile.txt'); + expect($tr.attr('data-size')).toEqual(null); + expect($tr.attr('data-etag')).toEqual(null); + expect($tr.attr('data-permissions')).toEqual('31'); + expect($tr.attr('data-mime')).toEqual(null); + expect($tr.attr('data-mtime')).toEqual('123456'); + + expect($tr.find('.filesize').text()).toEqual('Pending'); + }); + it('generates dir element with default attributes when calling add() with minimal data', function() { + var fileData = { + type: 'dir', + name: 'testFolder' + }; + clock.tick(123456); + var $tr = FileList.add(fileData); + + expect($tr).toBeDefined(); + expect($tr[0].tagName.toLowerCase()).toEqual('tr'); + expect($tr.attr('data-id')).toEqual(null); + expect($tr.attr('data-type')).toEqual('dir'); + expect($tr.attr('data-file')).toEqual('testFolder'); + expect($tr.attr('data-size')).toEqual(null); + expect($tr.attr('data-etag')).toEqual(null); + expect($tr.attr('data-permissions')).toEqual('31'); + expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); + expect($tr.attr('data-mtime')).toEqual('123456'); + + expect($tr.find('.filesize').text()).toEqual('Pending'); + }); + it('generates file element with zero size when size is explicitly zero', function() { + var fileData = { + type: 'dir', + name: 'testFolder', + size: '0' + }; + var $tr = FileList.add(fileData); + expect($tr.find('.filesize').text()).toEqual('0 B'); + }); + it('adds new file to the end of the list before the summary', function() { + var fileData = { + type: 'file', + name: 'P comes after O.txt' + }; + FileList.setFiles(testFiles); + $tr = FileList.add(fileData); + expect($tr.index()).toEqual(4); + expect($tr.next().hasClass('summary')).toEqual(true); + }); + it('adds new file at correct position in insert mode', function() { + var fileData = { + type: 'file', + name: 'P comes after O.txt' + }; + FileList.setFiles(testFiles); + $tr = FileList.add(fileData, {insert: true}); + // after "One.txt" + expect($tr.index()).toEqual(1); + }); + it('removes empty content message and shows summary when adding first file', function() { + var fileData = { + type: 'file', + name: 'first file.txt', + size: 12 + }; + FileList.setFiles([]); + expect(FileList.isEmpty).toEqual(true); + FileList.add(fileData); + $summary = $('#fileList .summary'); + expect($summary.length).toEqual(1); + // yes, ugly... + expect($summary.find('.info').text()).toEqual('0 folders and 1 file'); + expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(true); + expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false); + expect($summary.find('.filesize').text()).toEqual('12 B'); + expect($('#filestable thead th').hasClass('hidden')).toEqual(false); + expect($('#emptycontent').hasClass('hidden')).toEqual(true); + expect(FileList.isEmpty).toEqual(false); + }); }); - it('generates file element with correct attributes when calling addFile', function() { - var lastMod = new Date(10000); - // note: download_url is actually the link target, not the actual download URL... - var $tr = FileList.addFile('testName.txt', 1234, lastMod, false, false, {download_url: 'test/download/url'}); - - expect($tr).toBeDefined(); - expect($tr[0].tagName.toLowerCase()).toEqual('tr'); - expect($tr.find('a:first').attr('href')).toEqual('test/download/url'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('testName.txt'); - expect($tr.attr('data-size')).toEqual('1234'); - expect($tr.attr('data-permissions')).toEqual('31'); - //expect($tr.attr('data-mime')).toEqual('plain/text'); + describe('Removing files from the list', function() { + it('Removes file from list when calling remove() and updates summary', function() { + var $removedEl; + FileList.setFiles(testFiles); + $removedEl = FileList.remove('One.txt'); + expect($removedEl).toBeDefined(); + expect($removedEl.attr('data-file')).toEqual('One.txt'); + expect($('#fileList tr:not(.summary)').length).toEqual(3); + expect(FileList.findFileEl('One.txt').length).toEqual(0); + + $summary = $('#fileList .summary'); + expect($summary.length).toEqual(1); + expect($summary.find('.info').text()).toEqual('1 folder and 2 files'); + expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false); + expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false); + expect($summary.find('.filesize').text()).toEqual('69 kB'); + expect(FileList.isEmpty).toEqual(false); + }); + it('Shows empty content when removing last file', function() { + FileList.setFiles([testFiles[0]]); + FileList.remove('One.txt'); + expect($('#fileList tr:not(.summary)').length).toEqual(0); + expect(FileList.findFileEl('One.txt').length).toEqual(0); + + $summary = $('#fileList .summary'); + expect($summary.length).toEqual(0); + expect($('#filestable thead th').hasClass('hidden')).toEqual(true); + expect($('#emptycontent').hasClass('hidden')).toEqual(false); + expect(FileList.isEmpty).toEqual(true); + }); }); - it('generates dir element with correct attributes when calling addDir', function() { - var lastMod = new Date(10000); - var $tr = FileList.addDir('testFolder', 1234, lastMod, false); - - expect($tr).toBeDefined(); - expect($tr[0].tagName.toLowerCase()).toEqual('tr'); - expect($tr.attr('data-type')).toEqual('dir'); - expect($tr.attr('data-file')).toEqual('testFolder'); - expect($tr.attr('data-size')).toEqual('1234'); - expect($tr.attr('data-permissions')).toEqual('31'); - //expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); + describe('Deleting files', function() { + function doDelete() { + var request, query; + // note: normally called from FileActions + FileList.do_delete(['One.txt', 'Two.jpg']); + + expect(fakeServer.requests.length).toEqual(1); + request = fakeServer.requests[0]; + expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php'); + + query = fakeServer.requests[0].requestBody; + expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir', files: '["One.txt","Two.jpg"]'}); + } + it('calls delete.php, removes the deleted entries and updates summary', function() { + FileList.setFiles(testFiles); + doDelete(); + + fakeServer.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({status: 'success'}) + ); + + expect(FileList.findFileEl('One.txt').length).toEqual(0); + expect(FileList.findFileEl('Two.jpg').length).toEqual(0); + expect(FileList.findFileEl('Three.pdf').length).toEqual(1); + expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(2); + + $summary = $('#fileList .summary'); + expect($summary.length).toEqual(1); + expect($summary.find('.info').text()).toEqual('1 folder and 1 file'); + expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false); + expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false); + expect($summary.find('.filesize').text()).toEqual('57 kB'); + expect(FileList.isEmpty).toEqual(false); + expect($('#filestable thead th').hasClass('hidden')).toEqual(false); + expect($('#emptycontent').hasClass('hidden')).toEqual(true); + + expect(notificationStub.notCalled).toEqual(true); + }); + it('updates summary when deleting last file', function() { + FileList.setFiles([testFiles[0], testFiles[1]]); + doDelete(); + + fakeServer.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({status: 'success'}) + ); + + expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(0); + + $summary = $('#fileList .summary'); + expect($summary.length).toEqual(0); + expect(FileList.isEmpty).toEqual(true); + expect($('#filestable thead th').hasClass('hidden')).toEqual(true); + expect($('#emptycontent').hasClass('hidden')).toEqual(false); + }); + it('bring back deleted item when delete call failed', function() { + FileList.setFiles(testFiles); + doDelete(); + + fakeServer.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({status: 'error', data: {message: 'WOOT'}}) + ); + + // files are still in the list + expect(FileList.findFileEl('One.txt').length).toEqual(1); + expect(FileList.findFileEl('Two.jpg').length).toEqual(1); + expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(4); + + expect(notificationStub.calledOnce).toEqual(true); + }); + }); + describe('Renaming files', function() { + function doRename() { + var $input, request; + + FileList.setFiles(testFiles); + + // trigger rename prompt + FileList.rename('One.txt'); + $input = FileList.$fileList.find('input.filename'); + $input.val('One_renamed.txt').blur(); + + expect(fakeServer.requests.length).toEqual(1); + var request = fakeServer.requests[0]; + expect(request.url.substr(0, request.url.indexOf('?'))).toEqual(OC.webroot + '/index.php/apps/files/ajax/rename.php'); + expect(OC.parseQueryString(request.url)).toEqual({'dir': '/subdir', newname: 'One_renamed.txt', file: 'One.txt'}); + + // element is renamed before the request finishes + expect(FileList.findFileEl('One.txt').length).toEqual(0); + expect(FileList.findFileEl('One_renamed.txt').length).toEqual(1); + // input is gone + expect(FileList.$fileList.find('input.filename').length).toEqual(0); + } + it('Keeps renamed file entry if rename ajax call suceeded', function() { + doRename(); + + fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ + status: 'success', + data: { + name: 'One_renamed.txt' + } + })); + + // element stays renamed + expect(FileList.findFileEl('One.txt').length).toEqual(0); + expect(FileList.findFileEl('One_renamed.txt').length).toEqual(1); + + expect(alertStub.notCalled).toEqual(true); + }); + it('Reverts file entry if rename ajax call failed', function() { + doRename(); + + fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ + status: 'error', + data: { + message: 'Something went wrong' + } + })); + + // element was reverted + expect(FileList.findFileEl('One.txt').length).toEqual(1); + expect(FileList.findFileEl('One_renamed.txt').length).toEqual(0); + + expect(alertStub.calledOnce).toEqual(true); + }); + it('Correctly updates file link after rename', function() { + var $tr; + doRename(); + + fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ + status: 'success', + data: { + name: 'One_renamed.txt' + } + })); + + $tr = FileList.findFileEl('One_renamed.txt'); + expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=One_renamed.txt'); + }); + // FIXME: fix this in the source code! + xit('Correctly updates file link after rename when path has same name', function() { + var $tr; + // evil case: because of buggy code + $('#dir').val('/One.txt/subdir'); + doRename(); + + fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ + status: 'success', + data: { + name: 'One_renamed.txt' + } + })); + + $tr = FileList.findFileEl('One_renamed.txt'); + expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=One.txt'); + }); + }); + describe('List rendering', function() { + it('renders a list of files using add()', function() { + var addSpy = sinon.spy(FileList, 'add'); + FileList.setFiles(testFiles); + expect(addSpy.callCount).toEqual(4); + expect($('#fileList tr:not(.summary)').length).toEqual(4); + addSpy.restore(); + }); + it('updates summary using the file sizes', function() { + var $summary; + FileList.setFiles(testFiles); + $summary = $('#fileList .summary'); + expect($summary.length).toEqual(1); + expect($summary.find('.info').text()).toEqual('1 folder and 3 files'); + expect($summary.find('.filesize').text()).toEqual('69 kB'); + }); + it('shows headers, summary and hide empty content message after setting files', function(){ + FileList.setFiles(testFiles); + expect($('#filestable thead th').hasClass('hidden')).toEqual(false); + expect($('#emptycontent').hasClass('hidden')).toEqual(true); + expect(FileList.$fileList.find('.summary').length).toEqual(1); + }); + it('hides headers, summary and show empty content message after setting empty file list', function(){ + FileList.setFiles([]); + expect($('#filestable thead th').hasClass('hidden')).toEqual(true); + expect($('#emptycontent').hasClass('hidden')).toEqual(false); + expect(FileList.$fileList.find('.summary').length).toEqual(0); + }); + it('hides headers, empty content message, and summary when list is empty and user has no creation permission', function(){ + $('#permissions').val(0); + FileList.setFiles([]); + expect($('#filestable thead th').hasClass('hidden')).toEqual(true); + expect($('#emptycontent').hasClass('hidden')).toEqual(true); + expect(FileList.$fileList.find('.summary').length).toEqual(0); + }); + it('calling findFileEl() can find existing file element', function() { + FileList.setFiles(testFiles); + expect(FileList.findFileEl('Two.jpg').length).toEqual(1); + }); + it('calling findFileEl() returns empty when file not found in file', function() { + FileList.setFiles(testFiles); + expect(FileList.findFileEl('unexist.dat').length).toEqual(0); + }); + it('only add file if in same current directory', function() { + $('#dir').val('/current dir'); + var fileData = { + type: 'file', + name: 'testFile.txt', + directory: '/current dir' + }; + var $tr = FileList.add(fileData); + expect(FileList.findFileEl('testFile.txt').length).toEqual(1); + }); + it('triggers "fileActionsReady" event after update', function() { + var handler = sinon.stub(); + FileList.$fileList.on('fileActionsReady', handler); + FileList.setFiles(testFiles); + expect(handler.calledOnce).toEqual(true); + }); + it('triggers "updated" event after update', function() { + var handler = sinon.stub(); + FileList.$fileList.on('updated', handler); + FileList.setFiles(testFiles); + expect(handler.calledOnce).toEqual(true); + }); + }); + describe('file previews', function() { + var previewLoadStub; + + function getImageUrl($el) { + // might be slightly different cross-browser + var url = $el.css('background-image'); + var r = url.match(/url\(['"]?([^'")]*)['"]?\)/); + if (!r) { + return url; + } + return r[1]; + } + + beforeEach(function() { + previewLoadStub = sinon.stub(Files, 'lazyLoadPreview'); + }); + afterEach(function() { + previewLoadStub.restore(); + }); + it('renders default icon for file when none provided and no preview is available', function() { + var fileData = { + type: 'file', + name: 'testFile.txt' + }; + var $tr = FileList.add(fileData); + var $td = $tr.find('td.filename'); + expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/file.svg'); + expect(previewLoadStub.notCalled).toEqual(true); + }); + it('renders default icon for dir when none provided and no preview is available', function() { + var fileData = { + type: 'dir', + name: 'test dir' + }; + var $tr = FileList.add(fileData); + var $td = $tr.find('td.filename'); + expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/folder.svg'); + expect(previewLoadStub.notCalled).toEqual(true); + }); + it('renders provided icon for file when provided', function() { + var fileData = { + type: 'file', + name: 'test dir', + icon: OC.webroot + '/core/img/filetypes/application-pdf.svg' + }; + var $tr = FileList.add(fileData); + var $td = $tr.find('td.filename'); + expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg'); + expect(previewLoadStub.notCalled).toEqual(true); + }); + it('renders preview when no icon was provided and preview is available', function() { + var fileData = { + type: 'file', + name: 'test dir', + isPreviewAvailable: true + }; + var $tr = FileList.add(fileData); + var $td = $tr.find('td.filename'); + expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/file.svg'); + expect(previewLoadStub.calledOnce).toEqual(true); + // third argument is callback + previewLoadStub.getCall(0).args[2](OC.webroot + '/somepath.png'); + expect(getImageUrl($td)).toEqual(OC.webroot + '/somepath.png'); + }); + it('renders default file type icon when no icon was provided and no preview is available', function() { + var fileData = { + type: 'file', + name: 'test dir', + isPreviewAvailable: false + }; + var $tr = FileList.add(fileData); + var $td = $tr.find('td.filename'); + expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/file.svg'); + expect(previewLoadStub.notCalled).toEqual(true); + }); + }); + describe('viewer mode', function() { + it('enabling viewer mode hides files table and action buttons', function() { + FileList.setViewerMode(true); + expect($('#filestable').hasClass('hidden')).toEqual(true); + expect($('.actions').hasClass('hidden')).toEqual(true); + expect($('.notCreatable').hasClass('hidden')).toEqual(true); + }); + it('disabling viewer mode restores files table and action buttons', function() { + FileList.setViewerMode(true); + FileList.setViewerMode(false); + expect($('#filestable').hasClass('hidden')).toEqual(false); + expect($('.actions').hasClass('hidden')).toEqual(false); + expect($('.notCreatable').hasClass('hidden')).toEqual(true); + }); + it('disabling viewer mode restores files table and action buttons with correct permissions', function() { + $('#permissions').val(0); + FileList.setViewerMode(true); + FileList.setViewerMode(false); + expect($('#filestable').hasClass('hidden')).toEqual(false); + expect($('.actions').hasClass('hidden')).toEqual(true); + expect($('.notCreatable').hasClass('hidden')).toEqual(false); + }); + }); + describe('loading file list', function() { + beforeEach(function() { + var data = { + status: 'success', + data: { + files: testFiles, + permissions: 31 + } + }; + fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2F(subdir|anothersubdir)/, [ + 200, { + "Content-Type": "application/json" + }, + JSON.stringify(data) + ]); + }); + it('fetches file list from server and renders it when reload() is called', function() { + FileList.reload(); + expect(fakeServer.requests.length).toEqual(1); + var url = fakeServer.requests[0].url; + var query = url.substr(url.indexOf('?') + 1); + expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir'}); + fakeServer.respond(); + expect($('#fileList tr:not(.summary)').length).toEqual(4); + expect(FileList.findFileEl('One.txt').length).toEqual(1); + }); + it('switches dir and fetches file list when calling changeDirectory()', function() { + FileList.changeDirectory('/anothersubdir'); + expect(FileList.getCurrentDirectory()).toEqual('/anothersubdir'); + expect(fakeServer.requests.length).toEqual(1); + var url = fakeServer.requests[0].url; + var query = url.substr(url.indexOf('?') + 1); + expect(OC.parseQueryString(query)).toEqual({'dir': '/anothersubdir'}); + fakeServer.respond(); + }); + it('switches to root dir when current directory does not exist', function() { + fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [ + 404, { + "Content-Type": "application/json" + }, + '' + ]); + FileList.changeDirectory('/unexist'); + fakeServer.respond(); + expect(FileList.getCurrentDirectory()).toEqual('/'); + }); + it('shows mask before loading file list then hides it at the end', function() { + var showMaskStub = sinon.stub(FileList, 'showMask'); + var hideMaskStub = sinon.stub(FileList, 'hideMask'); + FileList.changeDirectory('/anothersubdir'); + expect(showMaskStub.calledOnce).toEqual(true); + expect(hideMaskStub.calledOnce).toEqual(false); + fakeServer.respond(); + expect(showMaskStub.calledOnce).toEqual(true); + expect(hideMaskStub.calledOnce).toEqual(true); + showMaskStub.restore(); + hideMaskStub.restore(); + }); + it('changes URL to target dir', function() { + FileList.changeDirectory('/somedir'); + expect(pushStateStub.calledOnce).toEqual(true); + expect(pushStateStub.getCall(0).args[0]).toEqual({dir: '/somedir'}); + expect(pushStateStub.getCall(0).args[2]).toEqual(OC.webroot + '/index.php/apps/files?dir=/somedir'); + }); + it('refreshes breadcrumb after update', function() { + var setDirSpy = sinon.spy(FileList.breadcrumb, 'setDirectory'); + FileList.changeDirectory('/anothersubdir'); + fakeServer.respond(); + expect(FileList.breadcrumb.setDirectory.calledOnce).toEqual(true); + expect(FileList.breadcrumb.setDirectory.calledWith('/anothersubdir')).toEqual(true); + setDirSpy.restore(); + }); + }); + describe('breadcrumb events', function() { + beforeEach(function() { + var data = { + status: 'success', + data: { + files: testFiles, + permissions: 31 + } + }; + fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2Fsubdir/, [ + 200, { + "Content-Type": "application/json" + }, + JSON.stringify(data) + ]); + }); + it('clicking on root breadcrumb changes directory to root', function() { + FileList.changeDirectory('/subdir/two/three with space/four/five'); + fakeServer.respond(); + var changeDirStub = sinon.stub(FileList, 'changeDirectory'); + FileList.breadcrumb.$el.find('.crumb:eq(0)').click(); + + expect(changeDirStub.calledOnce).toEqual(true); + expect(changeDirStub.getCall(0).args[0]).toEqual('/'); + changeDirStub.restore(); + }); + it('clicking on breadcrumb changes directory', function() { + FileList.changeDirectory('/subdir/two/three with space/four/five'); + fakeServer.respond(); + var changeDirStub = sinon.stub(FileList, 'changeDirectory'); + FileList.breadcrumb.$el.find('.crumb:eq(3)').click(); + + expect(changeDirStub.calledOnce).toEqual(true); + expect(changeDirStub.getCall(0).args[0]).toEqual('/subdir/two/three with space'); + changeDirStub.restore(); + }); + it('dropping files on breadcrumb calls move operation', function() { + var request, query, testDir = '/subdir/two/three with space/four/five'; + FileList.changeDirectory(testDir); + fakeServer.respond(); + var $crumb = FileList.breadcrumb.$el.find('.crumb:eq(3)'); + // no idea what this is but is required by the handler + var ui = { + helper: { + find: sinon.stub() + } + }; + // returns a list of tr that were dragged + // FIXME: why are their attributes different than the + // regular file trs ? + ui.helper.find.returns([ + $(''), + $('') + ]); + // simulate drop event + FileList._onDropOnBreadCrumb.call($crumb, new $.Event('drop'), ui); + + // will trigger two calls to move.php (first one was previous list.php) + expect(fakeServer.requests.length).toEqual(3); + + request = fakeServer.requests[1]; + expect(request.method).toEqual('POST'); + expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php'); + query = OC.parseQueryString(request.requestBody); + expect(query).toEqual({ + target: '/subdir/two/three with space', + dir: testDir, + file: 'One.txt' + }); + + request = fakeServer.requests[2]; + expect(request.method).toEqual('POST'); + expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php'); + query = OC.parseQueryString(request.requestBody); + expect(query).toEqual({ + target: '/subdir/two/three with space', + dir: testDir, + file: 'Two.jpg' + }); + }); + it('dropping files on same dir breadcrumb does nothing', function() { + var request, query, testDir = '/subdir/two/three with space/four/five'; + FileList.changeDirectory(testDir); + fakeServer.respond(); + var $crumb = FileList.breadcrumb.$el.find('.crumb:last'); + // no idea what this is but is required by the handler + var ui = { + helper: { + find: sinon.stub() + } + }; + // returns a list of tr that were dragged + // FIXME: why are their attributes different than the + // regular file trs ? + ui.helper.find.returns([ + $(''), + $('') + ]); + // simulate drop event + FileList._onDropOnBreadCrumb.call($crumb, new $.Event('drop'), ui); + + // no extra server request + expect(fakeServer.requests.length).toEqual(1); + }); }); describe('Download Url', function() { it('returns correct download URL for single files', function() { - expect(FileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=some%20file.txt'); - expect(FileList.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fanotherpath%2Fabc&files=some%20file.txt'); + expect(Files.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=some%20file.txt'); + expect(Files.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fanotherpath%2Fabc&files=some%20file.txt'); $('#dir').val('/'); - expect(FileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=some%20file.txt'); + expect(Files.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=some%20file.txt'); }); it('returns correct download URL for multiple files', function() { - expect(FileList.getDownloadUrl(['a b c.txt', 'd e f.txt'])).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D'); + expect(Files.getDownloadUrl(['a b c.txt', 'd e f.txt'])).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D'); + }); + it('returns the correct ajax URL', function() { + expect(Files.getAjaxUrl('test', {a:1, b:'x y'})).toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y'); }); }); }); diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml index ab47de828b9..15a09a29f51 100644 --- a/apps/files_encryption/appinfo/info.xml +++ b/apps/files_encryption/appinfo/info.xml @@ -2,7 +2,7 @@ files_encryption Encryption - The ownCloud files encryption system provides server side-encryption. After the app was enabled you need to re-login to initialize your encryption keys. Please note that server side encryption requires that the ownCloud server admin can be trusted. The main purpose of this app is the encryption of files that are stored on externally mounted storages. + The ownCloud files encryption system provides server side-encryption. After the app is enabled you need to re-login to initialize your encryption keys. Please note that server side encryption requires that the ownCloud server admin can be trusted. The main purpose of this app is the encryption of files that are stored on externally mounted storages. AGPL Sam Tuke, Bjoern Schiessle, Florin Peter 4 diff --git a/apps/files_encryption/l10n/ast.php b/apps/files_encryption/l10n/ast.php new file mode 100644 index 00000000000..7e08e073095 --- /dev/null +++ b/apps/files_encryption/l10n/ast.php @@ -0,0 +1,13 @@ + "Contraseña camudada esitosamente.", +"Could not change the password. Maybe the old password was not correct." => "Nun pue camudase la contraseña. Quiciabes la contraseña vieya nun fore correuta.", +"personal settings" => "axustes personales", +"Encryption" => "Cifráu", +"Enabled" => "Habilitáu", +"Disabled" => "Deshabilitáu", +"Change Password" => "Camudar conseña", +" If you don't remember your old password you can ask your administrator to recover your files." => "Si nun recuerdes la to contraseña vieya pues entrugar al to alministrador pa recuperar los tos ficheros.", +"Could not update file recovery" => "Nun pue anovase'l ficheru de recuperación" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files_encryption/l10n/el.php b/apps/files_encryption/l10n/el.php index ad8617bc6d2..972d7d7138c 100644 --- a/apps/files_encryption/l10n/el.php +++ b/apps/files_encryption/l10n/el.php @@ -16,6 +16,7 @@ $TRANSLATIONS = array( "Please make sure that PHP 5.3.3 or newer is installed and that OpenSSL together with the PHP extension is enabled and configured properly. For now, the encryption app has been disabled." => "Παρακαλώ επιβεβαιώστε ότι η PHP 5.3.3 ή νεότερη είναι εγκατεστημένη και ότι το OpenSSL μαζί με το PHP extension είναι ενεργοποιήμένο και έχει ρυθμιστεί σωστά. Προς το παρόν, η εφαρμογή κρυπτογράφησης είναι απενεργοποιημένη.", "Following users are not set up for encryption:" => "Οι κάτωθι χρήστες δεν έχουν ρυθμιστεί για κρυπογράφηση:", "Initial encryption started... This can take some time. Please wait." => "Η αρχική κρυπτογράφηση άρχισε... Αυτό μπορεί να πάρει κάποια ώρα. Παρακαλώ περιμένετε.", +"Initial encryption running... Please try again later." => "Εκτέλεση αρχικής κρυπτογράφησης... Παρακαλώ προσπαθήστε αργότερα.", "Go directly to your " => "Πηγαίνε απευθείας στο ", "personal settings" => "προσωπικές ρυθμίσεις", "Encryption" => "Κρυπτογράφηση", diff --git a/apps/files_encryption/l10n/et_EE.php b/apps/files_encryption/l10n/et_EE.php index dcf035289fa..f82f9df9279 100644 --- a/apps/files_encryption/l10n/et_EE.php +++ b/apps/files_encryption/l10n/et_EE.php @@ -16,6 +16,7 @@ $TRANSLATIONS = array( "Please make sure that PHP 5.3.3 or newer is installed and that OpenSSL together with the PHP extension is enabled and configured properly. For now, the encryption app has been disabled." => "Palun veendu, et on paigaldatud PHP 5.3.3 või uuem ning PHP OpenSSL laiendus on lubatud ning seadistatud korrektselt. Hetkel krüpteerimise rakendus on peatatud.", "Following users are not set up for encryption:" => "Järgmised kasutajad pole seadistatud krüpteeringuks:", "Initial encryption started... This can take some time. Please wait." => "Algne krüpteerimine käivitati... See võib võtta natuke aega. Palun oota.", +"Initial encryption running... Please try again later." => "Toimub esmane krüpteerimine... Palun proovi hiljem uuesti.", "Go directly to your " => "Liigu otse oma", "personal settings" => "isiklikes seadetes", "Encryption" => "Krüpteerimine", diff --git a/apps/files_encryption/l10n/hu_HU.php b/apps/files_encryption/l10n/hu_HU.php index a80c8d6f36d..22c1fa989bd 100644 --- a/apps/files_encryption/l10n/hu_HU.php +++ b/apps/files_encryption/l10n/hu_HU.php @@ -16,6 +16,7 @@ $TRANSLATIONS = array( "Please make sure that PHP 5.3.3 or newer is installed and that OpenSSL together with the PHP extension is enabled and configured properly. For now, the encryption app has been disabled." => "Kérem gondoskodjon arról, hogy PHP 5.3.3 vagy annál frissebb legyen telepítve, továbbá az OpenSSL a megfelelő PHP-bővítménnyel együtt rendelkezésre álljon és helyesen legyen konfigurálva! A titkosító modul egyelőre kikapcsolásra került.", "Following users are not set up for encryption:" => "A következő felhasználók nem állították be a titkosítást:", "Initial encryption started... This can take some time. Please wait." => "A titkosítási folyamat megkezdődött... Ez hosszabb ideig is eltarthat. Kérem várjon.", +"Initial encryption running... Please try again later." => "Kezedeti titkosítás fut... Próbálja később.", "Go directly to your " => "Ugrás ide:", "personal settings" => "személyes beállítások", "Encryption" => "Titkosítás", diff --git a/apps/files_encryption/l10n/km.php b/apps/files_encryption/l10n/km.php new file mode 100644 index 00000000000..0defe6c5388 --- /dev/null +++ b/apps/files_encryption/l10n/km.php @@ -0,0 +1,11 @@ + "បាន​ប្ដូរ​ពាក្យ​សម្ងាត់​ដោយ​ជោគជ័យ។", +"Could not change the password. Maybe the old password was not correct." => "មិន​អាច​ប្ដូរ​ពាក្យ​សម្ងាត់​បាន​ទេ។ ប្រហែល​ពាក្យ​សម្ងាត់​ចាស់​មិន​ត្រឹម​ត្រូវ។", +"personal settings" => "ការ​កំណត់​ផ្ទាល់​ខ្លួន", +"Encryption" => "កូដនីយកម្ម", +"Enabled" => "បាន​បើក", +"Disabled" => "បាន​បិទ", +"Change Password" => "ប្ដូរ​ពាក្យ​សម្ងាត់" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/apps/files_encryption/l10n/ru.php b/apps/files_encryption/l10n/ru.php index bce245ce680..ba984868932 100644 --- a/apps/files_encryption/l10n/ru.php +++ b/apps/files_encryption/l10n/ru.php @@ -16,6 +16,7 @@ $TRANSLATIONS = array( "Please make sure that PHP 5.3.3 or newer is installed and that OpenSSL together with the PHP extension is enabled and configured properly. For now, the encryption app has been disabled." => "Пожалуйста, убедитесь, что версия PHP 5.3.3 или новее, а также, что OpenSSL и соответствующее расширение PHP включены и правильно настроены. На данный момент приложение шифрования отключено.", "Following users are not set up for encryption:" => "Для следующих пользователей шифрование не настроено:", "Initial encryption started... This can take some time. Please wait." => "Начато начальное шифрование... Это может занять какое-то время. Пожалуйста, подождите.", +"Initial encryption running... Please try again later." => "Работает первоначальное шифрование... Пожалуйста, повторите попытку позже.", "Go directly to your " => "Перейти прямо в", "personal settings" => "персональные настройки", "Encryption" => "Шифрование", diff --git a/apps/files_encryption/l10n/sv.php b/apps/files_encryption/l10n/sv.php index 90a9bd73a6f..b17740f2541 100644 --- a/apps/files_encryption/l10n/sv.php +++ b/apps/files_encryption/l10n/sv.php @@ -15,6 +15,8 @@ $TRANSLATIONS = array( "Missing requirements." => "Krav som saknas", "Please make sure that PHP 5.3.3 or newer is installed and that OpenSSL together with the PHP extension is enabled and configured properly. For now, the encryption app has been disabled." => "Kontrollera att PHP 5.3.3 eller senare är installerad och att tillägget OpenSSL PHP är aktiverad och korrekt konfigurerad. Kryptering är tillsvidare inaktiverad.", "Following users are not set up for encryption:" => "Följande användare har inte aktiverat kryptering:", +"Initial encryption started... This can take some time. Please wait." => "Initiala krypteringen har påbörjats... Detta kan ta lite tid. Var god vänta.", +"Initial encryption running... Please try again later." => "Initiala krypteringen körs... Var god försök igen senare.", "Go directly to your " => "Gå direkt till din", "personal settings" => "personliga inställningar", "Encryption" => "Kryptering", diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index caca13acece..a4f7bd35497 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -497,13 +497,13 @@ class Crypt { } /** - * @brief Generate a pseudo random 1024kb ASCII key, used as file key + * @brief Generate a pseudo random 256-bit ASCII key, used as file key * @returns $key Generated key */ public static function generateKey() { // Generate key - if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) { + if ($key = base64_encode(openssl_random_pseudo_bytes(32, $strong))) { if (!$strong) { diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index bae1fded53d..ae2d8d63e23 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -3,9 +3,10 @@ /** * ownCloud * - * @author Sam Tuke, Robin Appelman - * @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman - * icewind1991@gmail.com + * @author Bjoern Schiessle, Sam Tuke, Robin Appelman + * @copyright 2012 Sam Tuke + * 2012 Robin Appelman + * 2014 Bjoern Schiessle * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -36,37 +37,40 @@ namespace OCA\Encryption; */ class Proxy extends \OC_FileProxy { - private static $blackList = null; //mimetypes blacklisted from encryption private static $unencryptedSizes = array(); // remember unencrypted size private static $fopenMode = array(); // remember the fopen mode + private static $enableEncryption = false; // Enable encryption for the given path /** * Check if a file requires encryption * @param string $path + * @param string $mode type of access * @return bool * - * Tests if server side encryption is enabled, and file is allowed by blacklists + * Tests if server side encryption is enabled, and if we should call the + * crypt stream wrapper for the given file */ - private static function shouldEncrypt($path) { + private static function shouldEncrypt($path, $mode = 'w') { $userId = Helper::getUser($path); - if (\OCP\App::isEnabled('files_encryption') === false || Crypt::mode() !== 'server' || - strpos($path, '/' . $userId . '/files') !== 0) { + // don't call the crypt stream wrapper, if... + if ( + \OCP\App::isEnabled('files_encryption') === false // encryption is disabled + || Crypt::mode() !== 'server' // we are not in server-side-encryption mode + || strpos($path, '/' . $userId . '/files') !== 0 // path is not in files/ + || substr($path, 0, 8) === 'crypt://' // we are already in crypt mode + ) { return false; } - if (is_null(self::$blackList)) { - self::$blackList = explode(',', \OCP\Config::getAppValue('files_encryption', 'type_blacklist', '')); - } - - if (Crypt::isCatfileContent($path)) { - return true; - } - - $extension = substr($path, strrpos($path, '.') + 1); + $view = new \OC_FilesystemView(''); + $util = new Util($view, $userId); - if (array_search($extension, self::$blackList) === false) { + // for write operation we always encrypt the files, for read operations + // we check if the existing file is encrypted or not decide if it needs to + // decrypt it. + if (($mode !== 'r' && $mode !== 'rb') || $util->isEncryptedPath($path)) { return true; } @@ -128,6 +132,8 @@ class Proxy extends \OC_FileProxy { // re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; + } else { + return false; } } } @@ -204,23 +210,16 @@ class Proxy extends \OC_FileProxy { } - /** - * @param $path - * @return bool - */ - public function postTouch($path) { - $this->handleFile($path); - - return true; - } - /** * @brief remember initial fopen mode because sometimes it gets changed during the request * @param string $path path * @param string $mode type of access */ public function preFopen($path, $mode) { + self::$fopenMode[$path] = $mode; + self::$enableEncryption = self::shouldEncrypt($path, $mode); + } @@ -233,26 +232,14 @@ class Proxy extends \OC_FileProxy { $path = \OC\Files\Filesystem::normalizePath($path); - if (!$result) { + if (!$result || self::$enableEncryption === false) { return $result; } - // split the path parts - $pathParts = explode('/', $path); - - // don't try to encrypt/decrypt cache chunks or files in the trash bin - if (isset($pathParts[2]) && ($pathParts[2] === 'cache' || $pathParts[2] === 'files_trashbin')) { - return $result; - } - - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - // if we remember the mode from the pre proxy we re-use it - // oterwise we fall back to stream_get_meta_data() + // otherwise we fall back to stream_get_meta_data() if (isset(self::$fopenMode[$path])) { $mode = self::$fopenMode[$path]; unset(self::$fopenMode[$path]); @@ -261,35 +248,12 @@ class Proxy extends \OC_FileProxy { $mode = $meta['mode']; } - $view = new \OC_FilesystemView(''); - - $userId = Helper::getUser($path); - $util = new Util($view, $userId); - - // If file is already encrypted, decrypt using crypto protocol - if ( - Crypt::mode() === 'server' - && $util->isEncryptedPath($path) - ) { - - // Close the original encrypted file - fclose($result); + // Close the original encrypted file + fclose($result); - // Open the file using the crypto stream wrapper - // protocol and let it do the decryption work instead - $result = fopen('crypt://' . $path, $mode); - - } elseif ( - self::shouldEncrypt($path) - and $mode !== 'r' - and $mode !== 'rb' - - ) { - $result = fopen('crypt://' . $path, $mode); - } - - // Re-enable the proxy - \OC_FileProxy::$enabled = $proxyStatus; + // Open the file using the crypto stream wrapper + // protocol and let it do the decryption work instead + $result = fopen('crypt://' . $path, $mode); return $result; @@ -402,39 +366,4 @@ class Proxy extends \OC_FileProxy { return $size; } - /** - * @param $path - */ - public function handleFile($path) { - - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $view = new \OC_FilesystemView('/'); - $session = new \OCA\Encryption\Session($view); - $userId = Helper::getUser($path); - $util = new Util($view, $userId); - - // split the path parts - $pathParts = explode('/', $path); - - // get relative path - $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path); - - // only if file is on 'files' folder fix file size and sharing - if (isset($pathParts[2]) && $pathParts[2] === 'files' && $util->fixFileSize($path)) { - - // get sharing app state - $sharingEnabled = \OCP\Share::isEnabled(); - - // get users - $usersSharing = $util->getSharingUsersArray($sharingEnabled, $relativePath); - - // update sharing-keys - $util->setSharedFileKeyfiles($session, $usersSharing, $relativePath); - } - - \OC_FileProxy::$enabled = $proxyStatus; - } } diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 58ac03373a7..df5de558867 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -545,7 +545,7 @@ class Stream { $util = new Util($this->rootView, $this->userId); // Get all users sharing the file includes current user - $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath, $this->userId); + $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath); $checkedUserIds = $util->filterShareReadyUsers($uniqueUserIds); // Fetch public keys for all sharing users @@ -568,21 +568,25 @@ class Stream { // part file. $path = Helper::stripPartialFileExtension($this->rawPath); - // get file info - $fileInfo = $this->rootView->getFileInfo($path); - if ($fileInfo) { - // set encryption data - $fileInfo['encrypted'] = true; - $fileInfo['size'] = $this->size; - $fileInfo['unencrypted_size'] = $this->unencryptedSize; + $fileInfo = array( + 'encrypted' => true, + 'size' => $this->size, + 'unencrypted_size' => $this->unencryptedSize, + ); - // set fileinfo - $this->rootView->putFileInfo($path, $fileInfo); - } + // set fileinfo + $this->rootView->putFileInfo($path, $fileInfo); + + } + $result = fclose($this->handle); + + if ($result === false) { + \OCP\Util::writeLog('Encryption library', 'Could not close stream, file could be corrupted', \OCP\Util::FATAL); } - return fclose($this->handle); + return $result; + } } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 3db5a423478..b86815021a8 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -432,25 +432,28 @@ class Util { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - // we only need 24 byte from the last chunk $data = ''; - $handle = $this->view->fopen($path, 'r'); - if (is_resource($handle)) { - // suppress fseek warining, we handle the case that fseek doesn't - // work in the else branch - if (@fseek($handle, -24, SEEK_END) === 0) { - $data = fgets($handle); - } else { - // if fseek failed on the storage we create a local copy from the file - // and read this one - fclose($handle); - $localFile = $this->view->getLocalFile($path); - $handle = fopen($localFile, 'r'); - if (is_resource($handle) && fseek($handle, -24, SEEK_END) === 0) { + + // we only need 24 byte from the last chunk + if ($this->view->file_exists($path)) { + $handle = $this->view->fopen($path, 'r'); + if (is_resource($handle)) { + // suppress fseek warining, we handle the case that fseek doesn't + // work in the else branch + if (@fseek($handle, -24, SEEK_END) === 0) { $data = fgets($handle); + } else { + // if fseek failed on the storage we create a local copy from the file + // and read this one + fclose($handle); + $localFile = $this->view->getLocalFile($path); + $handle = fopen($localFile, 'r'); + if (is_resource($handle) && fseek($handle, -24, SEEK_END) === 0) { + $data = fgets($handle); + } } + fclose($handle); } - fclose($handle); } // re-enable proxy @@ -1124,8 +1127,9 @@ class Util { * @brief Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle * @param boolean $sharingEnabled + * @param string $filePath path relativ to current users files folder */ - public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId = false) { + public function getSharingUsersArray($sharingEnabled, $filePath) { $appConfig = \OC::$server->getAppConfig(); @@ -1144,12 +1148,14 @@ class Util { $ownerPath = \OCA\Encryption\Helper::stripPartialFileExtension($ownerPath); - $userIds = array(); + // always add owner to the list of users with access to the file + $userIds = array($owner); + if ($sharingEnabled) { // Find out who, if anyone, is sharing the file - $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, true); - $userIds = $result['users']; + $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner); + $userIds = \array_merge($userIds, $result['users']); if ($result['public']) { $userIds[] = $this->publicShareKeyId; } @@ -1165,11 +1171,6 @@ class Util { $userIds[] = $recoveryKeyId; } - // add current user if given - if ($currentUserId !== false) { - $userIds[] = $currentUserId; - } - // check if it is a group mount if (\OCP\App::isEnabled("files_external")) { $mount = \OC_Mount_Config::getSystemMountPoints(); diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php index 231a68b6a58..cf676c445ce 100644 --- a/apps/files_encryption/templates/settings-admin.php +++ b/apps/files_encryption/templates/settings-admin.php @@ -1,63 +1,60 @@ -
-
+ +

t('Encryption')); ?>

-

t('Encryption')); ?>

+

+ t("Enable recovery key (allow to recover users files in case of password loss):")); ?> +
+
+ + +
+ + +
+ /> + t("Enabled")); ?> +
-

- t("Enable recovery key (allow to recover users files in case of password loss):")); ?> -
-
- - -
- - -
- /> - t("Enabled")); ?> -
+ /> + t("Disabled")); ?> +

+

- /> - t("Disabled")); ?> -

+

> + t("Change recovery key password:")); ?>

- -

> - t("Change recovery key password:")); ?> -

- t("Old Recovery key password")); ?> -
-
- t("New Recovery key password")); ?> -
- t("Repeat New Recovery key password")); ?> -
- - -

-
+ t("Old Recovery key password")); ?> +
+
+ t("New Recovery key password")); ?> +
+ t("Repeat New Recovery key password")); ?> +
+ + +

diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index 1b4239d82cd..8139ece1950 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -1,66 +1,63 @@ -
-
-

t( 'Encryption' ) ); ?>

+ +

t( 'Encryption' ) ); ?>

- -

- - -
- t( "Set your old private key password to your current log-in password." ) ); ?> - t( " If you don't remember your old password you can ask your administrator to recover your files." ) ); - endif; ?> - -
- - -
- - -
- - -

- - - + +

+ + +
+ t( "Set your old private key password to your current log-in password." ) ); ?> + t( " If you don't remember your old password you can ask your administrator to recover your files." ) ); + endif; ?> + +
+ + +
+ +
-

- -
- t( "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" ) ); ?> -
- /> - t( "Enabled" ) ); ?> -
+ + +

+ - /> - t( "Disabled" ) ); ?> -
t( 'File recovery settings updated' ) ); ?>
-
t( 'Could not update file recovery' ) ); ?>
-

- + +
+

+ +
+ t( "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" ) ); ?> +
+ /> + t( "Enabled" ) ); ?> +
-

+ /> + t( "Disabled" ) ); ?> +
t( 'File recovery settings updated' ) ); ?>
+
t( 'Could not update file recovery' ) ); ?>
+

+ diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index be56968ac09..1f57d7cb635 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -100,11 +100,11 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { $this->filename = 'share-tmp.test'; - // we don't want to tests with app files_trashbin enabled - \OC_App::disable('files_trashbin'); - // remember files_trashbin state $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); + + // we don't want to tests with app files_trashbin enabled + \OC_App::disable('files_trashbin'); } function tearDown() { diff --git a/apps/files_external/3rdparty/phpseclib/LICENSE b/apps/files_external/3rdparty/phpseclib/LICENSE index 6ecd9b9bec1..75f6b2045c5 100644 --- a/apps/files_external/3rdparty/phpseclib/LICENSE +++ b/apps/files_external/3rdparty/phpseclib/LICENSE @@ -1,4 +1,4 @@ -Copyright 2007-2012 TerraFrost and other contributors +Copyright 2007-2013 TerraFrost and other contributors http://phpseclib.sourceforge.net/ Permission is hereby granted, free of charge, to any person obtaining @@ -18,4 +18,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/apps/files_external/3rdparty/phpseclib/README.md b/apps/files_external/3rdparty/phpseclib/README.md index e90b12f4a6d..de528231662 100644 --- a/apps/files_external/3rdparty/phpseclib/README.md +++ b/apps/files_external/3rdparty/phpseclib/README.md @@ -6,11 +6,11 @@ MIT-licensed pure-PHP implementations of an arbitrary-precision integer arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael, AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 -* [Download (0.3.5)](http://sourceforge.net/projects/phpseclib/files/phpseclib0.3.5.zip/download) +* [Download (0.3.6)](http://sourceforge.net/projects/phpseclib/files/phpseclib0.3.6.zip/download) * [Browse Git](https://github.com/phpseclib/phpseclib) * [Documentation](http://phpseclib.sourceforge.net/) * [Support](http://www.frostjedi.com/phpbb/viewforum.php?f=46) -* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/latest/) +* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/master/latest/) PEAR Channel PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm) diff --git a/apps/files_external/3rdparty/phpseclib/composer.json b/apps/files_external/3rdparty/phpseclib/composer.json index 79c92b52e47..70f4f7c36e9 100644 --- a/apps/files_external/3rdparty/phpseclib/composer.json +++ b/apps/files_external/3rdparty/phpseclib/composer.json @@ -11,6 +11,8 @@ "signing", "rsa", "aes", + "blowfish", + "twofish", "ssh", "sftp", "x509", @@ -25,16 +27,34 @@ { "name": "Jim Wigginton", "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", "role": "Developer" } ], "require": { "php": ">=5.0.0" }, + "require-dev": { + "squizlabs/php_codesniffer": "1.*" + }, "suggest": { "ext-mcrypt": "Install the Mcrypt extension in order to speed up a wide variety of cryptographic operations.", "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", - "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP >= 4.3.3." + "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 4.3.3." }, "include-path": ["phpseclib/"], "autoload": { @@ -42,7 +62,8 @@ "Crypt": "phpseclib/", "File": "phpseclib/", "Math": "phpseclib/", - "Net": "phpseclib/" + "Net": "phpseclib/", + "System": "phpseclib/" }, "files": [ "phpseclib/Crypt/Random.php" diff --git a/apps/files_external/3rdparty/phpseclib/composer.lock b/apps/files_external/3rdparty/phpseclib/composer.lock new file mode 100644 index 00000000000..1b5ff07e484 --- /dev/null +++ b/apps/files_external/3rdparty/phpseclib/composer.lock @@ -0,0 +1,95 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], + "hash": "4975b8cde04a99d6e78e108753845af6", + "packages": [ + + ], + "packages-dev": [ + { + "name": "squizlabs/php_codesniffer", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "a76a39b317ce8106abe6264daa505e24e1731860" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/a76a39b317ce8106abe6264daa505e24e1731860", + "reference": "a76a39b317ce8106abe6264daa505e24e1731860", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.1.2" + }, + "suggest": { + "phpunit/php-timer": "dev-master" + }, + "bin": [ + "scripts/phpcs" + ], + "type": "library", + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/CommentParser/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2014-02-04 23:49:58" + } + ], + "aliases": [ + + ], + "minimum-stability": "stable", + "stability-flags": [ + + ], + "platform": { + "php": ">=5.0.0" + }, + "platform-dev": [ + + ] +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php index 81fa2feab66..cf8c050a59e 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/AES.php @@ -1,5 +1,4 @@ - * @copyright MMVIII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_AES + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** * Include Crypt_Rijndael */ if (!class_exists('Crypt_Rijndael')) { - require_once('Rijndael.php'); + include_once 'Rijndael.php'; } /**#@+ @@ -125,12 +124,13 @@ define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /** * Pure-PHP implementation of AES. * + * @package Crypt_AES * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_AES */ -class Crypt_AES extends Crypt_Rijndael { +class Crypt_AES extends Crypt_Rijndael +{ /** * The namespace used by the cipher for its constants. * @@ -183,6 +183,3 @@ class Crypt_AES extends Crypt_Rijndael { return; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php index 7c650ca729b..f08529b902b 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Base.php @@ -1,5 +1,4 @@ - * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0.1 - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_Base + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0.1 + * @link http://phpseclib.sourceforge.net */ /**#@+ @@ -115,13 +114,14 @@ define('CRYPT_MODE_MCRYPT', 2); /** * Base Class for all Crypt_* cipher classes * + * @package Crypt_Base * @author Jim Wigginton * @author Hans-Juergen Petrich * @version 1.0.0 * @access public - * @package Crypt_Base */ -class Crypt_Base { +class Crypt_Base +{ /** * The Encryption Mode * @@ -582,7 +582,7 @@ class Crypt_Base { case !function_exists('hash_algos'): case !in_array($hash, hash_algos()): if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); + include_once 'Crypt/Hash.php'; } $i = 1; while (strlen($key) < $dkLen) { @@ -1984,6 +1984,3 @@ class Crypt_Base { return $functions; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php index c8ef67e8f7c..b352e7c4688 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Blowfish.php @@ -1,5 +1,4 @@ - * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0 - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_Blowfish + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0 + * @link http://phpseclib.sourceforge.net */ /** @@ -61,7 +60,7 @@ * Base cipher class */ if (!class_exists('Crypt_Base')) { - require_once('Base.php'); + include_once 'Base.php'; } /**#@+ @@ -120,13 +119,14 @@ define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /** * Pure-PHP implementation of Blowfish. * + * @package Crypt_Blowfish * @author Jim Wigginton * @author Hans-Juergen Petrich * @version 1.0 * @access public - * @package Crypt_Blowfish */ -class Crypt_Blowfish extends Crypt_Base { +class Crypt_Blowfish extends Crypt_Base +{ /** * Block Length of the cipher * @@ -418,8 +418,7 @@ class Crypt_Blowfish extends Crypt_Base { if (!$keylength) { $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - } - elseif ($keylength > 56) { + } elseif ($keylength > 56) { $key = substr($key, 0, 56); } @@ -673,6 +672,3 @@ class Crypt_Blowfish extends Crypt_Base { $this->inline_crypt = $lambda_functions[$code_hash]; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php index 8b04210659d..fcbf01993a1 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php @@ -1,5 +1,4 @@ - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_DES + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** @@ -65,7 +64,7 @@ * Base cipher class */ if (!class_exists('Crypt_Base')) { - require_once('Base.php'); + include_once 'Base.php'; } /**#@+ @@ -139,12 +138,13 @@ define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /** * Pure-PHP implementation of DES. * + * @package Crypt_DES * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_DES */ -class Crypt_DES extends Crypt_Base { +class Crypt_DES extends Crypt_Base +{ /** * Block Length of the cipher * @@ -1336,12 +1336,14 @@ class Crypt_DES extends Crypt_Base { $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF]; // Reorder: odd bytes/even bytes. Push the result in key schedule. - $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = - $keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) | - (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF); - $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = - $keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) | - (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF); + $val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) | + (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF); + $val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) | + (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF); + $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val1; + $keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = $val1; + $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val2; + $keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = $val2; } } @@ -1531,6 +1533,3 @@ class Crypt_DES extends Crypt_Base { $this->inline_crypt = $lambda_functions[$code_hash]; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php index 21897241989..b156169d68b 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Hash.php @@ -1,5 +1,4 @@ - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_Hash + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /**#@+ @@ -76,12 +75,13 @@ define('CRYPT_HASH_MODE_HASH', 3); /** * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. * + * @package Crypt_Hash * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_Hash */ -class Crypt_Hash { +class Crypt_Hash +{ /** * Hash Parameter * @@ -581,7 +581,7 @@ class Crypt_Hash { function _sha512($m) { if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); + include_once 'Math/BigInteger.php'; } static $init384, $init512, $k; @@ -589,11 +589,11 @@ class Crypt_Hash { if (!isset($k)) { // Initialize variables $init384 = array( // initial values for SHA384 - 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', + 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' ); $init512 = array( // initial values for SHA512 - '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', + '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' ); diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php index 5e0ca88c8fc..de22d631a16 100755 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC2.php @@ -1,5 +1,4 @@ - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_RC2 + * @author Patrick Monnerat + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** @@ -58,7 +57,7 @@ * Base cipher class */ if (!class_exists('Crypt_Base')) { - require_once('Base.php'); + include_once 'Base.php'; } /**#@+ @@ -117,11 +116,12 @@ define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /** * Pure-PHP implementation of RC2. * + * @package Crypt_RC2 * @version 0.1.1 * @access public - * @package Crypt_RC2 */ -class Crypt_RC2 extends Crypt_Base { +class Crypt_RC2 extends Crypt_Base +{ /** * Block Length of the cipher * @@ -651,6 +651,3 @@ class Crypt_RC2 extends Crypt_Base { $this->inline_crypt = $lambda_functions[$code_hash]; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php index f6a9eae2fb7..d062be2573f 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RC4.php @@ -1,5 +1,4 @@ - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_RC4 + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** @@ -67,7 +66,7 @@ * Base cipher class */ if (!class_exists('Crypt_Base')) { - require_once('Base.php'); + include_once 'Base.php'; } /**#@+ @@ -95,20 +94,21 @@ define('CRYPT_RC4_DECRYPT', 1); /** * Pure-PHP implementation of RC4. * + * @package Crypt_RC4 * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_RC4 */ -class Crypt_RC4 extends Crypt_Base { +class Crypt_RC4 extends Crypt_Base +{ /** * Block Length of the cipher * - * RC4 is a stream cipher + * RC4 is a stream cipher * so we the block_size to 0 * * @see Crypt_Base::block_size - * @var Integer + * @var Integer * @access private */ var $block_size = 0; @@ -132,7 +132,6 @@ class Crypt_RC4 extends Crypt_Base { */ var $const_namespace = 'RC4'; - /** * The mcrypt specific name of the cipher * @@ -332,6 +331,3 @@ class Crypt_RC4 extends Crypt_Base { return $text; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php index 92ebfdf7236..feb887c7031 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/RSA.php @@ -1,5 +1,4 @@ - * @copyright MMIX Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_RSA + * @author Jim Wigginton + * @copyright MMIX Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** @@ -73,17 +72,17 @@ */ // the class_exists() will only be called if the crypt_random_string function hasn't been defined and // will trigger a call to __autoload() if you're wanting to auto-load classes -// call function_exists() a second time to stop the require_once from being called outside +// call function_exists() a second time to stop the include_once from being called outside // of the auto loader if (!function_exists('crypt_random_string')) { - require_once('Random.php'); + include_once 'Random.php'; } /** * Include Crypt_Hash */ if (!class_exists('Crypt_Hash')) { - require_once('Hash.php'); + include_once 'Hash.php'; } /**#@+ @@ -145,7 +144,7 @@ define('CRYPT_RSA_ASN1_INTEGER', 2); /** * ASN1 Bit String */ -define('CRYPT_RSA_ASN1_BITSTRING', 3); +define('CRYPT_RSA_ASN1_BITSTRING', 3); /** * ASN1 Sequence (with the constucted bit set) */ @@ -240,12 +239,13 @@ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7); /** * Pure-PHP PKCS#1 compliant implementation of RSA. * + * @package Crypt_RSA * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_RSA */ -class Crypt_RSA { +class Crypt_RSA +{ /** * Precomputed Zero * @@ -433,7 +433,7 @@ class Crypt_RSA { /** * OpenSSL configuration file name. * - * Set to NULL to use system configuration file. + * Set to null to use system configuration file. * @see Crypt_RSA::createKey() * @var Mixed * @Access public @@ -461,7 +461,7 @@ class Crypt_RSA { function Crypt_RSA() { if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); + include_once 'Math/BigInteger.php'; } $this->configFile = CRYPT_RSA_OPENSSL_CONFIG; @@ -555,7 +555,7 @@ class Crypt_RSA { $config['config'] = $this->configFile; } $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config); - openssl_pkey_export($rsa, $privatekey, NULL, $config); + openssl_pkey_export($rsa, $privatekey, null, $config); $publickey = openssl_pkey_get_details($rsa); $publickey = $publickey['key']; @@ -773,7 +773,7 @@ class Crypt_RSA { $private.= crypt_random_string(16 - (strlen($private) & 15)); $source.= pack('Na*', strlen($private), $private); if (!class_exists('Crypt_AES')) { - require_once('Crypt/AES.php'); + include_once 'Crypt/AES.php'; } $sequence = 0; $symkey = ''; @@ -794,7 +794,7 @@ class Crypt_RSA { $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n"; $key.= chunk_split($private, 64); if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); + include_once 'Crypt/Hash.php'; } $hash = new Crypt_Hash('sha1'); $hash->setKey(pack('H*', sha1($hashkey))); @@ -834,7 +834,7 @@ class Crypt_RSA { $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $des = new Crypt_TripleDES(); $des->setKey($symkey); @@ -984,7 +984,7 @@ class Crypt_RSA { DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell. DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's - own implementation. ie. the implementation *is* the standard and any bugs that may exist in that + own implementation. ie. the implementation *is* the standard and any bugs that may exist in that implementation are part of the standard, as well. * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ @@ -992,41 +992,42 @@ class Crypt_RSA { $iv = pack('H*', trim($matches[2])); $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8))); - $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key); - $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; + // remove the Proc-Type / DEK-Info sections as they're no longer needed + $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key); + $ciphertext = $this->_extractBER($key); if ($ciphertext === false) { $ciphertext = $key; } switch ($matches[1]) { case 'AES-256-CBC': if (!class_exists('Crypt_AES')) { - require_once('Crypt/AES.php'); + include_once 'Crypt/AES.php'; } $crypto = new Crypt_AES(); break; case 'AES-128-CBC': if (!class_exists('Crypt_AES')) { - require_once('Crypt/AES.php'); + include_once 'Crypt/AES.php'; } $symkey = substr($symkey, 0, 16); $crypto = new Crypt_AES(); break; case 'DES-EDE3-CFB': if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB); break; case 'DES-EDE3-CBC': if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $symkey = substr($symkey, 0, 24); $crypto = new Crypt_TripleDES(); break; case 'DES-CBC': if (!class_exists('Crypt_DES')) { - require_once('Crypt/DES.php'); + include_once 'Crypt/DES.php'; } $crypto = new Crypt_DES(); break; @@ -1037,8 +1038,7 @@ class Crypt_RSA { $crypto->setIV($iv); $decoded = $crypto->decrypt($ciphertext); } else { - $decoded = preg_replace('#-.+-|[\r\n]| #', '', $key); - $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false; + $decoded = $this->_extractBER($key); } if ($decoded !== false) { @@ -1240,7 +1240,7 @@ class Crypt_RSA { switch ($encryption) { case 'aes256-cbc': if (!class_exists('Crypt_AES')) { - require_once('Crypt/AES.php'); + include_once 'Crypt/AES.php'; } $symkey = ''; $sequence = 0; @@ -1452,7 +1452,7 @@ class Crypt_RSA { break; } } - + } else { $components = $this->_parseKey($key, $type); } @@ -2152,7 +2152,7 @@ class Crypt_RSA { * * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2: - * + * * Note. Care must be taken to ensure that an opponent cannot * distinguish the different error conditions in Step 3.g, whether by * error message or timing, or, more generally, learn partial @@ -2781,4 +2781,31 @@ class Crypt_RSA { return $this->_rsassa_pss_verify($message, $signature); } } + + /** + * Extract raw BER from Base64 encoding + * + * @access private + * @param String $str + * @return String + */ + function _extractBER($str) + { + /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them + * above and beyond the ceritificate. + * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: + * + * Bag Attributes + * localKeyID: 01 00 00 00 + * subject=/O=organization/OU=org unit/CN=common name + * issuer=/O=organization/CN=common name + */ + $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1); + // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff + $temp = preg_replace('#-+[^-]+-+#', '', $temp); + // remove new lines + $temp = str_replace(array("\r", "\n", ' '), '', $temp); + $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; + return $temp != false ? $temp : $str; + } } diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php index 8532aab5a59..977ec79726b 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Random.php @@ -1,5 +1,4 @@ - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_Random + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** @@ -132,9 +131,7 @@ function crypt_random_string($length) $old_session_id = session_id(); $old_use_cookies = ini_get('session.use_cookies'); $old_session_cache_limiter = session_cache_limiter(); - if (isset($_SESSION)) { - $_OLD_SESSION = $_SESSION; - } + $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false; if ($old_session_id != '') { session_write_close(); } @@ -167,7 +164,7 @@ function crypt_random_string($length) ini_set('session.use_cookies', $old_use_cookies); session_cache_limiter($old_session_cache_limiter); } else { - if (isset($_OLD_SESSION)) { + if ($_OLD_SESSION !== false) { $_SESSION = $_OLD_SESSION; unset($_OLD_SESSION); } else { diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php index c63e0ff7e3f..42531516cf8 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Rijndael.php @@ -1,5 +1,4 @@ - * @copyright MMVIII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_Rijndael + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** @@ -77,7 +76,7 @@ * Base cipher class */ if (!class_exists('Crypt_Base')) { - require_once('Base.php'); + include_once 'Base.php'; } /**#@+ @@ -136,12 +135,13 @@ define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /** * Pure-PHP implementation of Rijndael. * + * @package Crypt_Rijndael * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_Rijndael */ -class Crypt_Rijndael extends Crypt_Base { +class Crypt_Rijndael extends Crypt_Base +{ /** * The default password key_size used by setPassword() * @@ -1369,6 +1369,3 @@ class Crypt_Rijndael extends Crypt_Base { $this->inline_crypt = $lambda_functions[$code_hash]; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php index 4030c6c9fbe..21318209fe2 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/TripleDES.php @@ -1,5 +1,4 @@ - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_TripleDES + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** * Include Crypt_DES */ if (!class_exists('Crypt_DES')) { - require_once('DES.php'); + include_once 'DES.php'; } /** @@ -77,12 +76,13 @@ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); /** * Pure-PHP implementation of Triple DES. * + * @package Crypt_TripleDES * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Crypt_TripleDES */ -class Crypt_TripleDES extends Crypt_DES { +class Crypt_TripleDES extends Crypt_DES +{ /** * The default password key_size used by setPassword() * @@ -417,6 +417,3 @@ class Crypt_TripleDES extends Crypt_DES { parent::_setupKey(); } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php index 6342298d1a3..9be5fd10997 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/Twofish.php @@ -1,5 +1,4 @@ - * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0 - * @link http://phpseclib.sourceforge.net + * @category Crypt + * @package Crypt_Twofish + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0 + * @link http://phpseclib.sourceforge.net */ /** @@ -61,7 +60,7 @@ * Base cipher class */ if (!class_exists('Crypt_Base')) { - require_once('Base.php'); + include_once 'Base.php'; } /**#@+ @@ -120,13 +119,14 @@ define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); /** * Pure-PHP implementation of Twofish. * + * @package Crypt_Twofish * @author Jim Wigginton * @author Hans-Juergen Petrich * @version 1.0 * @access public - * @package Crypt_Twofish */ -class Crypt_Twofish extends Crypt_Base { +class Crypt_Twofish extends Crypt_Base +{ /** * The namespace used by the cipher for its constants. * @@ -919,6 +919,3 @@ class Crypt_Twofish extends Crypt_Base { $this->inline_crypt = $lambda_functions[$code_hash]; } } - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php index f7ac85536f8..0e0004ce27d 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ANSI.php @@ -1,5 +1,4 @@ - * @copyright MMXII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category File + * @package File_ANSI + * @author Jim Wigginton + * @copyright MMXII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** * Pure-PHP ANSI Decoder * + * @package File_ANSI * @author Jim Wigginton * @version 0.3.0 * @access public - * @package File_ANSI */ -class File_ANSI { +class File_ANSI +{ /** * Max Width * @@ -557,4 +557,4 @@ class File_ANSI { return '
' . $scrollback . '
'; } -} \ No newline at end of file +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php index 9f481fc3ccb..67d1f6dc790 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/File/ASN1.php @@ -1,5 +1,4 @@ - * @copyright MMXII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category File + * @package File_ASN1 + * @author Jim Wigginton + * @copyright MMXII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /**#@+ @@ -58,21 +57,21 @@ define('FILE_ASN1_CLASS_PRIVATE', 3); * @access private * @link http://www.obj-sys.com/asn1tutorial/node124.html */ -define('FILE_ASN1_TYPE_BOOLEAN', 1); -define('FILE_ASN1_TYPE_INTEGER', 2); -define('FILE_ASN1_TYPE_BIT_STRING', 3); -define('FILE_ASN1_TYPE_OCTET_STRING', 4); -define('FILE_ASN1_TYPE_NULL', 5); -define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER',6); -//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR',7); -//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL -define('FILE_ASN1_TYPE_REAL', 9); -define('FILE_ASN1_TYPE_ENUMERATED', 10); -//define('FILE_ASN1_TYPE_EMBEDDED', 11); -define('FILE_ASN1_TYPE_UTF8_STRING', 12); -//define('FILE_ASN1_TYPE_RELATIVE_OID', 13); -define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF -define('FILE_ASN1_TYPE_SET', 17); // SET OF +define('FILE_ASN1_TYPE_BOOLEAN', 1); +define('FILE_ASN1_TYPE_INTEGER', 2); +define('FILE_ASN1_TYPE_BIT_STRING', 3); +define('FILE_ASN1_TYPE_OCTET_STRING', 4); +define('FILE_ASN1_TYPE_NULL', 5); +define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6); +//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7); +//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL +define('FILE_ASN1_TYPE_REAL', 9); +define('FILE_ASN1_TYPE_ENUMERATED', 10); +//define('FILE_ASN1_TYPE_EMBEDDED', 11); +define('FILE_ASN1_TYPE_UTF8_STRING', 12); +//define('FILE_ASN1_TYPE_RELATIVE_OID', 13); +define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF +define('FILE_ASN1_TYPE_SET', 17); // SET OF /**#@-*/ /**#@+ * More Tag Classes @@ -80,19 +79,19 @@ define('FILE_ASN1_TYPE_SET', 17); // SET OF * @access private * @link http://www.obj-sys.com/asn1tutorial/node10.html */ -define('FILE_ASN1_TYPE_NUMERIC_STRING', 18); -define('FILE_ASN1_TYPE_PRINTABLE_STRING',19); -define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String -define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21); -define('FILE_ASN1_TYPE_IA5_STRING', 22); -define('FILE_ASN1_TYPE_UTC_TIME', 23); -define('FILE_ASN1_TYPE_GENERALIZED_TIME',24); -define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25); -define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String -define('FILE_ASN1_TYPE_GENERAL_STRING', 27); -define('FILE_ASN1_TYPE_UNIVERSAL_STRING',28); -//define('FILE_ASN1_TYPE_CHARACTER_STRING',29); -define('FILE_ASN1_TYPE_BMP_STRING', 30); +define('FILE_ASN1_TYPE_NUMERIC_STRING', 18); +define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19); +define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String +define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21); +define('FILE_ASN1_TYPE_IA5_STRING', 22); +define('FILE_ASN1_TYPE_UTC_TIME', 23); +define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24); +define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25); +define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String +define('FILE_ASN1_TYPE_GENERAL_STRING', 27); +define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28); +//define('FILE_ASN1_TYPE_CHARACTER_STRING', 29); +define('FILE_ASN1_TYPE_BMP_STRING', 30); /**#@-*/ /**#@+ @@ -111,12 +110,13 @@ define('FILE_ASN1_TYPE_ANY', -2); * * Bypass normal encoding rules in File_ASN1::encodeDER() * + * @package File_ASN1 * @author Jim Wigginton * @version 0.3.0 * @access public - * @package File_ASN1 */ -class File_ASN1_Element { +class File_ASN1_Element +{ /** * Raw element value * @@ -141,12 +141,13 @@ class File_ASN1_Element { /** * Pure-PHP ASN.1 Parser * + * @package File_ASN1 * @author Jim Wigginton * @version 0.3.0 * @access public - * @package File_ASN1 */ -class File_ASN1 { +class File_ASN1 +{ /** * ASN.1 object identifier * @@ -252,7 +253,7 @@ class File_ASN1 { if (!$static_init) { $static_init = true; if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); + include_once 'Math/BigInteger.php'; } } } @@ -316,7 +317,7 @@ class File_ASN1 { $length = ord($this->_string_shift($encoded)); $start++; if ( $length == 0x80 ) { // indefinite length - // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all + // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all // immediately available." -- paragraph 8.1.3.2.c //if ( !$constructed ) { // return false; @@ -419,7 +420,7 @@ class File_ASN1 { //} $current['content'].= $temp[$i]['content']; } - // $length = + // $length = } break; case FILE_ASN1_TYPE_NULL: @@ -456,7 +457,7 @@ class File_ASN1 { -- X.690-0207.pdf#page=23 (paragraph 8.21.3) - Per that, we're not going to do any validation. If there are any illegal characters in the string, + Per that, we're not going to do any validation. If there are any illegal characters in the string, we don't really care */ case FILE_ASN1_TYPE_NUMERIC_STRING: // 0,1,2,3,4,5,6,7,8,9, and space @@ -545,13 +546,13 @@ class File_ASN1 { return array($key => $value); } } - return NULL; + return null; case isset($mapping['implicit']): case isset($mapping['explicit']): case $decoded['type'] == $mapping['type']: break; default: - return NULL; + return null; } if (isset($mapping['implicit'])) { @@ -566,8 +567,8 @@ class File_ASN1 { if (isset($mapping['min']) && isset($mapping['max'])) { $child = $mapping['children']; foreach ($decoded['content'] as $content) { - if (($map[] = $this->asn1map($content, $child, $special)) === NULL) { - return NULL; + if (($map[] = $this->asn1map($content, $child, $special)) === null) { + return null; } } @@ -585,15 +586,14 @@ class File_ASN1 { if ($child['type'] != FILE_ASN1_TYPE_CHOICE) { // Get the mapping and input class & constant. $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL; - $constant = NULL; + $constant = null; if (isset($temp['constant'])) { $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC; } if (isset($child['class'])) { $childClass = $child['class']; $constant = $child['cast']; - } - elseif (isset($child['constant'])) { + } elseif (isset($child['constant'])) { $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC; $constant = $child['constant']; } @@ -611,7 +611,7 @@ class File_ASN1 { if ($maymatch) { // Attempt submapping. $candidate = $this->asn1map($temp, $child, $special); - $maymatch = $candidate !== NULL; + $maymatch = $candidate !== null; } if ($maymatch) { @@ -624,12 +624,12 @@ class File_ASN1 { } elseif (isset($child['default'])) { $map[$key] = $child['default']; // Use default. } elseif (!isset($child['optional'])) { - return NULL; // Syntax error. + return null; // Syntax error. } } // Fail mapping if all input items have not been consumed. - return $i < $n? NULL: $map; + return $i < $n? null: $map; // the main diff between sets and sequences is the encapsulation of the foreach in another for loop case FILE_ASN1_TYPE_SET: @@ -639,8 +639,8 @@ class File_ASN1 { if (isset($mapping['min']) && isset($mapping['max'])) { $child = $mapping['children']; foreach ($decoded['content'] as $content) { - if (($map[] = $this->asn1map($content, $child, $special)) === NULL) { - return NULL; + if (($map[] = $this->asn1map($content, $child, $special)) === null) { + return null; } } @@ -661,12 +661,11 @@ class File_ASN1 { $maymatch = true; if ($child['type'] != FILE_ASN1_TYPE_CHOICE) { $childClass = FILE_ASN1_CLASS_UNIVERSAL; - $constant = NULL; + $constant = null; if (isset($child['class'])) { $childClass = $child['class']; $constant = $child['cast']; - } - elseif (isset($child['constant'])) { + } elseif (isset($child['constant'])) { $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC; $constant = $child['constant']; } @@ -683,7 +682,7 @@ class File_ASN1 { if ($maymatch) { // Attempt submapping. $candidate = $this->asn1map($temp, $child, $special); - $maymatch = $candidate !== NULL; + $maymatch = $candidate !== null; } if (!$maymatch) { @@ -704,7 +703,7 @@ class File_ASN1 { if (isset($child['default'])) { $map[$key] = $child['default']; } elseif (!isset($child['optional'])) { - return NULL; + return null; } } } @@ -797,7 +796,7 @@ class File_ASN1 { function encodeDER($source, $mapping, $special = array()) { $this->location = array(); - return $this->_encode_der($source, $mapping, NULL, $special); + return $this->_encode_der($source, $mapping, null, $special); } /** @@ -819,7 +818,7 @@ class File_ASN1 { * @return String * @access private */ - function _encode_der($source, $mapping, $idx = NULL, $special = array()) + function _encode_der($source, $mapping, $idx = null, $special = array()) { if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') { return $source->element; @@ -850,7 +849,7 @@ class File_ASN1 { $child = $mapping['children']; foreach ($source as $content) { - $temp = $this->_encode_der($content, $child, NULL, $special); + $temp = $this->_encode_der($content, $child, null, $special); if ($temp === false) { return false; } @@ -1030,19 +1029,19 @@ class File_ASN1 { switch (true) { case !isset($source): - return $this->_encode_der(NULL, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, NULL, $special); + return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special); case is_int($source): case is_object($source) && strtolower(get_class($source)) == 'math_biginteger': - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, NULL, $special); + return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special); case is_float($source): - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, NULL, $special); + return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special); case is_bool($source): - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, NULL, $special); + return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special); case is_array($source) && count($source) == 1: $typename = implode('', array_keys($source)); $outtype = array_search($typename, $this->ANYmap, true); if ($outtype !== false) { - return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, NULL, $special); + return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special); } } @@ -1058,7 +1057,7 @@ class File_ASN1 { user_error('No filters defined for ' . implode('/', $loc)); return false; } - return $this->_encode_der($source, $filters + $mapping, NULL, $special); + return $this->_encode_der($source, $filters + $mapping, null, $special); case FILE_ASN1_TYPE_NULL: $value = ''; break; diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php b/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php index 0b4e291361e..9e7b0b3b962 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/File/X509.php @@ -1,5 +1,4 @@ - * @copyright MMXII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category File + * @package File_X509 + * @author Jim Wigginton + * @copyright MMXII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** * Include File_ASN1 */ if (!class_exists('File_ASN1')) { - require_once('ASN1.php'); + include_once 'ASN1.php'; } /** @@ -124,12 +123,13 @@ define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value. /** * Pure-PHP X.509 Parser * + * @package File_X509 * @author Jim Wigginton * @version 0.3.1 * @access public - * @package File_X509 */ -class File_X509 { +class File_X509 +{ /** * ASN.1 syntax for X.509 certificates * @@ -248,7 +248,7 @@ class File_X509 { * The signature subject * * There's no guarantee File_X509 is going to reencode an X.509 cert in the same way it was originally - * encoded so we take save the portion of the original cert that the signature would have made for. + * encoded so we take save the portion of the original cert that the signature would have made for. * * @var String * @access private @@ -307,7 +307,7 @@ class File_X509 { function File_X509() { if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); + include_once 'Math/BigInteger.php'; } // Explicitly Tagged Module, 1988 Syntax @@ -1431,7 +1431,7 @@ class File_X509 { $this->currentCert = $cert; $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); - $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : NULL; + $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; unset($this->signatureSubject); @@ -1469,7 +1469,7 @@ class File_X509 { $this->dn = $x509['tbsCertificate']['subject']; $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); - $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : NULL; + $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; return $x509; } @@ -1496,33 +1496,33 @@ class File_X509 { default: switch ($algorithm) { case 'rsaEncryption': - $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] = - base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))); + $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] + = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))); } } $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); $filters = array(); - $filters['tbsCertificate']['signature']['parameters'] = - $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = - $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = - $filters['tbsCertificate']['subject']['rdnSequence']['value'] = - $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = - $filters['signatureAlgorithm']['parameters'] = - $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = - //$filters['policyQualifiers']['qualifier'] = - $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = - $filters['directoryName']['rdnSequence']['value'] = - array('type' => FILE_ASN1_TYPE_UTF8_STRING); + $type_utf8_string = array('type' => FILE_ASN1_TYPE_UTF8_STRING); + $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string; + $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string; + $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string; + $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string; + $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string; + $filters['signatureAlgorithm']['parameters'] = $type_utf8_string; + $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string; + //$filters['policyQualifiers']['qualifier'] = $type_utf8_string; + $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string; + $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string; + /* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING. FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random characters. */ - $filters['policyQualifiers']['qualifier'] = - array('type' => FILE_ASN1_TYPE_IA5_STRING); + $filters['policyQualifiers']['qualifier'] + = array('type' => FILE_ASN1_TYPE_IA5_STRING); $asn1->loadFilters($filters); @@ -1715,8 +1715,7 @@ class File_X509 { if ($map === false) { user_error($id . ' is not a currently supported attribute', E_USER_NOTICE); unset($attributes[$i]); - } - elseif (is_array($attributes[$i]['value'])) { + } elseif (is_array($attributes[$i]['value'])) { $values = &$attributes[$i]['value']; for ($j = 0; $j < count($values); $j++) { switch ($id) { @@ -1963,7 +1962,7 @@ class File_X509 { * @param Integer $date optional * @access public */ - function validateDate($date = NULL) + function validateDate($date = null) { if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { return false; @@ -1992,7 +1991,7 @@ class File_X509 { * Validate a signature * * Works on X.509 certs, CSR's and CRL's. - * Returns true if the signature is verified, false if it is not correct or NULL on error + * Returns true if the signature is verified, false if it is not correct or null on error * * By default returns false for self-signed certs. Call validateSignature(false) to make this support * self-signed. @@ -2006,7 +2005,7 @@ class File_X509 { function validateSignature($caonly = true) { if (!is_array($this->currentCert) || !isset($this->signatureSubject)) { - return NULL; + return null; } /* TODO: @@ -2107,7 +2106,7 @@ class File_X509 { /** * Validates a signature * - * Returns true if the signature is verified, false if it is not correct or NULL on error + * Returns true if the signature is verified, false if it is not correct or null on error * * @param String $publicKeyAlgorithm * @param String $publicKey @@ -2122,7 +2121,7 @@ class File_X509 { switch ($publicKeyAlgorithm) { case 'rsaEncryption': if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); + include_once 'Crypt/RSA.php'; } $rsa = new Crypt_RSA(); $rsa->loadKey($publicKey); @@ -2142,11 +2141,11 @@ class File_X509 { } break; default: - return NULL; + return null; } break; default: - return NULL; + return null; } return true; @@ -2367,7 +2366,7 @@ class File_X509 { * @return Mixed * @access public */ - function getDNProp($propName, $dn = NULL, $withType = false) + function getDNProp($propName, $dn = null, $withType = false) { if (!isset($dn)) { $dn = $this->dn; @@ -2421,7 +2420,7 @@ class File_X509 { function setDN($dn, $merge = false, $type = 'utf8String') { if (!$merge) { - $this->dn = NULL; + $this->dn = null; } if (is_array($dn)) { @@ -2460,7 +2459,7 @@ class File_X509 { * @access public * @return Boolean */ - function getDN($format = FILE_X509_DN_ARRAY, $dn = NULL) + function getDN($format = FILE_X509_DN_ARRAY, $dn = null) { if (!isset($dn)) { $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn; @@ -2524,7 +2523,7 @@ class File_X509 { case FILE_X509_DN_HASH: $dn = $this->getDN(FILE_X509_DN_CANON, $dn); if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); + include_once 'Crypt/Hash.php'; } $hash = new Crypt_Hash('sha1'); $hash = $hash->hash($dn); @@ -2676,7 +2675,7 @@ class File_X509 { { switch (true) { case !empty($this->dn): - return $this->getDNProp($propName, NULL, $withType); + return $this->getDNProp($propName, null, $withType); case !isset($this->currentCert) || !is_array($this->currentCert): break; case isset($this->currentCert['tbsCertificate']): @@ -2792,7 +2791,7 @@ class File_X509 { switch ($keyinfo['algorithm']['algorithm']) { case 'rsaEncryption': if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); + include_once 'Crypt/RSA.php'; } $publicKey = new Crypt_RSA(); $publicKey->loadKey($key); @@ -2865,17 +2864,17 @@ class File_X509 { switch ($algorithm) { case 'rsaEncryption': if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); + include_once 'Crypt/RSA.php'; } $this->publicKey = new Crypt_RSA(); $this->publicKey->loadKey($key); $this->publicKey->setPublicKey(); break; default: - $this->publicKey = NULL; + $this->publicKey = null; } - $this->currentKeyIdentifier = NULL; + $this->currentKeyIdentifier = null; $this->currentCert = $csr; return $csr; @@ -2902,8 +2901,8 @@ class File_X509 { default: switch ($algorithm) { case 'rsaEncryption': - $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] = - base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']))); + $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] + = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']))); } } @@ -2912,8 +2911,8 @@ class File_X509 { $asn1->loadOIDs($this->oids); $filters = array(); - $filters['certificationRequestInfo']['subject']['rdnSequence']['value'] = - array('type' => FILE_ASN1_TYPE_UTF8_STRING); + $filters['certificationRequestInfo']['subject']['rdnSequence']['value'] + = array('type' => FILE_ASN1_TYPE_UTF8_STRING); $asn1->loadFilters($filters); @@ -2990,17 +2989,17 @@ class File_X509 { switch ($algorithm) { case 'rsaEncryption': if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); + include_once 'Crypt/RSA.php'; } $this->publicKey = new Crypt_RSA(); $this->publicKey->loadKey($key); $this->publicKey->setPublicKey(); break; default: - $this->publicKey = NULL; + $this->publicKey = null; } - $this->currentKeyIdentifier = NULL; + $this->currentKeyIdentifier = null; $this->currentCert = $spkac; return $spkac; @@ -3048,14 +3047,14 @@ class File_X509 { $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1); - $rclist = &$this->_subArray($crl,'tbsCertList/revokedCertificates'); + $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates'); if (is_array($rclist)) { foreach ($rclist as $i => $extension) { $this->_mapInExtensions($rclist, "$i/crlEntryExtensions", $asn1); } } - $this->currentKeyIdentifier = NULL; + $this->currentKeyIdentifier = null; $this->currentCert = $crl; return $crl; @@ -3080,25 +3079,27 @@ class File_X509 { $asn1->loadOIDs($this->oids); $filters = array(); - $filters['tbsCertList']['issuer']['rdnSequence']['value'] = - $filters['tbsCertList']['signature']['parameters'] = - $filters['signatureAlgorithm']['parameters'] = - array('type' => FILE_ASN1_TYPE_UTF8_STRING); + $filters['tbsCertList']['issuer']['rdnSequence']['value'] + = array('type' => FILE_ASN1_TYPE_UTF8_STRING); + $filters['tbsCertList']['signature']['parameters'] + = array('type' => FILE_ASN1_TYPE_UTF8_STRING); + $filters['signatureAlgorithm']['parameters'] + = array('type' => FILE_ASN1_TYPE_UTF8_STRING); if (empty($crl['tbsCertList']['signature']['parameters'])) { - $filters['tbsCertList']['signature']['parameters'] = - array('type' => FILE_ASN1_TYPE_NULL); + $filters['tbsCertList']['signature']['parameters'] + = array('type' => FILE_ASN1_TYPE_NULL); } if (empty($crl['signatureAlgorithm']['parameters'])) { - $filters['signatureAlgorithm']['parameters'] = - array('type' => FILE_ASN1_TYPE_NULL); + $filters['signatureAlgorithm']['parameters'] + = array('type' => FILE_ASN1_TYPE_NULL); } $asn1->loadFilters($filters); $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1); - $rclist = &$this->_subArray($crl,'tbsCertList/revokedCertificates'); + $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates'); if (is_array($rclist)) { foreach ($rclist as $i => $extension) { $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1); @@ -3139,14 +3140,14 @@ class File_X509 { return false; } - $currentCert = isset($this->currentCert) ? $this->currentCert : NULL; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: NULL; + $currentCert = isset($this->currentCert) ? $this->currentCert : null; + $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) { $this->currentCert = $subject->currentCert; - $this->currentCert['tbsCertificate']['signature']['algorithm'] = - $this->currentCert['signatureAlgorithm']['algorithm'] = - $signatureAlgorithm; + $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm; + $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; + if (!empty($this->startDate)) { $this->currentCert['tbsCertificate']['validity']['notBefore']['generalTime'] = $this->startDate; unset($this->currentCert['tbsCertificate']['validity']['notBefore']['utcTime']); @@ -3312,12 +3313,11 @@ class File_X509 { } $this->publicKey = $origPublicKey; - $currentCert = isset($this->currentCert) ? $this->currentCert : NULL; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: NULL; + $currentCert = isset($this->currentCert) ? $this->currentCert : null; + $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) { - $this->currentCert['signatureAlgorithm']['algorithm'] = - $signatureAlgorithm; + $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; if (!empty($this->dn)) { $this->currentCert['certificationRequestInfo']['subject'] = $this->dn; } @@ -3366,8 +3366,8 @@ class File_X509 { return false; } - $currentCert = isset($this->currentCert) ? $this->currentCert : NULL; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : NULL; + $currentCert = isset($this->currentCert) ? $this->currentCert : null; + $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M y H:i:s O'); if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) { @@ -3400,10 +3400,9 @@ class File_X509 { if (!empty($this->serialNumber)) { $crlNumber = $this->serialNumber; - } - else { + } else { $crlNumber = $this->getExtension('id-ce-cRLNumber'); - $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : NULL; + $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null; } $this->removeExtension('id-ce-authorityKeyIdentifier'); @@ -3414,8 +3413,7 @@ class File_X509 { if (!$version) { if (!empty($tbsCertList['crlExtensions'])) { $version = 1; // v2. - } - elseif (!empty($tbsCertList['revokedCertificates'])) { + } elseif (!empty($tbsCertList['revokedCertificates'])) { foreach ($tbsCertList['revokedCertificates'] as $cert) { if (!empty($cert['crlEntryExtensions'])) { $version = 1; // v2. @@ -3613,7 +3611,7 @@ class File_X509 { * @access private * @return array ref or false */ - function &_extensions(&$root, $path = NULL, $create = false) + function &_extensions(&$root, $path = null, $create = false) { if (!isset($root)) { $root = $this->currentCert; @@ -3667,7 +3665,7 @@ class File_X509 { * @access private * @return Boolean */ - function _removeExtension($id, $path = NULL) + function _removeExtension($id, $path = null) { $extensions = &$this->_extensions($this->currentCert, $path); @@ -3698,7 +3696,7 @@ class File_X509 { * @access private * @return Mixed */ - function _getExtension($id, $cert = NULL, $path = NULL) + function _getExtension($id, $cert = null, $path = null) { $extensions = $this->_extensions($cert, $path); @@ -3723,7 +3721,7 @@ class File_X509 { * @access private * @return Array */ - function _getExtensions($cert = NULL, $path = NULL) + function _getExtensions($cert = null, $path = null) { $exts = $this->_extensions($cert, $path); $extensions = array(); @@ -3748,7 +3746,7 @@ class File_X509 { * @access private * @return Boolean */ - function _setExtension($id, $value, $critical = false, $replace = true, $path = NULL) + function _setExtension($id, $value, $critical = false, $replace = true, $path = null) { $extensions = &$this->_extensions($this->currentCert, $path, true); @@ -3795,7 +3793,7 @@ class File_X509 { * @access public * @return Mixed */ - function getExtension($id, $cert = NULL) + function getExtension($id, $cert = null) { return $this->_getExtension($id, $cert); } @@ -3807,7 +3805,7 @@ class File_X509 { * @access public * @return Array */ - function getExtensions($cert = NULL) + function getExtensions($cert = null) { return $this->_getExtensions($cert); } @@ -3886,7 +3884,7 @@ class File_X509 { * @access public * @return Mixed */ - function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = NULL) + function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = null) { if (empty($csr)) { $csr = $this->currentCert; @@ -3926,7 +3924,7 @@ class File_X509 { * @access public * @return Array */ - function getAttributes($csr = NULL) + function getAttributes($csr = null) { if (empty($csr)) { $csr = $this->currentCert; @@ -4035,7 +4033,7 @@ class File_X509 { * @access public * @return String binary key identifier */ - function computeKeyIdentifier($key = NULL, $method = 1) + function computeKeyIdentifier($key = null, $method = 1) { if (is_null($key)) { $key = $this; @@ -4064,7 +4062,7 @@ class File_X509 { $raw = base64_decode($raw); // If the key is private, compute identifier from its corresponding public key. if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); + include_once 'Crypt/RSA.php'; } $key = new Crypt_RSA(); if (!$key->loadKey($raw)) { @@ -4096,7 +4094,7 @@ class File_X509 { // Now we have the key string: compute its sha-1 sum. if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); + include_once 'Crypt/Hash.php'; } $hash = new Crypt_Hash('sha1'); $hash = $hash->hash($key); @@ -4228,7 +4226,7 @@ class File_X509 { * @access public * @return Boolean */ - function revoke($serial, $date = NULL) + function revoke($serial, $date = null) { if (isset($this->currentCert['tbsCertList'])) { if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { @@ -4293,7 +4291,7 @@ class File_X509 { * @access public * @return array */ - function listRevoked($crl = NULL) + function listRevoked($crl = null) { if (!isset($crl)) { $crl = $this->currentCert; @@ -4344,7 +4342,7 @@ class File_X509 { * @access public * @return Mixed */ - function getRevokedCertificateExtension($serial, $id, $crl = NULL) + function getRevokedCertificateExtension($serial, $id, $crl = null) { if (!isset($crl)) { $crl = $this->currentCert; @@ -4367,7 +4365,7 @@ class File_X509 { * @access public * @return Array */ - function getRevokedCertificateExtensions($serial, $crl = NULL) + function getRevokedCertificateExtensions($serial, $crl = null) { if (!isset($crl)) { $crl = $this->currentCert; @@ -4415,15 +4413,15 @@ class File_X509 { */ function _extractBER($str) { - /* - X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them above and beyond the ceritificate. ie. - some may have the following preceding the -----BEGIN CERTIFICATE----- line: - - Bag Attributes - localKeyID: 01 00 00 00 - subject=/O=organization/OU=org unit/CN=common name - issuer=/O=organization/CN=common name - */ + /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them + * above and beyond the ceritificate. + * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: + * + * Bag Attributes + * localKeyID: 01 00 00 00 + * subject=/O=organization/OU=org unit/CN=common name + * issuer=/O=organization/CN=common name + */ $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1); // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff $temp = preg_replace('#-+[^-]+-+#', '', $temp); diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php index e40433de5bd..1b4ea675fcc 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Math/BigInteger.php @@ -1,5 +1,4 @@ - * @copyright MMVI Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://pear.php.net/package/Math_BigInteger + * @category Math + * @package Math_BigInteger + * @author Jim Wigginton + * @copyright MMVI Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://pear.php.net/package/Math_BigInteger */ /**#@+ @@ -174,12 +173,13 @@ define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256 * numbers. * + * @package Math_BigInteger * @author Jim Wigginton * @version 1.0.0RC4 * @access public - * @package Math_BigInteger */ -class Math_BigInteger { +class Math_BigInteger +{ /** * Holds the BigInteger's value. * @@ -223,7 +223,7 @@ class Math_BigInteger { /** * Mode independent value used for serialization. * - * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for + * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value, * however, $this->hex is only calculated when $this->__sleep() is called. * @@ -797,7 +797,7 @@ class Math_BigInteger { $vars[] = 'precision'; } return $vars; - + } /** @@ -2279,7 +2279,7 @@ class Math_BigInteger { /** * Montgomery Multiply * - * Interleaves the montgomery reduction and long multiplication algorithms together as described in + * Interleaves the montgomery reduction and long multiplication algorithms together as described in * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36} * * @see _prepMontgomery() @@ -2359,7 +2359,7 @@ class Math_BigInteger { * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85} * * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For - * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields + * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the @@ -3290,7 +3290,7 @@ class Math_BigInteger { * @return Boolean * @access public * @internal Uses the - * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See + * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}. */ function isPrime($t = false) @@ -3299,6 +3299,7 @@ class Math_BigInteger { if (!$t) { // see HAC 4.49 "Note (controlling the error probability)" + // @codingStandardsIgnoreStart if ($length >= 163) { $t = 2; } // floor(1300 / 8) else if ($length >= 106) { $t = 3; } // floor( 850 / 8) else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8) @@ -3311,6 +3312,7 @@ class Math_BigInteger { else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8) else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8) else { $t = 27; } + // @codingStandardsIgnoreEnd } // ie. gmp_testbit($this, 0) @@ -3339,16 +3341,16 @@ class Math_BigInteger { if (!isset($primes)) { $primes = array( - 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, - 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, - 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, - 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, - 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, - 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, - 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, - 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, - 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, - 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 ); diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php index 88180cac67a..4cfa357009f 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SCP.php @@ -1,5 +1,4 @@ - * @copyright MMX Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Net + * @package Net_SCP + * @author Jim Wigginton + * @copyright MMX Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /**#@+ @@ -82,12 +81,13 @@ define('NET_SCP_SSH2', 2); /** * Pure-PHP implementations of SCP. * + * @package Net_SCP * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Net_SCP */ -class Net_SCP { +class Net_SCP +{ /** * SSH Object * @@ -151,7 +151,7 @@ class Net_SCP { * So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes * long, containing 'filename.ext' as its contents. * - * Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will + * Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how * large $remote_file will be, as well. * @@ -181,7 +181,7 @@ class Net_SCP { } if ($this->mode == NET_SCP_SSH2) { - $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC]; + $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4; } $remote_file = basename($remote_file); @@ -353,7 +353,7 @@ class Net_SCP { { switch ($this->mode) { case NET_SCP_SSH2: - $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC); + $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true); break; case NET_SCP_SSH1: $this->ssh->disconnect(); diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php index 5356ffbf77a..68d944f9f3f 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP.php @@ -1,5 +1,4 @@ - * @copyright MMIX Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Net + * @package Net_SFTP + * @author Jim Wigginton + * @copyright MMIX Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** * Include Net_SSH2 */ if (!class_exists('Net_SSH2')) { - require_once('SSH2.php'); + include_once 'SSH2.php'; } /**#@+ @@ -116,12 +115,13 @@ define('NET_SFTP_RESUME_START', 8); /** * Pure-PHP implementations of SFTP. * + * @package Net_SFTP * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Net_SFTP */ -class Net_SFTP extends Net_SSH2 { +class Net_SFTP extends Net_SSH2 +{ /** * Packet Types * @@ -233,7 +233,7 @@ class Net_SFTP extends Net_SSH2 { * Directory Cache * * Rather than always having to open a directory and close it immediately there after to see if a file is a directory or - * rather than always + * rather than always * * @see Net_SFTP::_save_dir() * @see Net_SFTP::_remove_dir() @@ -347,7 +347,7 @@ class Net_SFTP extends Net_SSH2 { 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS', 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME', // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers - // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in + // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000. // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored. -1 << 31 => 'NET_SFTP_ATTR_EXTENDED' @@ -402,7 +402,7 @@ class Net_SFTP extends Net_SSH2 { function login($username) { $args = func_get_args(); - if (!call_user_func_array(array('Net_SSH2', 'login'), $args)) { + if (!call_user_func_array(array(&$this, '_login'), $args)) { return false; } @@ -635,7 +635,11 @@ class Net_SFTP extends Net_SSH2 { return false; } - if ($dir[strlen($dir) - 1] != '/') { + // assume current dir if $dir is empty + if ($dir === '') { + $dir = './'; + // suffix a slash if needed + } elseif ($dir[strlen($dir) - 1] != '/') { $dir.= '/'; } @@ -1038,7 +1042,7 @@ class Net_SFTP extends Net_SSH2 { */ function truncate($filename, $new_size) { - $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 0x100000000, $new_size); + $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); // 4294967296 == 0x100000000 == 1<<32 return $this->_setstat($filename, $attr, false); } @@ -1054,7 +1058,7 @@ class Net_SFTP extends Net_SSH2 { * @return Boolean * @access public */ - function touch($filename, $time = NULL, $atime = NULL) + function touch($filename, $time = null, $atime = null) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; @@ -1097,7 +1101,7 @@ class Net_SFTP extends Net_SSH2 { /** * Changes file or directory owner * - * Returns TRUE on success or FALSE on error. + * Returns true on success or false on error. * * @param String $filename * @param Integer $uid @@ -1117,7 +1121,7 @@ class Net_SFTP extends Net_SSH2 { /** * Changes file or directory group * - * Returns TRUE on success or FALSE on error. + * Returns true on success or false on error. * * @param String $filename * @param Integer $gid @@ -1135,8 +1139,8 @@ class Net_SFTP extends Net_SSH2 { /** * Set permissions on a file. * - * Returns the new file permissions on success or FALSE on error. - * If $recursive is true than this just returns TRUE or FALSE. + * Returns the new file permissions on success or false on error. + * If $recursive is true than this just returns true or false. * * @param Integer $mode * @param String $filename @@ -1216,7 +1220,7 @@ class Net_SFTP extends Net_SSH2 { } /* - "Because some systems must use separate system calls to set various attributes, it is possible that a failure + "Because some systems must use separate system calls to set various attributes, it is possible that a failure response will be returned, but yet some of the attributes may be have been successfully modified. If possible, servers SHOULD avoid this situation; however, clients MUST be aware that this is possible." @@ -1326,7 +1330,7 @@ class Net_SFTP extends Net_SSH2 { } $dir = $this->_realpath($dir); - // by not providing any permissions, hopefully the server will use the logged in users umask - their + // by not providing any permissions, hopefully the server will use the logged in users umask - their // default permissions. $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); @@ -1424,7 +1428,7 @@ class Net_SFTP extends Net_SSH2 { * So, for example, if you set $data to 'filename.ext' and then do Net_SFTP::get(), you will get a file, twelve bytes * long, containing 'filename.ext' as its contents. * - * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will + * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how * large $remote_file will be, as well. * @@ -1502,8 +1506,6 @@ class Net_SFTP extends Net_SSH2 { return false; } - $initialize = true; - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 if ($mode & NET_SFTP_LOCAL_FILE) { if (!is_file($data)) { @@ -1537,7 +1539,7 @@ class Net_SFTP extends Net_SSH2 { while ($sent < $size) { $temp = $mode & NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); $subtemp = $offset + $sent; - $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 0x100000000, $subtemp, strlen($temp), $temp); + $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { fclose($fp); return false; @@ -1683,9 +1685,10 @@ class Net_SFTP extends Net_SSH2 { $content = ''; } + $start = $offset; $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length; while (true) { - $packet = pack('Na*N3', strlen($handle), $handle, $offset / 0x100000000, $offset, $size); + $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size); if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { if ($local_file !== false) { fclose($fp); @@ -1716,12 +1719,12 @@ class Net_SFTP extends Net_SSH2 { return false; } - if ($length > 0 && $length <= $offset - $size) { + if ($length > 0 && $length <= $offset - $start) { break; } } - if ($length > 0 && $length <= $offset - $size) { + if ($length > 0 && $length <= $offset - $start) { if ($local_file === false) { $content = substr($content, 0, $length); } else { @@ -1923,7 +1926,7 @@ class Net_SFTP extends Net_SSH2 { // (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than // 4GB as being 4GB. extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8))); - $attr['size'] = $upper ? 0x100000000 * $upper : 0; + $attr['size'] = $upper ? 4294967296 * $upper : 0; $attr['size']+= $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; break; case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) @@ -2054,7 +2057,7 @@ class Net_SFTP extends Net_SSH2 { $stop = strtok(microtime(), ' ') + strtok(''); if (defined('NET_SFTP_LOGGING')) { - $packet_type = '-> ' . $this->packet_types[$type] . + $packet_type = '-> ' . $this->packet_types[$type] . ' (' . round($stop - $start, 4) . 's)'; if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) { echo "
\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n
\r\n"; @@ -2130,7 +2133,7 @@ class Net_SFTP extends Net_SSH2 { $packet = $this->_string_shift($this->packet_buffer, $length); if (defined('NET_SFTP_LOGGING')) { - $packet_type = '<- ' . $this->packet_types[$this->packet_type] . + $packet_type = '<- ' . $this->packet_types[$this->packet_type] . ' (' . round($stop - $start, 4) . 's)'; if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) { echo "
\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n
\r\n"; diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php index 0572c5c4025..48b79b3ef7f 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SFTP/Stream.php @@ -1,5 +1,4 @@ - * @copyright MMXIII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Net + * @package Net_SFTP_Stream + * @author Jim Wigginton + * @copyright MMXIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /** * SFTP Stream Wrapper * + * @package Net_SFTP_Stream * @author Jim Wigginton * @version 0.3.2 * @access public - * @package Net_SFTP_Stream */ -class Net_SFTP_Stream { +class Net_SFTP_Stream +{ /** * SFTP instances * @@ -134,8 +134,12 @@ class Net_SFTP_Stream { */ function Net_SFTP_Stream() { + if (defined('NET_SFTP_STREAM_LOGGING')) { + echo "__construct()\r\n"; + } + if (!class_exists('Net_SFTP')) { - require_once('Net/SFTP.php'); + include_once 'Net/SFTP.php'; } } @@ -513,7 +517,7 @@ class Net_SFTP_Stream { * Open directory handle * * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and - * removed in 5.4 I'm just going to ignore it + * removed in 5.4 I'm just going to ignore it * * @param String $path * @param Integer $options diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php index 83d5980d00a..0a6aa908289 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH1.php @@ -1,5 +1,4 @@ * * - * More information on the SSHv1 specification can be found by reading + * More information on the SSHv1 specification can be found by reading * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}. * * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy @@ -45,10 +44,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -57,12 +56,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * - * @category Net - * @package Net_SSH1 - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Net + * @package Net_SSH1 + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /**#@+ @@ -202,11 +201,11 @@ define('NET_SSH1_LOG_COMPLEX', 2); /** * Outputs the content real-time */ -define('NET_SSH2_LOG_REALTIME', 3); +define('NET_SSH1_LOG_REALTIME', 3); /** * Dumps the content real-time to a file */ -define('NET_SSH2_LOG_REALTIME_FILE', 4); +define('NET_SSH1_LOG_REALTIME_FILE', 4); /**#@-*/ /**#@+ @@ -226,12 +225,13 @@ define('NET_SSH1_READ_REGEX', 2); /** * Pure-PHP implementation of SSHv1. * + * @package Net_SSH1 * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Net_SSH1 */ -class Net_SSH1 { +class Net_SSH1 +{ /** * The SSH identifier * @@ -429,11 +429,35 @@ class Net_SSH1 { /** * Current Timeout * - * @see Net_SSH2::_get_channel_packet() + * @see Net_SSH1::_get_channel_packet() * @access private */ var $curTimeout; + /** + * Log Boundary + * + * @see Net_SSH1::_format_log + * @access private + */ + var $log_boundary = ':'; + + /** + * Log Long Width + * + * @see Net_SSH1::_format_log + * @access private + */ + var $log_long_width = 65; + + /** + * Log Short Width + * + * @see Net_SSH1::_format_log + * @access private + */ + var $log_short_width = 16; + /** * Default Constructor. * @@ -449,16 +473,16 @@ class Net_SSH1 { function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES) { if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); + include_once 'Math/BigInteger.php'; } // Include Crypt_Random // the class_exists() will only be called if the crypt_random_string function hasn't been defined and // will trigger a call to __autoload() if you're wanting to auto-load classes - // call function_exists() a second time to stop the require_once from being called outside + // call function_exists() a second time to stop the include_once from being called outside // of the auto loader if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) { - require_once('Crypt/Random.php'); + include_once 'Crypt/Random.php'; } $this->protocol_flags = array( @@ -603,7 +627,7 @@ class Net_SSH1 { // break; case NET_SSH1_CIPHER_DES: if (!class_exists('Crypt_DES')) { - require_once('Crypt/DES.php'); + include_once 'Crypt/DES.php'; } $this->crypto = new Crypt_DES(); $this->crypto->disablePadding(); @@ -612,7 +636,7 @@ class Net_SSH1 { break; case NET_SSH1_CIPHER_3DES: if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC); $this->crypto->disablePadding(); @@ -621,7 +645,7 @@ class Net_SSH1 { break; //case NET_SSH1_CIPHER_RC4: // if (!class_exists('Crypt_RC4')) { - // require_once('Crypt/RC4.php'); + // include_once('Crypt/RC4.php'); // } // $this->crypto = new Crypt_RC4(); // $this->crypto->enableContinuousBuffer(); @@ -1017,7 +1041,7 @@ class Net_SSH1 { if ($this->curTimeout) { $read = array($this->fsock); - $write = $except = NULL; + $write = $except = null; $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 $sec = floor($this->curTimeout); @@ -1253,7 +1277,7 @@ class Net_SSH1 { { /* if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); + include_once 'Crypt/RSA.php'; } $rsa = new Crypt_RSA(); @@ -1318,7 +1342,7 @@ class Net_SSH1 { /** * Returns a log of the packets that have been sent and received. * - * Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING') + * Returns a string if NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX, an array if NET_SSH1_LOGGING == NET_SSH1_LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING') * * @access public * @return String or Array @@ -1351,8 +1375,6 @@ class Net_SSH1 { */ function _format_log($message_log, $message_number_log) { - static $boundary = ':', $long_width = 65, $short_width = 16; - $output = ''; for ($i = 0; $i < count($message_log); $i++) { $output.= $message_number_log[$i] . "\r\n"; @@ -1362,19 +1384,13 @@ class Net_SSH1 { if (strlen($current_log)) { $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; } - $fragment = $this->_string_shift($current_log, $short_width); - $hex = substr( - preg_replace( - '#(.)#es', - '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)', - $fragment), - strlen($boundary) - ); + $fragment = $this->_string_shift($current_log, $this->log_short_width); + $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary)); // replace non ASCII printable characters with dots // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters // also replace < with a . since < messes up the output on web browsers $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); - $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n"; + $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n"; $j++; } while (strlen($current_log)); $output.= "\r\n"; @@ -1383,6 +1399,20 @@ class Net_SSH1 { return $output; } + /** + * Helper function for _format_log + * + * For use with preg_replace_callback() + * + * @param Array $matches + * @access private + * @return String + */ + function _format_log_helper($matches) + { + return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT); + } + /** * Return the server key public exponent * @@ -1496,57 +1526,57 @@ class Net_SSH1 { */ function _append_log($protocol_flags, $message) { - switch (NET_SSH1_LOGGING) { - // useful for benchmarks - case NET_SSH1_LOG_SIMPLE: - $this->protocol_flags_log[] = $protocol_flags; - break; - // the most useful log for SSH1 - case NET_SSH1_LOG_COMPLEX: - $this->protocol_flags_log[] = $protocol_flags; - $this->_string_shift($message); - $this->log_size+= strlen($message); - $this->message_log[] = $message; - while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) { - $this->log_size-= strlen(array_shift($this->message_log)); - array_shift($this->protocol_flags_log); - } - break; - // dump the output out realtime; packets may be interspersed with non packets, - // passwords won't be filtered out and select other packets may not be correctly - // identified - case NET_SSH1_LOG_REALTIME: - echo "
\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n
\r\n"; - @flush(); - @ob_flush(); + switch (NET_SSH1_LOGGING) { + // useful for benchmarks + case NET_SSH1_LOG_SIMPLE: + $this->protocol_flags_log[] = $protocol_flags; + break; + // the most useful log for SSH1 + case NET_SSH1_LOG_COMPLEX: + $this->protocol_flags_log[] = $protocol_flags; + $this->_string_shift($message); + $this->log_size+= strlen($message); + $this->message_log[] = $message; + while ($this->log_size > NET_SSH1_LOG_MAX_SIZE) { + $this->log_size-= strlen(array_shift($this->message_log)); + array_shift($this->protocol_flags_log); + } + break; + // dump the output out realtime; packets may be interspersed with non packets, + // passwords won't be filtered out and select other packets may not be correctly + // identified + case NET_SSH1_LOG_REALTIME: + echo "
\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n
\r\n"; + @flush(); + @ob_flush(); + break; + // basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE + // needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE. + // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily + // at the beginning of the file + case NET_SSH1_LOG_REALTIME_FILE: + if (!isset($this->realtime_log_file)) { + // PHP doesn't seem to like using constants in fopen() + $filename = NET_SSH1_LOG_REALTIME_FILE; + $fp = fopen($filename, 'w'); + $this->realtime_log_file = $fp; + } + if (!is_resource($this->realtime_log_file)) { break; - // basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE - // needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE. - // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily - // at the beginning of the file - case NET_SSH1_LOG_REALTIME_FILE: - if (!isset($this->realtime_log_file)) { - // PHP doesn't seem to like using constants in fopen() - $filename = NET_SSH2_LOG_REALTIME_FILE; - $fp = fopen($filename, 'w'); - $this->realtime_log_file = $fp; - } - if (!is_resource($this->realtime_log_file)) { - break; - } - $entry = $this->_format_log(array($message), array($protocol_flags)); - if ($this->realtime_log_wrap) { - $temp = "<<< START >>>\r\n"; - $entry.= $temp; - fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); - } - $this->realtime_log_size+= strlen($entry); - if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) { - fseek($this->realtime_log_file, 0); - $this->realtime_log_size = strlen($entry); - $this->realtime_log_wrap = true; - } - fputs($this->realtime_log_file, $entry); - } + } + $entry = $this->_format_log(array($message), array($protocol_flags)); + if ($this->realtime_log_wrap) { + $temp = "<<< START >>>\r\n"; + $entry.= $temp; + fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); + } + $this->realtime_log_size+= strlen($entry); + if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) { + fseek($this->realtime_log_file, 0); + $this->realtime_log_size = strlen($entry); + $this->realtime_log_wrap = true; + } + fputs($this->realtime_log_file, $entry); + } } } diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php index dad03697233..2fddb68a9b2 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/Net/SSH2.php @@ -1,5 +1,4 @@ - * @copyright MMVII Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net + * @category Net + * @package Net_SSH2 + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net */ /**#@+ @@ -144,19 +143,20 @@ define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024); /** * Pure-PHP implementation of SSHv2. * + * @package Net_SSH2 * @author Jim Wigginton * @version 0.1.0 * @access public - * @package Net_SSH2 */ -class Net_SSH2 { +class Net_SSH2 +{ /** * The SSH identifier * * @var String * @access private */ - var $identifier = 'SSH-2.0-phpseclib_0.3'; + var $identifier; /** * The Socket Object @@ -747,6 +747,30 @@ class Net_SSH2 { */ var $is_timeout = false; + /** + * Log Boundary + * + * @see Net_SSH2::_format_log + * @access private + */ + var $log_boundary = ':'; + + /** + * Log Long Width + * + * @see Net_SSH2::_format_log + * @access private + */ + var $log_long_width = 65; + + /** + * Log Short Width + * + * @see Net_SSH2::_format_log + * @access private + */ + var $log_short_width = 16; + /** * Default Constructor. * @@ -763,15 +787,15 @@ class Net_SSH2 { // Include Math_BigInteger // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification. if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); + include_once 'Math/BigInteger.php'; } if (!function_exists('crypt_random_string')) { - require_once('Crypt/Random.php'); + include_once 'Crypt/Random.php'; } if (!class_exists('Crypt_Hash')) { - require_once('Crypt/Hash.php'); + include_once 'Crypt/Hash.php'; } $this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5 @@ -861,7 +885,7 @@ class Net_SSH2 { } $read = array($this->fsock); - $write = $except = NULL; + $write = $except = null; $sec = floor($timeout); $usec = 1000000 * ($timeout - $sec); @@ -895,19 +919,7 @@ class Net_SSH2 { return false; } - $ext = array(); - if (extension_loaded('mcrypt')) { - $ext[] = 'mcrypt'; - } - if (extension_loaded('gmp')) { - $ext[] = 'gmp'; - } else if (extension_loaded('bcmath')) { - $ext[] = 'bcmath'; - } - - if (!empty($ext)) { - $this->identifier.= ' (' . implode(', ', $ext) . ')'; - } + $this->identifier = $this->_generate_identifier(); if (defined('NET_SSH2_LOGGING')) { $this->_append_log('<-', $extra . $temp); @@ -944,6 +956,36 @@ class Net_SSH2 { $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR; } + /** + * Generates the SSH identifier + * + * You should overwrite this method in your own class if you want to use another identifier + * + * @access protected + * @return String + */ + function _generate_identifier() + { + $identifier = 'SSH-2.0-phpseclib_0.3'; + + $ext = array(); + if (extension_loaded('mcrypt')) { + $ext[] = 'mcrypt'; + } + + if (extension_loaded('gmp')) { + $ext[] = 'gmp'; + } elseif (extension_loaded('bcmath')) { + $ext[] = 'bcmath'; + } + + if (!empty($ext)) { + $identifier .= ' (' . implode(', ', $ext) . ')'; + } + + return $identifier; + } + /** * Key Exchange * @@ -1223,23 +1265,23 @@ class Net_SSH2 { } switch ($kex_algorithms[$i]) { - // see http://tools.ietf.org/html/rfc2409#section-6.2 and + // see http://tools.ietf.org/html/rfc2409#section-6.2 and // http://tools.ietf.org/html/rfc2412, appendex E case 'diffie-hellman-group1-sha1': - $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . + $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; break; // see http://tools.ietf.org/html/rfc3526#section-3 case 'diffie-hellman-group14-sha1': - $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . - '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . - '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . - 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . + $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . + '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . + '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . + 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; break; } @@ -1260,7 +1302,8 @@ class Net_SSH2 { -- http://tools.ietf.org/html/rfc4419#section-6.2 */ $one = new Math_BigInteger(1); $keyLength = min($keyLength, $kexHash->getLength()); - $max = $one->bitwise_leftShift(16 * $keyLength)->subtract($one); // 2 * 8 * $keyLength + $max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength + $max = $max->subtract($one); $x = $one->random($one, $max); $e = $g->modPow($x, $prime); @@ -1353,14 +1396,14 @@ class Net_SSH2 { switch ($encrypt) { case '3des-cbc': if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $this->encrypt = new Crypt_TripleDES(); // $this->encrypt_block_size = 64 / 8 == the default break; case '3des-ctr': if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); // $this->encrypt_block_size = 64 / 8 == the default @@ -1369,7 +1412,7 @@ class Net_SSH2 { case 'aes192-cbc': case 'aes128-cbc': if (!class_exists('Crypt_Rijndael')) { - require_once('Crypt/Rijndael.php'); + include_once 'Crypt/Rijndael.php'; } $this->encrypt = new Crypt_Rijndael(); $this->encrypt_block_size = 16; // eg. 128 / 8 @@ -1378,21 +1421,21 @@ class Net_SSH2 { case 'aes192-ctr': case 'aes128-ctr': if (!class_exists('Crypt_Rijndael')) { - require_once('Crypt/Rijndael.php'); + include_once 'Crypt/Rijndael.php'; } $this->encrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); $this->encrypt_block_size = 16; // eg. 128 / 8 break; case 'blowfish-cbc': if (!class_exists('Crypt_Blowfish')) { - require_once('Crypt/Blowfish.php'); + include_once 'Crypt/Blowfish.php'; } $this->encrypt = new Crypt_Blowfish(); $this->encrypt_block_size = 8; break; case 'blowfish-ctr': if (!class_exists('Crypt_Blowfish')) { - require_once('Crypt/Blowfish.php'); + include_once 'Crypt/Blowfish.php'; } $this->encrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); $this->encrypt_block_size = 8; @@ -1402,7 +1445,7 @@ class Net_SSH2 { case 'twofish256-cbc': case 'twofish-cbc': if (!class_exists('Crypt_Twofish')) { - require_once('Crypt/Twofish.php'); + include_once 'Crypt/Twofish.php'; } $this->encrypt = new Crypt_Twofish(); $this->encrypt_block_size = 16; @@ -1411,7 +1454,7 @@ class Net_SSH2 { case 'twofish192-ctr': case 'twofish256-ctr': if (!class_exists('Crypt_Twofish')) { - require_once('Crypt/Twofish.php'); + include_once 'Crypt/Twofish.php'; } $this->encrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); $this->encrypt_block_size = 16; @@ -1420,7 +1463,7 @@ class Net_SSH2 { case 'arcfour128': case 'arcfour256': if (!class_exists('Crypt_RC4')) { - require_once('Crypt/RC4.php'); + include_once 'Crypt/RC4.php'; } $this->encrypt = new Crypt_RC4(); break; @@ -1431,13 +1474,13 @@ class Net_SSH2 { switch ($decrypt) { case '3des-cbc': if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $this->decrypt = new Crypt_TripleDES(); break; case '3des-ctr': if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); + include_once 'Crypt/TripleDES.php'; } $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); break; @@ -1445,7 +1488,7 @@ class Net_SSH2 { case 'aes192-cbc': case 'aes128-cbc': if (!class_exists('Crypt_Rijndael')) { - require_once('Crypt/Rijndael.php'); + include_once 'Crypt/Rijndael.php'; } $this->decrypt = new Crypt_Rijndael(); $this->decrypt_block_size = 16; @@ -1454,21 +1497,21 @@ class Net_SSH2 { case 'aes192-ctr': case 'aes128-ctr': if (!class_exists('Crypt_Rijndael')) { - require_once('Crypt/Rijndael.php'); + include_once 'Crypt/Rijndael.php'; } $this->decrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); $this->decrypt_block_size = 16; break; case 'blowfish-cbc': if (!class_exists('Crypt_Blowfish')) { - require_once('Crypt/Blowfish.php'); + include_once 'Crypt/Blowfish.php'; } $this->decrypt = new Crypt_Blowfish(); $this->decrypt_block_size = 8; break; case 'blowfish-ctr': if (!class_exists('Crypt_Blowfish')) { - require_once('Crypt/Blowfish.php'); + include_once 'Crypt/Blowfish.php'; } $this->decrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); $this->decrypt_block_size = 8; @@ -1478,7 +1521,7 @@ class Net_SSH2 { case 'twofish256-cbc': case 'twofish-cbc': if (!class_exists('Crypt_Twofish')) { - require_once('Crypt/Twofish.php'); + include_once 'Crypt/Twofish.php'; } $this->decrypt = new Crypt_Twofish(); $this->decrypt_block_size = 16; @@ -1487,7 +1530,7 @@ class Net_SSH2 { case 'twofish192-ctr': case 'twofish256-ctr': if (!class_exists('Crypt_Twofish')) { - require_once('Crypt/Twofish.php'); + include_once 'Crypt/Twofish.php'; } $this->decrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); $this->decrypt_block_size = 16; @@ -1496,7 +1539,7 @@ class Net_SSH2 { case 'arcfour128': case 'arcfour256': if (!class_exists('Crypt_RC4')) { - require_once('Crypt/RC4.php'); + include_once 'Crypt/RC4.php'; } $this->decrypt = new Crypt_RC4(); break; @@ -1647,10 +1690,26 @@ class Net_SSH2 { * @param Mixed $password * @param Mixed $... * @return Boolean - * @see _login_helper + * @see _login * @access public */ function login($username) + { + $args = func_get_args(); + return call_user_func_array(array(&$this, '_login'), $args); + } + + /** + * Login Helper + * + * @param String $username + * @param Mixed $password + * @param Mixed $... + * @return Boolean + * @see _login_helper + * @access private + */ + function _login($username) { $args = array_slice(func_get_args(), 1); if (empty($args)) { @@ -1710,8 +1769,13 @@ class Net_SSH2 { } // although PHP5's get_class() preserves the case, PHP4's does not - if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') { - return $this->_privatekey_login($username, $password); + if (is_object($password)) { + switch (strtolower(get_class($password))) { + case 'crypt_rsa': + return $this->_privatekey_login($username, $password); + case 'system_ssh_agent': + return $this->_ssh_agent_login($username, $password); + } } if (is_array($password)) { @@ -1757,7 +1821,7 @@ class Net_SSH2 { // remove the username and password from the logged packet if (!defined('NET_SSH2_LOGGING')) { - $logged = NULL; + $logged = null; } else { $logged = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection', @@ -1821,7 +1885,7 @@ class Net_SSH2 { */ function _keyboard_interactive_login($username, $password) { - $packet = pack('CNa*Na*Na*Na*Na*', + $packet = pack('CNa*Na*Na*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', strlen('keyboard-interactive'), 'keyboard-interactive', 0, '', 0, '' ); @@ -1948,6 +2012,26 @@ class Net_SSH2 { return false; } + /** + * Login with an ssh-agent provided key + * + * @param String $username + * @param System_SSH_Agent $agent + * @return Boolean + * @access private + */ + function _ssh_agent_login($username, $agent) + { + $keys = $agent->requestIdentities(); + foreach ($keys as $key) { + if ($this->_privatekey_login($username, $key)) { + return true; + } + } + + return false; + } + /** * Login with an RSA private key * @@ -2056,7 +2140,7 @@ class Net_SSH2 { /** * Get the output from stdError - * + * * @access public */ function getStdError() @@ -2075,7 +2159,7 @@ class Net_SSH2 { * @return String * @access public */ - function exec($command, $callback = NULL) + function exec($command, $callback = null) { $this->curTimeout = $this->timeout; $this->is_timeout = false; @@ -2086,7 +2170,7 @@ class Net_SSH2 { } // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to - // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, + // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, // honestly, if you're transfering more than 2GB, you probably shouldn't be using phpseclib, anyway. // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; @@ -2143,7 +2227,7 @@ class Net_SSH2 { // neither will your script. // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by - // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the + // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates. $packet = pack('CNNa*CNa*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec'), 'exec', 1, strlen($command), $command); @@ -2349,7 +2433,6 @@ class Net_SSH2 { return false; } - $channel = $this->in_request_pty_exec ? NET_SSH2_CHANNEL_EXEC : NET_SSH2_CHANNEL_SHELL; return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd); } @@ -2430,8 +2513,7 @@ class Net_SSH2 { */ function reset() { - $channel = $this->in_request_pty_exec ? NET_SSH2_CHANNEL_EXEC : NET_SSH2_CHANNEL_SHELL; - $this->_close_channel($channel); + $this->_close_channel($this->_get_interactive_channel()); } /** @@ -2724,7 +2806,7 @@ class Net_SSH2 { } $read = array($this->fsock); - $write = $except = NULL; + $write = $except = null; $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 $sec = floor($this->curTimeout); @@ -2801,7 +2883,7 @@ class Net_SSH2 { /* if ($channel == NET_SSH2_CHANNEL_EXEC) { // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server - // this actually seems to make things twice as fast. more to the point, the message right after + // this actually seems to make things twice as fast. more to the point, the message right after // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise. // in OpenSSH it slows things down but only by a couple thousandths of a second. $this->_send_channel_packet($channel, chr(0)); @@ -2861,12 +2943,9 @@ class Net_SSH2 { case 'exit-status': extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5))); $this->exit_status = $exit_status; - // "The channel needs to be closed with SSH_MSG_CHANNEL_CLOSE after this message." - // -- http://tools.ietf.org/html/rfc4254#section-6.10 - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); - $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; + // "The client MAY ignore these messages." + // -- http://tools.ietf.org/html/rfc4254#section-6.10 break; default: @@ -2907,7 +2986,7 @@ class Net_SSH2 { * @return Boolean * @access private */ - function _send_binary_packet($data, $logged = NULL) + function _send_binary_packet($data, $logged = null) { if (!is_resource($this->fsock) || feof($this->fsock)) { user_error('Connection closed prematurely'); @@ -2967,70 +3046,70 @@ class Net_SSH2 { */ function _append_log($message_number, $message) { - // remove the byte identifying the message type from all but the first two messages (ie. the identification strings) - if (strlen($message_number) > 2) { - $this->_string_shift($message); - } + // remove the byte identifying the message type from all but the first two messages (ie. the identification strings) + if (strlen($message_number) > 2) { + $this->_string_shift($message); + } - switch (NET_SSH2_LOGGING) { - // useful for benchmarks - case NET_SSH2_LOG_SIMPLE: - $this->message_number_log[] = $message_number; - break; - // the most useful log for SSH2 - case NET_SSH2_LOG_COMPLEX: - $this->message_number_log[] = $message_number; - $this->log_size+= strlen($message); - $this->message_log[] = $message; - while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) { - $this->log_size-= strlen(array_shift($this->message_log)); - array_shift($this->message_number_log); - } - break; - // dump the output out realtime; packets may be interspersed with non packets, - // passwords won't be filtered out and select other packets may not be correctly - // identified - case NET_SSH2_LOG_REALTIME: - switch (PHP_SAPI) { - case 'cli': - $start = $stop = "\r\n"; - break; - default: - $start = '
';
-                            $stop = '
'; - } - echo $start . $this->_format_log(array($message), array($message_number)) . $stop; - @flush(); - @ob_flush(); - break; - // basically the same thing as NET_SSH2_LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILE - // needs to be defined and that the resultant log file will be capped out at NET_SSH2_LOG_MAX_SIZE. - // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily - // at the beginning of the file - case NET_SSH2_LOG_REALTIME_FILE: - if (!isset($this->realtime_log_file)) { - // PHP doesn't seem to like using constants in fopen() - $filename = NET_SSH2_LOG_REALTIME_FILENAME; - $fp = fopen($filename, 'w'); - $this->realtime_log_file = $fp; - } - if (!is_resource($this->realtime_log_file)) { + switch (NET_SSH2_LOGGING) { + // useful for benchmarks + case NET_SSH2_LOG_SIMPLE: + $this->message_number_log[] = $message_number; + break; + // the most useful log for SSH2 + case NET_SSH2_LOG_COMPLEX: + $this->message_number_log[] = $message_number; + $this->log_size+= strlen($message); + $this->message_log[] = $message; + while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) { + $this->log_size-= strlen(array_shift($this->message_log)); + array_shift($this->message_number_log); + } + break; + // dump the output out realtime; packets may be interspersed with non packets, + // passwords won't be filtered out and select other packets may not be correctly + // identified + case NET_SSH2_LOG_REALTIME: + switch (PHP_SAPI) { + case 'cli': + $start = $stop = "\r\n"; break; - } - $entry = $this->_format_log(array($message), array($message_number)); - if ($this->realtime_log_wrap) { - $temp = "<<< START >>>\r\n"; - $entry.= $temp; - fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); - } - $this->realtime_log_size+= strlen($entry); - if ($this->realtime_log_size > NET_SSH2_LOG_MAX_SIZE) { - fseek($this->realtime_log_file, 0); - $this->realtime_log_size = strlen($entry); - $this->realtime_log_wrap = true; - } - fputs($this->realtime_log_file, $entry); - } + default: + $start = '
';
+                        $stop = '
'; + } + echo $start . $this->_format_log(array($message), array($message_number)) . $stop; + @flush(); + @ob_flush(); + break; + // basically the same thing as NET_SSH2_LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILE + // needs to be defined and that the resultant log file will be capped out at NET_SSH2_LOG_MAX_SIZE. + // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily + // at the beginning of the file + case NET_SSH2_LOG_REALTIME_FILE: + if (!isset($this->realtime_log_file)) { + // PHP doesn't seem to like using constants in fopen() + $filename = NET_SSH2_LOG_REALTIME_FILENAME; + $fp = fopen($filename, 'w'); + $this->realtime_log_file = $fp; + } + if (!is_resource($this->realtime_log_file)) { + break; + } + $entry = $this->_format_log(array($message), array($message_number)); + if ($this->realtime_log_wrap) { + $temp = "<<< START >>>\r\n"; + $entry.= $temp; + fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); + } + $this->realtime_log_size+= strlen($entry); + if ($this->realtime_log_size > NET_SSH2_LOG_MAX_SIZE) { + fseek($this->realtime_log_file, 0); + $this->realtime_log_size = strlen($entry); + $this->realtime_log_wrap = true; + } + fputs($this->realtime_log_file, $entry); + } } /** @@ -3103,16 +3182,19 @@ class Net_SSH2 { * for SCP more than anything. * * @param Integer $client_channel + * @param Boolean $want_reply * @return Boolean * @access private */ - function _close_channel($client_channel) + function _close_channel($client_channel, $want_reply = false) { // see http://tools.ietf.org/html/rfc4254#section-5.3 $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); + if (!$want_reply) { + $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); + } $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE; @@ -3120,6 +3202,10 @@ class Net_SSH2 { while (!is_bool($this->_get_channel_packet($client_channel))); + if ($want_reply) { + $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); + } + if ($this->bitmap & NET_SSH2_MASK_SHELL) { $this->bitmap&= ~NET_SSH2_MASK_SHELL; } @@ -3220,8 +3306,6 @@ class Net_SSH2 { */ function _format_log($message_log, $message_number_log) { - static $boundary = ':', $long_width = 65, $short_width = 16; - $output = ''; for ($i = 0; $i < count($message_log); $i++) { $output.= $message_number_log[$i] . "\r\n"; @@ -3231,19 +3315,13 @@ class Net_SSH2 { if (strlen($current_log)) { $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; } - $fragment = $this->_string_shift($current_log, $short_width); - $hex = substr( - preg_replace( - '#(.)#es', - '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)', - $fragment), - strlen($boundary) - ); + $fragment = $this->_string_shift($current_log, $this->log_short_width); + $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary)); // replace non ASCII printable characters with dots // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters // also replace < with a . since < messes up the output on web browsers $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); - $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n"; + $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n"; $j++; } while (strlen($current_log)); $output.= "\r\n"; @@ -3252,6 +3330,20 @@ class Net_SSH2 { return $output; } + /** + * Helper function for _format_log + * + * For use with preg_replace_callback() + * + * @param Array $matches + * @access private + * @return String + */ + function _format_log_helper($matches) + { + return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT); + } + /** * Returns all errors * @@ -3505,7 +3597,7 @@ class Net_SSH2 { $signature = $this->_string_shift($signature, $temp['length']); if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); + include_once 'Crypt/RSA.php'; } $rsa = new Crypt_RSA(); @@ -3572,7 +3664,15 @@ class Net_SSH2 { */ function _is_includable($suffix) { - foreach (explode(PATH_SEPARATOR, get_include_path()) as $prefix) { + // stream_resolve_include_path was introduced in PHP 5.3.2 + if (function_exists('stream_resolve_include_path')) { + return stream_resolve_include_path($suffix) !== false; + } + + $paths = PATH_SEPARATOR == ':' ? + preg_split('#(? + * login('username', $agent)) { + * exit('Login Failed'); + * } + * + * echo $ssh->exec('pwd'); + * echo $ssh->exec('ls -la'); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category System + * @package System_SSH_Agent + * @author Jim Wigginton + * @copyright MMXIV Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + * @internal See http://api.libssh.org/rfc/PROTOCOL.agent + */ + +/**#@+ + * Message numbers + * + * @access private + */ +// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1) +define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11); +// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2). +define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12); +define('SYSTEM_SSH_AGENT_FAILURE', 5); +// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3) +define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13); +// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) +define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); +/**#@-*/ + +/** + * Pure-PHP ssh-agent client identity object + * + * Instantiation should only be performed by System_SSH_Agent class. + * This could be thought of as implementing an interface that Crypt_RSA + * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. + * The methods in this interface would be getPublicKey, setSignatureMode + * and sign since those are the methods phpseclib looks for to perform + * public key authentication. + * + * @package System_SSH_Agent + * @author Jim Wigginton + * @version 0.1.0 + * @access internal + */ +class System_SSH_Agent_Identity +{ + /** + * Key Object + * + * @var Crypt_RSA + * @access private + * @see System_SSH_Agent_Identity::getPublicKey() + */ + var $key; + + /** + * Key Blob + * + * @var String + * @access private + * @see System_SSH_Agent_Identity::sign() + */ + var $key_blob; + + /** + * Socket Resource + * + * @var Resource + * @access private + * @see System_SSH_Agent_Identity::sign() + */ + var $fsock; + + /** + * Default Constructor. + * + * @param Resource $fsock + * @return System_SSH_Agent_Identity + * @access private + */ + function System_SSH_Agent_Identity($fsock) + { + $this->fsock = $fsock; + } + + /** + * Set Public Key + * + * Called by System_SSH_Agent::requestIdentities() + * + * @param Crypt_RSA $key + * @access private + */ + function setPublicKey($key) + { + $this->key = $key; + $this->key->setPublicKey(); + } + + /** + * Set Public Key + * + * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key + * but this saves a small amount of computation. + * + * @param String $key_blob + * @access private + */ + function setPublicKeyBlob($key_blob) + { + $this->key_blob = $key_blob; + } + + /** + * Get Public Key + * + * Wrapper for $this->key->getPublicKey() + * + * @param Integer $format optional + * @return Mixed + * @access public + */ + function getPublicKey($format = null) + { + return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format); + } + + /** + * Set Signature Mode + * + * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie. + * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1 + * + * @param Integer $mode + * @access public + */ + function setSignatureMode($mode) + { + } + + /** + * Create a signature + * + * See "2.6.2 Protocol 2 private key signature request" + * + * @param String $message + * @return String + * @access public + */ + function sign($message) + { + // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE + $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0); + $packet = pack('Na*', strlen($packet), $packet); + if (strlen($packet) != fputs($this->fsock, $packet)) { + user_error('Connection closed during signing'); + } + + $length = current(unpack('N', fread($this->fsock, 4))); + $type = ord(fread($this->fsock, 1)); + if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) { + user_error('Unable to retreive signature'); + } + + $signature_blob = fread($this->fsock, $length - 1); + // the only other signature format defined - ssh-dss - is the same length as ssh-rsa + // the + 12 is for the other various SSH added length fields + return substr($signature_blob, strlen('ssh-rsa') + 12); + } +} + +/** + * Pure-PHP ssh-agent client identity factory + * + * requestIdentities() method pumps out System_SSH_Agent_Identity objects + * + * @package System_SSH_Agent + * @author Jim Wigginton + * @version 0.1.0 + * @access internal + */ +class System_SSH_Agent +{ + /** + * Socket Resource + * + * @var Resource + * @access private + */ + var $fsock; + + /** + * Default Constructor + * + * @return System_SSH_Agent + * @access public + */ + function System_SSH_Agent() + { + switch (true) { + case isset($_SERVER['SSH_AUTH_SOCK']): + $address = $_SERVER['SSH_AUTH_SOCK']; + break; + case isset($_ENV['SSH_AUTH_SOCK']): + $address = $_ENV['SSH_AUTH_SOCK']; + break; + default: + user_error('SSH_AUTH_SOCK not found'); + return false; + } + + $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); + if (!$this->fsock) { + user_error("Unable to connect to ssh-agent (Error $errno: $errstr)"); + } + } + + /** + * Request Identities + * + * See "2.5.2 Requesting a list of protocol 2 keys" + * Returns an array containing zero or more System_SSH_Agent_Identity objects + * + * @return Array + * @access public + */ + function requestIdentities() + { + if (!$this->fsock) { + return array(); + } + + $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES); + if (strlen($packet) != fputs($this->fsock, $packet)) { + user_error('Connection closed while requesting identities'); + } + + $length = current(unpack('N', fread($this->fsock, 4))); + $type = ord(fread($this->fsock, 1)); + if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) { + user_error('Unable to request identities'); + } + + $identities = array(); + $keyCount = current(unpack('N', fread($this->fsock, 4))); + for ($i = 0; $i < $keyCount; $i++) { + $length = current(unpack('N', fread($this->fsock, 4))); + $key_blob = fread($this->fsock, $length); + $length = current(unpack('N', fread($this->fsock, 4))); + $key_comment = fread($this->fsock, $length); + $length = current(unpack('N', substr($key_blob, 0, 4))); + $key_type = substr($key_blob, 4, $length); + switch ($key_type) { + case 'ssh-rsa': + if (!class_exists('Crypt_RSA')) { + include_once 'Crypt/RSA.php'; + } + $key = new Crypt_RSA(); + $key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment); + break; + case 'ssh-dss': + // not currently supported + break; + } + // resources are passed by reference by default + if (isset($key)) { + $identity = new System_SSH_Agent_Identity($this->fsock); + $identity->setPublicKey($key); + $identity->setPublicKeyBlob($key_blob); + $identities[] = $identity; + unset($key); + } + } + + return $identities; + } +} diff --git a/apps/files_external/3rdparty/phpseclib/phpseclib/openssl.cnf b/apps/files_external/3rdparty/phpseclib/phpseclib/openssl.cnf index 6baa566102c..2b8b52f9f7f 100644 --- a/apps/files_external/3rdparty/phpseclib/phpseclib/openssl.cnf +++ b/apps/files_external/3rdparty/phpseclib/phpseclib/openssl.cnf @@ -3,4 +3,4 @@ HOME = . RANDFILE = $ENV::HOME/.rnd -[ v3_ca ] \ No newline at end of file +[ v3_ca ] diff --git a/apps/files_external/3rdparty/smb4php/smb.php b/apps/files_external/3rdparty/smb4php/smb.php index 656930514f0..e325506fa14 100644 --- a/apps/files_external/3rdparty/smb4php/smb.php +++ b/apps/files_external/3rdparty/smb4php/smb.php @@ -8,6 +8,8 @@ # Homepage: http://www.phpclasses.org/smb4php # # Copyright (c) 2007 Victor M. Varela +# Copyright (c) 2012 Frank Karlitschek +# Copyright (c) 2014 Robin McCorkell # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -19,8 +21,6 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # -# Addition 17/12/2012 Frank Karlitschek (frank@owncloud.org) -# Addition 17/03/2014 Robin McCorkell (rmccorkell@karoshi.org.uk) # On the official website http://www.phpclasses.org/smb4php the # license is listed as LGPL so we assume that this is # dual-licensed GPL/LGPL @@ -44,6 +44,42 @@ $GLOBALS['__smb_cache'] = array ('stat' => array (), 'dir' => array ()); class smb { + private static $regexp = array ( + '^added interface ip=(.*) bcast=(.*) nmask=(.*)$' => 'skip', + 'Anonymous login successful' => 'skip', + '^Domain=\[(.*)\] OS=\[(.*)\] Server=\[(.*)\]$' => 'skip', + '^\tSharename[ ]+Type[ ]+Comment$' => 'shares', + '^\t---------[ ]+----[ ]+-------$' => 'skip', + '^\tServer [ ]+Comment$' => 'servers', + '^\t---------[ ]+-------$' => 'skip', + '^\tWorkgroup[ ]+Master$' => 'workg', + '^\t(.*)[ ]+(Disk|IPC)[ ]+IPC.*$' => 'skip', + '^\tIPC\\\$(.*)[ ]+IPC' => 'skip', + '^\t(.*)[ ]+(Disk)[ ]+(.*)$' => 'share', + '^\t(.*)[ ]+(Printer)[ ]+(.*)$' => 'skip', + '([0-9]+) blocks of size ([0-9]+)\. ([0-9]+) blocks available' => 'skip', + 'Got a positive name query response from ' => 'skip', + '^(session setup failed): (.*)$' => 'error', + '^(.*): ERRSRV - ERRbadpw' => 'error', + '^Error returning browse list: (.*)$' => 'error', + '^tree connect failed: (.*)$' => 'error', + '^(Connection to .* failed)(.*)$' => 'error-connect', + '^NT_STATUS_(.*) ' => 'error', + '^NT_STATUS_(.*)\$' => 'error', + 'ERRDOS - ERRbadpath \((.*).\)' => 'error', + 'cd (.*): (.*)$' => 'error', + '^cd (.*): NT_STATUS_(.*)' => 'error', + '^\t(.*)$' => 'srvorwg', + '^([0-9]+)[ ]+([0-9]+)[ ]+(.*)$' => 'skip', + '^Job ([0-9]+) cancelled' => 'skip', + '^[ ]+(.*)[ ]+([0-9]+)[ ]+(Mon|Tue|Wed|Thu|Fri|Sat|Sun)[ ](Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ]+([0-9]+)[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]([0-9]{4})$' => 'files', + '^message start: ERRSRV - (ERRmsgoff)' => 'error' + ); + + function getRegexp() { + return self::$regexp; + } + function parse_url ($url) { $pu = parse_url (trim($url)); foreach (array ('domain', 'user', 'pass', 'host', 'port', 'path') as $i) { @@ -75,46 +111,16 @@ class smb { } - function execute ($command, $purl) { + function execute ($command, $purl, $regexp = NULL) { return smb::client ('-d 0 ' . escapeshellarg ('//' . $purl['host'] . '/' . $purl['share']) - . ' -c ' . escapeshellarg ($command), $purl + . ' -c ' . escapeshellarg ($command), $purl, $regexp ); } - function client ($params, $purl) { - - static $regexp = array ( - '^added interface ip=(.*) bcast=(.*) nmask=(.*)$' => 'skip', - 'Anonymous login successful' => 'skip', - '^Domain=\[(.*)\] OS=\[(.*)\] Server=\[(.*)\]$' => 'skip', - '^\tSharename[ ]+Type[ ]+Comment$' => 'shares', - '^\t---------[ ]+----[ ]+-------$' => 'skip', - '^\tServer [ ]+Comment$' => 'servers', - '^\t---------[ ]+-------$' => 'skip', - '^\tWorkgroup[ ]+Master$' => 'workg', - '^\t(.*)[ ]+(Disk|IPC)[ ]+IPC.*$' => 'skip', - '^\tIPC\\\$(.*)[ ]+IPC' => 'skip', - '^\t(.*)[ ]+(Disk)[ ]+(.*)$' => 'share', - '^\t(.*)[ ]+(Printer)[ ]+(.*)$' => 'skip', - '([0-9]+) blocks of size ([0-9]+)\. ([0-9]+) blocks available' => 'skip', - 'Got a positive name query response from ' => 'skip', - '^(session setup failed): (.*)$' => 'error', - '^(.*): ERRSRV - ERRbadpw' => 'error', - '^Error returning browse list: (.*)$' => 'error', - '^tree connect failed: (.*)$' => 'error', - '^(Connection to .* failed)(.*)$' => 'error-connect', - '^NT_STATUS_(.*) ' => 'error', - '^NT_STATUS_(.*)\$' => 'error', - 'ERRDOS - ERRbadpath \((.*).\)' => 'error', - 'cd (.*): (.*)$' => 'error', - '^cd (.*): NT_STATUS_(.*)' => 'error', - '^\t(.*)$' => 'srvorwg', - '^([0-9]+)[ ]+([0-9]+)[ ]+(.*)$' => 'skip', - '^Job ([0-9]+) cancelled' => 'skip', - '^[ ]+(.*)[ ]+([0-9]+)[ ]+(Mon|Tue|Wed|Thu|Fri|Sat|Sun)[ ](Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ]+([0-9]+)[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]([0-9]{4})$' => 'files', - '^message start: ERRSRV - (ERRmsgoff)' => 'error' - ); + function client ($params, $purl, $regexp = NULL) { + + if ($regexp === NULL) $regexp = smb::$regexp; if (SMB4PHP_AUTHMODE == 'env') { putenv("USER={$purl['user']}%{$purl['pass']}"); diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index 0e83660f845..0017b22caad 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -1,6 +1,7 @@ + * Copyright (c) 2014 Robin McCorkell * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. @@ -13,6 +14,7 @@ OC::$CLASSPATH['OC\Files\Storage\OwnCloud'] = 'files_external/lib/owncloud.php'; OC::$CLASSPATH['OC\Files\Storage\Google'] = 'files_external/lib/google.php'; OC::$CLASSPATH['OC\Files\Storage\Swift'] = 'files_external/lib/swift.php'; OC::$CLASSPATH['OC\Files\Storage\SMB'] = 'files_external/lib/smb.php'; +OC::$CLASSPATH['OC\Files\Storage\SMB_OC'] = 'files_external/lib/smb_oc.php'; OC::$CLASSPATH['OC\Files\Storage\AmazonS3'] = 'files_external/lib/amazons3.php'; OC::$CLASSPATH['OC\Files\Storage\Dropbox'] = 'files_external/lib/dropbox.php'; OC::$CLASSPATH['OC\Files\Storage\SFTP'] = 'files_external/lib/sftp.php'; @@ -27,4 +29,138 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == ' // connecting hooks OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook'); OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login'); +OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login'); +OC_Mount_Config::registerBackend('\OC\Files\Storage\Local', array( + 'backend' => 'Local', + 'configuration' => array( + 'datadir' => 'Location'))); + +OC_Mount_Config::registerBackend('\OC\Files\Storage\AmazonS3', array( + 'backend' => 'Amazon S3', + 'configuration' => array( + 'key' => 'Key', + 'secret' => '*Secret', + 'bucket' => 'Bucket'), + 'has_dependencies' => true)); + +OC_Mount_Config::registerBackend('\OC\Files\Storage\AmazonS3', array( + 'backend' => 'Amazon S3 and compliant', + 'configuration' => array( + 'key' => 'Access Key', + 'secret' => '*Secret Key', + 'bucket' => 'Bucket', + 'hostname' => '&Hostname (optional)', + 'port' => '&Port (optional)', + 'region' => '&Region (optional)', + 'use_ssl' => '!Enable SSL', + 'use_path_style' => '!Enable Path Style'), + 'has_dependencies' => true)); + +OC_Mount_Config::registerBackend('\OC\Files\Storage\Dropbox', array( + 'backend' => 'Dropbox', + 'configuration' => array( + 'configured' => '#configured', + 'app_key' => 'App key', + 'app_secret' => '*App secret', + 'token' => '#token', + 'token_secret' => '#token_secret'), + 'custom' => 'dropbox', + 'has_dependencies' => true)); + +OC_Mount_Config::registerBackend('\OC\Files\Storage\FTP', array( + 'backend' => 'FTP', + 'configuration' => array( + 'host' => 'URL', + 'user' => 'Username', + 'password' => '*Password', + 'root' => '&Root', + 'secure' => '!Secure ftps://'), + 'has_dependencies' => true)); + +OC_Mount_Config::registerBackend('\OC\Files\Storage\Google', array( + 'backend' => 'Google Drive', + 'configuration' => array( + 'configured' => '#configured', + 'client_id' => 'Client ID', + 'client_secret' => '*Client secret', + 'token' => '#token'), + 'custom' => 'google', + 'has_dependencies' => true)); + + +OC_Mount_Config::registerBackend('\OC\Files\Storage\Swift', array( + 'backend' => 'OpenStack Object Storage', + 'configuration' => array( + 'user' => 'Username (required)', + 'bucket' => 'Bucket (required)', + 'region' => '&Region (optional for OpenStack Object Storage)', + 'key' => '*API Key (required for Rackspace Cloud Files)', + 'tenant' => '&Tenantname (required for OpenStack Object Storage)', + 'password' => '*Password (required for OpenStack Object Storage)', + 'service_name' => '&Service Name (required for OpenStack Object Storage)', + 'url' => '&URL of identity endpoint (required for OpenStack Object Storage)', + 'timeout' => '&Timeout of HTTP requests in seconds (optional)', + ), + 'has_dependencies' => true)); + + +if (!OC_Util::runningOnWindows()) { + OC_Mount_Config::registerBackend('\OC\Files\Storage\SMB', array( + 'backend' => 'SMB / CIFS', + 'configuration' => array( + 'host' => 'URL', + 'user' => 'Username', + 'password' => '*Password', + 'share' => 'Share', + 'root' => '&Root'), + 'has_dependencies' => true)); + + OC_Mount_Config::registerBackend('\OC\Files\Storage\SMB_OC', array( + 'backend' => 'SMB / CIFS using OC login', + 'configuration' => array( + 'host' => 'URL', + 'username_as_share' => '!Username as share', + 'share' => '&Share', + 'root' => '&Root'), + 'has_dependencies' => true)); +} + +OC_Mount_Config::registerBackend('\OC\Files\Storage\DAV', array( + 'backend' => 'WebDAV', + 'configuration' => array( + 'host' => 'URL', + 'user' => 'Username', + 'password' => '*Password', + 'root' => '&Root', + 'secure' => '!Secure https://'), + 'has_dependencies' => true)); + +OC_Mount_Config::registerBackend('\OC\Files\Storage\OwnCloud', array( + 'backend' => 'ownCloud', + 'configuration' => array( + 'host' => 'URL', + 'user' => 'Username', + 'password' => '*Password', + 'root' => '&Remote subfolder', + 'secure' => '!Secure https://'))); + + +OC_Mount_Config::registerBackend('\OC\Files\Storage\SFTP', array( + 'backend' => 'SFTP', + 'configuration' => array( + 'host' => 'URL', + 'user' => 'Username', + 'password' => '*Password', + 'root' => '&Root'))); + +OC_Mount_Config::registerBackend('\OC\Files\Storage\iRODS', array( + 'backend' => 'iRODS', + 'configuration' => array( + 'host' => 'Host', + 'port' => 'Port', + 'use_logon_credentials' => '!Use ownCloud login', + 'user' => 'Username', + 'password' => '*Password', + 'auth_mode' => 'Authentication Mode', + 'zone' => 'Zone'))); diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index cd2a3103eb7..00793a614c2 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -181,16 +181,21 @@ $(document).ready(function() { $.each(configurations, function(backend, parameters) { if (backend == backendClass) { $.each(parameters['configuration'], function(parameter, placeholder) { - if (placeholder.indexOf('*') != -1) { - td.append(''); - } else if (placeholder.indexOf('!') != -1) { + var is_optional = false; + if (placeholder.indexOf('&') === 0) { + is_optional = true; + placeholder = placeholder.substring(1); + } + if (placeholder.indexOf('*') === 0) { + var class_string = is_optional ? ' class="optional"' : ''; + td.append(''); + } else if (placeholder.indexOf('!') === 0) { td.append(''); - } else if (placeholder.indexOf('&') != -1) { - td.append(''); - } else if (placeholder.indexOf('#') != -1) { + } else if (placeholder.indexOf('#') === 0) { td.append(''); } else { - td.append(''); + var class_string = is_optional ? ' class="optional"' : ''; + td.append(''); } }); if (parameters['custom'] && $('#externalStorage tbody tr.'+backendClass.replace(/\\/g, '\\\\')).length == 1) { diff --git a/apps/files_external/l10n/ast.php b/apps/files_external/l10n/ast.php new file mode 100644 index 00000000000..7061cffaa8e --- /dev/null +++ b/apps/files_external/l10n/ast.php @@ -0,0 +1,9 @@ + "Nome de la carpeta", +"Options" => "Opciones", +"Groups" => "Grupos", +"Users" => "Usuarios", +"Delete" => "Desaniciar" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files_external/l10n/bg_BG.php b/apps/files_external/l10n/bg_BG.php index d59a4b8c80b..118da27f74a 100644 --- a/apps/files_external/l10n/bg_BG.php +++ b/apps/files_external/l10n/bg_BG.php @@ -6,8 +6,6 @@ $TRANSLATIONS = array( "Folder name" => "Име на папката", "Configuration" => "Конфигурация", "Options" => "Опции", -"Applicable" => "Приложимо", -"None set" => "Няма избрано", "All Users" => "Всички потребители", "Groups" => "Групи", "Users" => "Потребители", diff --git a/apps/files_external/l10n/bn_BD.php b/apps/files_external/l10n/bn_BD.php index 065d61acfca..6c8f5777958 100644 --- a/apps/files_external/l10n/bn_BD.php +++ b/apps/files_external/l10n/bn_BD.php @@ -8,8 +8,6 @@ $TRANSLATIONS = array( "External Storage" => "বাহ্যিক সংরক্ষণাগার", "Configuration" => "কনফিগারেসন", "Options" => "বিকল্পসমূহ", -"Applicable" => "প্রযোজ্য", -"None set" => "কোনটিই নির্ধারণ করা হয় নি", "All Users" => "সমস্ত ব্যবহারকারী", "Groups" => "গোষ্ঠীসমূহ", "Users" => "ব্যবহারকারী", diff --git a/apps/files_external/l10n/ca.php b/apps/files_external/l10n/ca.php index 3e722046296..50b6f55231b 100644 --- a/apps/files_external/l10n/ca.php +++ b/apps/files_external/l10n/ca.php @@ -6,17 +6,12 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Proporcioneu una clau d'aplicació i secret vàlids per a Dropbox", "Error configuring Google Drive storage" => "Error en configurar l'emmagatzemament Google Drive", "Saved" => "Desat", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Avís: \"smbclient\" no està instal·lat. No es pot muntar la compartició CIFS/SMB. Demaneu a l'administrador del sistema que l'instal·li.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Avís: El suport FTP per PHP no està activat o no està instal·lat. No es pot muntar la compartició FTP. Demaneu a l'administrador del sistema que l'instal·li.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Avís:El suport Curl de PHP no està activat o instal·lat. No es pot muntar ownCloud / WebDAV o GoogleDrive. Demaneu a l'administrador que l'instal·li.", "External Storage" => "Emmagatzemament extern", "Folder name" => "Nom de la carpeta", "External storage" => "Emmagatzemament extern", "Configuration" => "Configuració", "Options" => "Options", -"Applicable" => "Aplicable", "Add storage" => "Afegeix emmagatzemament", -"None set" => "Cap d'establert", "All Users" => "Tots els usuaris", "Groups" => "Grups", "Users" => "Usuaris", diff --git a/apps/files_external/l10n/cs_CZ.php b/apps/files_external/l10n/cs_CZ.php index 1b92e35c456..6a4e09aa3ab 100644 --- a/apps/files_external/l10n/cs_CZ.php +++ b/apps/files_external/l10n/cs_CZ.php @@ -6,17 +6,12 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Zadejte, prosím, platný klíč a bezpečnostní frázi aplikace Dropbox.", "Error configuring Google Drive storage" => "Chyba při nastavení úložiště Google Drive", "Saved" => "Uloženo", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Varování: není nainstalován program \"smbclient\". Není možné připojení oddílů CIFS/SMB. Prosím požádejte svého správce systému ať jej nainstaluje.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Varování: podpora FTP v PHP není povolena nebo není nainstalována. Není možné připojení oddílů FTP. Prosím požádejte svého správce systému ať ji nainstaluje.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Varování: podpora CURL v PHP není povolena nebo není nainstalována. Není možné připojení oddílů ownCloud, WebDAV, či GoogleDrive. Prosím požádejte svého správce systému ať ji nainstaluje.", "External Storage" => "Externí úložiště", "Folder name" => "Název složky", "External storage" => "Externí úložiště", "Configuration" => "Nastavení", "Options" => "Možnosti", -"Applicable" => "Přístupný pro", "Add storage" => "Přidat úložiště", -"None set" => "Nenastaveno", "All Users" => "Všichni uživatelé", "Groups" => "Skupiny", "Users" => "Uživatelé", diff --git a/apps/files_external/l10n/da.php b/apps/files_external/l10n/da.php index f3ac35e42e0..e0dea75303e 100644 --- a/apps/files_external/l10n/da.php +++ b/apps/files_external/l10n/da.php @@ -6,17 +6,12 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Angiv venligst en valid Dropbox app nøgle og hemmelighed", "Error configuring Google Drive storage" => "Fejl ved konfiguration af Google Drive plads", "Saved" => "Gemt", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => " Advarsel: \"smbclient\" ikke er installeret. Montering af CIFS / SMB delinger er ikke muligt. Spørg din systemadministrator om at installere det.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => " Advarsel: FTP-understøttelse i PHP ikke er aktiveret eller installeret. Montering af FTP delinger er ikke muligt. Spørg din systemadministrator om at installere det.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Advarsel: Understøttelsen for Curl i PHP er enten ikke aktiveret eller ikke installeret. Det er ikke muligt, at montere ownCloud / WebDAV eller GoogleDrive. Spørg din system administrator om at installere det. ", "External Storage" => "Ekstern opbevaring", "Folder name" => "Mappenavn", "External storage" => "Eksternt lager", "Configuration" => "Opsætning", "Options" => "Valgmuligheder", -"Applicable" => "Kan anvendes", "Add storage" => "Tilføj lager", -"None set" => "Ingen sat", "All Users" => "Alle brugere", "Groups" => "Grupper", "Users" => "Brugere", diff --git a/apps/files_external/l10n/de.php b/apps/files_external/l10n/de.php index a78728b4c20..25c7ffb3af1 100644 --- a/apps/files_external/l10n/de.php +++ b/apps/files_external/l10n/de.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Bitte trage einen gültigen Dropbox-App-Key mit Secret ein.", "Error configuring Google Drive storage" => "Fehler beim Einrichten von Google Drive", "Saved" => "Gespeichert", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Warnung: \"smbclient\" ist nicht installiert. Das Einhängen von CIFS/SMB-Freigaben ist nicht möglich. Bitte Deinen System-Administrator, dies zu installieren.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Warnung:: Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Bitte wende Dich an Deinen Systemadministrator.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Warnung: Die Curl-Unterstützung in PHP ist nicht aktiviert oder installiert. Das Einbinden von ownCloud / WebDav der GoogleDrive-Freigaben ist nicht möglich. Bitte Deinen Systemadminstrator um die Installation. ", +"Note: " => "Hinweis: ", +" and " => "und", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Hinweis: Die cURL-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wende Dich zur Installation an Deinen Systemadministrator.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Hinweis: Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wende Dich sich zur Installation an Deinen Systemadministrator.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Hinweis: \"%s\" ist nicht installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wende Dich sich zur Installation an Deinen Systemadministrator.", "External Storage" => "Externer Speicher", "Folder name" => "Ordnername", "External storage" => "Externer Speicher", "Configuration" => "Konfiguration", "Options" => "Optionen", -"Applicable" => "Zutreffend", +"Available for" => "Verfügbar für", "Add storage" => "Speicher hinzufügen", -"None set" => "Nicht definiert", +"No user or group" => "Kein Nutzer oder Gruppe", "All Users" => "Alle Benutzer", "Groups" => "Gruppen", "Users" => "Benutzer", diff --git a/apps/files_external/l10n/de_CH.php b/apps/files_external/l10n/de_CH.php index 8a13c7cdd57..554fca8de54 100644 --- a/apps/files_external/l10n/de_CH.php +++ b/apps/files_external/l10n/de_CH.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Zugriff gestatten", "Please provide a valid Dropbox app key and secret." => "Bitte tragen Sie einen gültigen Dropbox-App-Key mit Secret ein.", "Error configuring Google Drive storage" => "Fehler beim Einrichten von Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Warnung: «smbclient» ist nicht installiert. Das Einhängen von CIFS/SMB-Freigaben ist nicht möglich. Bitten Sie Ihren Systemadministrator, dies zu installieren.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Warnung:: Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Bitte wenden Sie sich an Ihren Systemadministrator.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Achtung: Die Curl-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Laden von ownCloud / WebDAV oder GoogleDrive Freigaben ist nicht möglich. Bitte Sie Ihren Systemadministrator, das Modul zu installieren.", "External Storage" => "Externer Speicher", "Folder name" => "Ordnername", "External storage" => "Externer Speicher", "Configuration" => "Konfiguration", "Options" => "Optionen", -"Applicable" => "Zutreffend", "Add storage" => "Speicher hinzufügen", -"None set" => "Nicht definiert", "All Users" => "Alle Benutzer", "Groups" => "Gruppen", "Users" => "Benutzer", diff --git a/apps/files_external/l10n/de_DE.php b/apps/files_external/l10n/de_DE.php index 5ffe946c699..186aa5a299a 100644 --- a/apps/files_external/l10n/de_DE.php +++ b/apps/files_external/l10n/de_DE.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Bitte tragen Sie einen gültigen Dropbox-App-Key mit Secret ein.", "Error configuring Google Drive storage" => "Fehler beim Einrichten von Google Drive", "Saved" => "Gespeichert", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Warnung: \"smbclient\" ist nicht installiert. Das Einhängen von CIFS/SMB-Freigaben ist nicht möglich. Bitten Sie Ihren Systemadministrator, dies zu installieren.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Warnung:: Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Bitte wenden Sie sich an Ihren Systemadministrator.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Achtung: Die Curl-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Laden von ownCloud / WebDAV oder GoogleDrive Freigaben ist nicht möglich. Bitte Sie Ihren Systemadministrator, das Modul zu installieren.", +"Note: " => "Hinweis: ", +" and " => "und", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Hinweis: Die cURL-Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wenden Sie sich zur Installation an Ihren Systemadministrator.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Hinweis: Die FTP Unterstützung von PHP ist nicht aktiviert oder installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wenden Sie sich zur Installation an Ihren Systemadministrator.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Hinweis: \"%s\" ist nicht installiert. Das Hinzufügen von %s ist nicht möglich. Bitte wenden Sie sich zur Installation an Ihren Systemadministrator.", "External Storage" => "Externer Speicher", "Folder name" => "Ordnername", "External storage" => "Externer Speicher", "Configuration" => "Konfiguration", "Options" => "Optionen", -"Applicable" => "Zutreffend", +"Available for" => "Verfügbar für", "Add storage" => "Speicher hinzufügen", -"None set" => "Nicht definiert", +"No user or group" => "Kein Nutzer oder Gruppe", "All Users" => "Alle Benutzer", "Groups" => "Gruppen", "Users" => "Benutzer", diff --git a/apps/files_external/l10n/el.php b/apps/files_external/l10n/el.php index 4dcd93d7ac8..16b837e24c5 100644 --- a/apps/files_external/l10n/el.php +++ b/apps/files_external/l10n/el.php @@ -6,22 +6,18 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Παρακαλούμε δώστε έγκυρο κλειδί Dropbox και μυστικό.", "Error configuring Google Drive storage" => "Σφάλμα ρυθμίζωντας αποθήκευση Google Drive ", "Saved" => "Αποθηκεύτηκαν", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Προσοχή: Ο \"smbclient\" δεν εγκαταστάθηκε. Δεν είναι δυνατή η προσάρτηση CIFS/SMB. Παρακαλώ ενημερώστε τον διαχειριστή συστήματος να το εγκαταστήσει.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Προσοχή: Η υποστήριξη FTP στην PHP δεν ενεργοποιήθηκε ή εγκαταστάθηκε. Δεν είναι δυνατή η προσάρτηση FTP. Παρακαλώ ενημερώστε τον διαχειριστή συστήματος να το εγκαταστήσει.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<Προειδοποίηση Η υποστήριξη του συστήματος Curl στο PHP δεν είναι ενεργοποιημένη ή εγκαταστημένη. Η αναπαραγωγή του ownCloud/WebDAV ή GoogleDrive δεν είναι δυνατή. Παρακαλώ ρωτήστε τον διαχειριστλη του συστήματος για την εγκατάσταση. ", "External Storage" => "Εξωτερικό Αποθηκευτικό Μέσο", "Folder name" => "Όνομα φακέλου", "External storage" => "Εξωτερική αποθήκευση", "Configuration" => "Ρυθμίσεις", "Options" => "Επιλογές", -"Applicable" => "Εφαρμόσιμο", "Add storage" => "Προσθηκη αποθηκευσης", -"None set" => "Κανένα επιλεγμένο", "All Users" => "Όλοι οι Χρήστες", "Groups" => "Ομάδες", "Users" => "Χρήστες", "Delete" => "Διαγραφή", "Enable User External Storage" => "Ενεργοποίηση Εξωτερικού Αποθηκευτικού Χώρου Χρήστη", +"Allow users to mount the following external storage" => "Χορήγηση άδειας στους χρήστες να συνδέσουν τα παρακάτω εξωτερικά μέσα αποθήκευσης", "SSL root certificates" => "Πιστοποιητικά SSL root", "Import Root Certificate" => "Εισαγωγή Πιστοποιητικού Root" ); diff --git a/apps/files_external/l10n/en_GB.php b/apps/files_external/l10n/en_GB.php index f7fdbf2f0d1..4bd3f9daf2a 100644 --- a/apps/files_external/l10n/en_GB.php +++ b/apps/files_external/l10n/en_GB.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Please provide a valid Dropbox app key and secret.", "Error configuring Google Drive storage" => "Error configuring Google Drive storage", "Saved" => "Saved", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it.", +"Note: " => "Note: ", +" and " => " and ", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.", "External Storage" => "External Storage", "Folder name" => "Folder name", "External storage" => "External storage", "Configuration" => "Configuration", "Options" => "Options", -"Applicable" => "Applicable", +"Available for" => "Available for", "Add storage" => "Add storage", -"None set" => "None set", +"No user or group" => "No user or group", "All Users" => "All Users", "Groups" => "Groups", "Users" => "Users", diff --git a/apps/files_external/l10n/eo.php b/apps/files_external/l10n/eo.php index aba16e2efa8..5312872c07a 100644 --- a/apps/files_external/l10n/eo.php +++ b/apps/files_external/l10n/eo.php @@ -9,8 +9,6 @@ $TRANSLATIONS = array( "Folder name" => "Dosierujnomo", "Configuration" => "Agordo", "Options" => "Malneproj", -"Applicable" => "Aplikebla", -"None set" => "Nenio agordita", "All Users" => "Ĉiuj uzantoj", "Groups" => "Grupoj", "Users" => "Uzantoj", diff --git a/apps/files_external/l10n/es.php b/apps/files_external/l10n/es.php index ea831c947f4..bfe542c6e71 100644 --- a/apps/files_external/l10n/es.php +++ b/apps/files_external/l10n/es.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Por favor, proporcione un una clave válida de la app Dropbox y una clave secreta.", "Error configuring Google Drive storage" => "Error configurando el almacenamiento de Google Drive", "Saved" => "Guardado", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Advertencia: El cliente smb (smbclient) no se encuentra instalado. El montado de archivos o ficheros CIFS/SMB no es posible. Por favor pida al administrador de su sistema que lo instale.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Advertencia: El soporte de FTP en PHP no se encuentra instalado. El montado de archivos o ficheros FTP no es posible. Por favor pida al administrador de su sistema que lo instale.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Advertencia: El soporte de Curl en PHP no está activado ni instalado. El montado de ownCloud, WebDAV o GoogleDrive no es posible. Pida al administrador de su sistema que lo instale.", +"Note: " => "Nota: ", +" and " => "y", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: El soporte de cURL en PHP no está activado o instalado. No se puede montar %s. Pídale al administrador de sistema que lo instale.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: El soporte de FTP en PHP no está activado o instalado. No se puede montar %s. Pídale al administrador de sistema que lo instale.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: \"%s\" no está instalado. No se puede montar %s. Pídale al administrador de sistema que lo instale.", "External Storage" => "Almacenamiento externo", "Folder name" => "Nombre de la carpeta", "External storage" => "Almacenamiento externo", "Configuration" => "Configuración", "Options" => "Opciones", -"Applicable" => "Aplicable", +"Available for" => "Disponible para", "Add storage" => "Añadir almacenamiento", -"None set" => "No se ha configurado", +"No user or group" => "Ningún usuario o grupo", "All Users" => "Todos los usuarios", "Groups" => "Grupos", "Users" => "Usuarios", diff --git a/apps/files_external/l10n/es_AR.php b/apps/files_external/l10n/es_AR.php index 05204b748c4..f184dbdb7d8 100644 --- a/apps/files_external/l10n/es_AR.php +++ b/apps/files_external/l10n/es_AR.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Permitir acceso", "Please provide a valid Dropbox app key and secret." => "Por favor, proporcioná un secreto y una contraseña válida para la aplicación Dropbox.", "Error configuring Google Drive storage" => "Error al configurar el almacenamiento de Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Advertencia: El cliente smb \"smbclient\" no está instalado. Montar archivos CIFS/SMB no es posible. Por favor, pedile al administrador de tu sistema que lo instale.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Advertencia: El soporte de FTP en PHP no está instalado. Montar archivos FTP no es posible. Por favor, pedile al administrador de tu sistema que lo instale.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Advertencia: El soporte de Curl de PHP no está activo ni instalado. Montar servicios ownCloud, WebDAV y/o GoogleDrive no será posible. Pedile al administrador del sistema que lo instale.", "External Storage" => "Almacenamiento externo", "Folder name" => "Nombre de la carpeta", "External storage" => "Almacenamiento externo", "Configuration" => "Configuración", "Options" => "Opciones", -"Applicable" => "Aplicable", "Add storage" => "Añadir almacenamiento", -"None set" => "No fue configurado", "All Users" => "Todos los usuarios", "Groups" => "Grupos", "Users" => "Usuarios", diff --git a/apps/files_external/l10n/es_MX.php b/apps/files_external/l10n/es_MX.php index 5d3fd44bec6..dc0aef45c4f 100644 --- a/apps/files_external/l10n/es_MX.php +++ b/apps/files_external/l10n/es_MX.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Conceder acceso", "Please provide a valid Dropbox app key and secret." => "Por favor, proporcione un una clave válida de la app Dropbox y una clave secreta.", "Error configuring Google Drive storage" => "Error configurando el almacenamiento de Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Advertencia: El cliente \"smbclient\" no se encuentra instalado. El montado de carpetas CIFS/SMB no es posible. Por favor pida al administrador de su sistema que lo instale.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Advertencia: El soporte de FTP en PHP no se encuentra instalado. El montado de carpetas FTP no es posible. Por favor pida al administrador de su sistema que lo instale.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Advertencia: El soporte de Curl en PHP no está activado ni instalado. El montado de ownCloud, WebDAV o GoogleDrive no es posible. Pida al administrador de su sistema que lo instale.", "External Storage" => "Almacenamiento externo", "Folder name" => "Nombre de la carpeta", "External storage" => "Almacenamiento externo", "Configuration" => "Configuración", "Options" => "Opciones", -"Applicable" => "Aplicable", "Add storage" => "Añadir almacenamiento", -"None set" => "No se ha configurado", "All Users" => "Todos los usuarios", "Groups" => "Grupos", "Users" => "Usuarios", diff --git a/apps/files_external/l10n/et_EE.php b/apps/files_external/l10n/et_EE.php index c6450f95e18..0589d9fd518 100644 --- a/apps/files_external/l10n/et_EE.php +++ b/apps/files_external/l10n/et_EE.php @@ -5,22 +5,21 @@ $TRANSLATIONS = array( "Grant access" => "Anna ligipääs", "Please provide a valid Dropbox app key and secret." => "Palun sisesta korrektne Dropboxi rakenduse võti ja salasõna.", "Error configuring Google Drive storage" => "Viga Google Drive'i salvestusruumi seadistamisel", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Hoiatus: \"smbclient\" pole paigaldatud. Jagatud CIFS/SMB hoidlate ühendamine pole võimalik. Palu oma süsteemihalduril paigaldata SAMBA tugi.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Hoiatus: PHP-s puudub FTP tugi. Jagatud FTP hoidlate ühendamine pole võimalik. Palu oma süsteemihalduril paigaldata FTP tugi.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Hoiatus: PHP-s puudub Curl tugi. Jagatud ownCloud / WebDAV või GoogleDrive ühendamine pole võimalik. Palu oma süsteemihalduril see paigaldada.", +"Saved" => "Salvestatud", "External Storage" => "Väline salvestuskoht", "Folder name" => "Kausta nimi", "External storage" => "Väline andmehoidla", "Configuration" => "Seadistamine", "Options" => "Valikud", -"Applicable" => "Rakendatav", +"Available for" => "Saadaval", "Add storage" => "Lisa andmehoidla", -"None set" => "Pole määratud", +"No user or group" => "Ühtki kasutajat või gruppi", "All Users" => "Kõik kasutajad", "Groups" => "Grupid", "Users" => "Kasutajad", "Delete" => "Kustuta", "Enable User External Storage" => "Luba kasutajatele väline salvestamine", +"Allow users to mount the following external storage" => "Võimalda kasutajatel ühendada järgmist välist andmehoidlat", "SSL root certificates" => "SSL root sertifikaadid", "Import Root Certificate" => "Impordi root sertifikaadid" ); diff --git a/apps/files_external/l10n/eu.php b/apps/files_external/l10n/eu.php index bdc5cf56760..c2111a1f736 100644 --- a/apps/files_external/l10n/eu.php +++ b/apps/files_external/l10n/eu.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Baimendu sarrera", "Please provide a valid Dropbox app key and secret." => "Mesedez eman baliozkoa den Dropbox app giltza eta sekretua", "Error configuring Google Drive storage" => "Errore bat egon da Google Drive biltegiratzea konfiguratzean", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Abisua: \"smbclient\" ez dago instalatuta. CIFS/SMB partekatutako karpetak montatzea ez da posible. Mesedez eskatu zure sistema kudeatzaileari instalatzea.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Abisua: PHPren FTP modulua ez dago instalatuta edo gaitua. FTP partekatutako karpetak montatzea ez da posible. Mesedez eskatu zure sistema kudeatzaileari instalatzea.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Abisua: Curl euskarri PHP modulua ez dago instalatuta edo gaitua. Ezinezko da ownCloud /WebDAV GoogleDrive-n muntatzea. Mesedez eskatu sistema kudeatzaileari instala dezan. ", "External Storage" => "Kanpoko Biltegiratzea", "Folder name" => "Karpetaren izena", "External storage" => "Kanpoko biltegiratzea", "Configuration" => "Konfigurazioa", "Options" => "Aukerak", -"Applicable" => "Aplikagarria", "Add storage" => "Gehitu biltegiratzea", -"None set" => "Ezarri gabe", "All Users" => "Erabiltzaile guztiak", "Groups" => "Taldeak", "Users" => "Erabiltzaileak", diff --git a/apps/files_external/l10n/fa.php b/apps/files_external/l10n/fa.php index 544b8a14d5c..74472c54bf5 100644 --- a/apps/files_external/l10n/fa.php +++ b/apps/files_external/l10n/fa.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => " مجوز اعطا دسترسی", "Please provide a valid Dropbox app key and secret." => "لطفا یک کلید و کد امنیتی صحیح دراپ باکس وارد کنید.", "Error configuring Google Drive storage" => "خطا به هنگام تنظیم فضای Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "خطا: \"smbclient\" نصب نشده است. نصب و راه اندازی سهام CIFS/SMB امکان پذیر نمیباشد. لطفا از مدیریت سازمان خود برای راه اندازی آن درخواست نمایید.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "خطا: پشتیبانی FTP در PHP فعال نمی باشد یا نصب نشده است. نصب و راه اندازی از سهم های FTP امکان پذیر نمی باشد. لطفا از مدیر سیستم خود برای راه اندازی آن درخواست\nکنید.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "خطا: پشتیبانی Curl فعال نمی باشد یا نصب نشده است. نصب و راه اندازی ownCloud / WebDAV یا GoogleDrive امکان پذیر نیست. لطفا از مدیر سیستم خود برای نصب آن درخواست کنید.", "External Storage" => "حافظه خارجی", "Folder name" => "نام پوشه", "External storage" => "حافظه خارجی", "Configuration" => "پیکربندی", "Options" => "تنظیمات", -"Applicable" => "قابل اجرا", "Add storage" => "اضافه کردن حافظه", -"None set" => "تنظیم نشده", "All Users" => "تمام کاربران", "Groups" => "گروه ها", "Users" => "کاربران", diff --git a/apps/files_external/l10n/fi_FI.php b/apps/files_external/l10n/fi_FI.php index d2f9d1a73a5..677425d8a6a 100644 --- a/apps/files_external/l10n/fi_FI.php +++ b/apps/files_external/l10n/fi_FI.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Anna kelvollinen Dropbox-sovellusavain ja salainen vastaus.", "Error configuring Google Drive storage" => "Virhe Google Drive levyn asetuksia tehtäessä", "Saved" => "Tallennettu", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Varoitus: \"smbclient\" ei ole asennettuna. CIFS-/SMB-jakojen liittäminen ei ole mahdollista. Pyydä järjestelmän ylläpitäjää asentamaan smbclient.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Varoitus: PHP:n FTP-tuki ei ole käytössä tai sitä ei ole asennettu. FTP-jakojen liittäminen ei ole mahdollista. Pyydä järjestelmän ylläpitäjää ottamaan FTP-tuki käyttöön.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Varoitus: PHP:n Curl-tuki ei ole käytössä tai sitä ei ole lainkaan asennettu. ownCloudin, WebDAV:in tai Google Driven liittäminen ei ole mahdollista. Pyydä järjestelmän ylläpitäjää ottamaan Curl-tuki käyttöön.", +"Note: " => "Huomio: ", +" and " => "ja", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Huomio: PHP:n cURL-tuki ei ole käytössä tai sitä ei ole asennettu. Kohteen %s liittäminen ei ole mahdollista. Pyydä järjestelmän ylläpitäjää ottamaan cURL-tuki käyttöön.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Huomio: PHP:n FTP-tuki ei ole käytössä tai sitä ei ole asennettu. Kohteen %s liittäminen ei ole mahdollista. Pyydä järjestelmän ylläpitäjää ottamaan FTP-tuki käyttöön.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Huomio: \"%s\" ei ole asennettu. Kohteen %s liittäminen ei ole mahdollista. Pyydä järjestelmän ylläpitäjää asentamaan puuttuva kohde.", "External Storage" => "Erillinen tallennusväline", "Folder name" => "Kansion nimi", "External storage" => "Ulkoinen tallennustila", "Configuration" => "Asetukset", "Options" => "Valinnat", -"Applicable" => "Sovellettavissa", +"Available for" => "Saatavuus", "Add storage" => "Lisää tallennustila", -"None set" => "Ei asetettu", +"No user or group" => "Ei käyttäjää tai ryhmää", "All Users" => "Kaikki käyttäjät", "Groups" => "Ryhmät", "Users" => "Käyttäjät", diff --git a/apps/files_external/l10n/fr.php b/apps/files_external/l10n/fr.php index 4b8e2b905b6..8ff19697182 100644 --- a/apps/files_external/l10n/fr.php +++ b/apps/files_external/l10n/fr.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Veuillez fournir une clé d'application (app key) ainsi qu'un mot de passe valides.", "Error configuring Google Drive storage" => "Erreur lors de la configuration du support de stockage Google Drive", "Saved" => "Sauvegarder", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Attention : \"smbclient\" n'est pas installé. Le montage des partages CIFS/SMB n'est pas disponible. Contactez votre administrateur système pour l'installer.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Attention : Le support FTP de PHP n'est pas activé ou installé. Le montage des partages FTP n'est pas disponible. Contactez votre administrateur système pour l'installer.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Attention : Le support de Curl n'est pas activé ou installé dans PHP. Le montage de ownCloud / WebDAV ou GoogleDrive n'est pas possible. Contactez votre administrateur système pour l'installer.", +"Note: " => "Attention :", +" and " => "et", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Attention : Le support de cURL de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Attention : Le support FTP de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Attention : \"%s\" n'est pas installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.", "External Storage" => "Stockage externe", "Folder name" => "Nom du dossier", "External storage" => "Stockage externe", "Configuration" => "Configuration", "Options" => "Options", -"Applicable" => "Disponible", +"Available for" => "Disponible pour", "Add storage" => "Ajouter un support de stockage", -"None set" => "Aucun spécifié", +"No user or group" => "Aucun utilisateur ou groupe", "All Users" => "Tous les utilisateurs", "Groups" => "Groupes", "Users" => "Utilisateurs", diff --git a/apps/files_external/l10n/gl.php b/apps/files_external/l10n/gl.php index ec13fe241f6..5efa6ce6028 100644 --- a/apps/files_external/l10n/gl.php +++ b/apps/files_external/l10n/gl.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Forneza unha chave correcta e segreda do Dropbox.", "Error configuring Google Drive storage" => "Produciuse un erro ao configurar o almacenamento en Google Drive", "Saved" => "Gardado", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Aviso: «smbclient» non está instalado. Non é posibel a montaxe de comparticións CIFS/SMB. Consulte co administrador do sistema para instalalo.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Aviso: A compatibilidade de FTP en PHP non está activada ou instalada. Non é posibel a montaxe de comparticións FTP. Consulte co administrador do sistema para instalalo.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Aviso: A compatibilidade de Curl en PHP non está activada ou instalada. Non é posíbel a montaxe de ownCloud / WebDAV ou GoogleDrive. Consulte co administrador do sistema para instalala.", +"Note: " => "Nota: ", +" and " => "e", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: A compatibilidade de cURL en PHP non está activada, ou non está instalado. Non é posíbel a montaxe de %s. Consulte co administrador do sistema como instalalo.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: A compatibilidade de FTP en PHP non está activada, ou non está instalado. Non é posíbel a montaxe de %s. Consulte co administrador do sistema como instalalo.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: «%s» non está instalado. Non é posíbel a montaxe de %s. Consulte co administrador do sistema como instalalo.", "External Storage" => "Almacenamento externo", "Folder name" => "Nome do cartafol", "External storage" => "Almacenamento externo", "Configuration" => "Configuración", "Options" => "Opcións", -"Applicable" => "Aplicábel", +"Available for" => "Dispoñíbel para", "Add storage" => "Engadir almacenamento", -"None set" => "Ningún definido", +"No user or group" => "Non hai usuario ou grupo", "All Users" => "Todos os usuarios", "Groups" => "Grupos", "Users" => "Usuarios", diff --git a/apps/files_external/l10n/he.php b/apps/files_external/l10n/he.php index 6aec07e78cf..e433f4fc306 100644 --- a/apps/files_external/l10n/he.php +++ b/apps/files_external/l10n/he.php @@ -9,8 +9,6 @@ $TRANSLATIONS = array( "Folder name" => "שם התיקייה", "Configuration" => "הגדרות", "Options" => "אפשרויות", -"Applicable" => "ניתן ליישום", -"None set" => "לא הוגדרה", "All Users" => "כל המשתמשים", "Groups" => "קבוצות", "Users" => "משתמשים", diff --git a/apps/files_external/l10n/hu_HU.php b/apps/files_external/l10n/hu_HU.php index 60661380433..39d185d5f0b 100644 --- a/apps/files_external/l10n/hu_HU.php +++ b/apps/files_external/l10n/hu_HU.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Megadom a hozzáférést", "Please provide a valid Dropbox app key and secret." => "Adjon meg egy érvényes Dropbox app key-t és secretet!", "Error configuring Google Drive storage" => "A Google Drive tárolót nem sikerült beállítani", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Figyelem: az \"smbclient\" nincs telepítve a kiszolgálón. Emiatt nem lehet CIFS/SMB megosztásokat fölcsatolni. Kérje meg a rendszergazdát, hogy telepítse a szükséges programot.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Figyelem: a PHP FTP támogatása vagy nincs telepítve, vagy nincs engedélyezve a kiszolgálón. Emiatt nem lehetséges FTP-tárolókat fölcsatolni. Kérje meg a rendszergazdát, hogy telepítse a szükséges programot.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Figyelmeztetés: A PHP-ben nincs telepítve vagy engedélyezve a Curl támogatás. Nem lehetséges ownCloud / WebDAV ill. GoogleDrive tárolók becsatolása. Kérje meg a rendszergazdát, hogy telepítse a szükséges programot!", "External Storage" => "Külső tárolási szolgáltatások becsatolása", "Folder name" => "Mappanév", "External storage" => "Külső tárolók", "Configuration" => "Beállítások", "Options" => "Opciók", -"Applicable" => "Érvényességi kör", "Add storage" => "Tároló becsatolása", -"None set" => "Nincs beállítva", "All Users" => "Az összes felhasználó", "Groups" => "Csoportok", "Users" => "Felhasználók", diff --git a/apps/files_external/l10n/id.php b/apps/files_external/l10n/id.php index 9f91fdf992f..8ab5069539f 100644 --- a/apps/files_external/l10n/id.php +++ b/apps/files_external/l10n/id.php @@ -5,16 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Berikan hak akses", "Please provide a valid Dropbox app key and secret." => "Masukkan kunci dan sandi aplikasi Dropbox yang benar.", "Error configuring Google Drive storage" => "Kesalahan dalam mengkonfigurasi penyimpanan Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Peringatan: \"smbclient\" tidak terpasang. Mount direktori CIFS/SMB tidak dapat dilakukan. Silakan minta administrator sistem untuk memasangnya.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Peringatan: Dukungan FTP di PHP tidak aktif atau tidak terpasang. Mount direktori FTP tidak dapat dilakukan. Silakan minta administrator sistem untuk memasangnya.", "External Storage" => "Penyimpanan Eksternal", "Folder name" => "Nama folder", "External storage" => "Penyimpanan eksternal", "Configuration" => "Konfigurasi", "Options" => "Opsi", -"Applicable" => "Berlaku", "Add storage" => "Tambahkan penyimpanan", -"None set" => "Tidak satupun di set", "All Users" => "Semua Pengguna", "Groups" => "Grup", "Users" => "Pengguna", diff --git a/apps/files_external/l10n/is.php b/apps/files_external/l10n/is.php index e86cfa108a6..21a215807ab 100644 --- a/apps/files_external/l10n/is.php +++ b/apps/files_external/l10n/is.php @@ -5,14 +5,10 @@ $TRANSLATIONS = array( "Grant access" => "Veita aðgengi", "Please provide a valid Dropbox app key and secret." => "Gefðu upp virkan Dropbox lykil og leynikóða", "Error configuring Google Drive storage" => "Villa kom upp við að setja upp Google Drive gagnasvæði", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Aðvörun: \"smbclient\" er ekki uppsettur. Uppsetning á CIFS/SMB gagnasvæðum er ekki möguleg. Hafðu samband við kerfisstjóra til að fá hann uppsettan.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Aðvörun: FTP stuðningur í PHP er ekki virkur. Uppsetning á FTP gagnasvæðum er ekki möguleg. Hafðu samband við kerfisstjóra til að fá hann uppsettan.", "External Storage" => "Ytri gagnageymsla", "Folder name" => "Nafn möppu", "Configuration" => "Uppsetning", "Options" => "Stillingar", -"Applicable" => "Gilt", -"None set" => "Ekkert sett", "All Users" => "Allir notendur", "Groups" => "Hópar", "Users" => "Notendur", diff --git a/apps/files_external/l10n/it.php b/apps/files_external/l10n/it.php index d62d8e97327..f3a6f9af129 100644 --- a/apps/files_external/l10n/it.php +++ b/apps/files_external/l10n/it.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Fornisci chiave di applicazione e segreto di Dropbox validi.", "Error configuring Google Drive storage" => "Errore durante la configurazione dell'archivio Google Drive", "Saved" => "Salvato", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Avviso: \"smbclient\" non è installato. Impossibile montare condivisioni CIFS/SMB. Chiedi all'amministratore di sistema di installarlo.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Avviso: il supporto FTP di PHP non è abilitato o non è installato. Impossibile montare condivisioni FTP. Chiedi all'amministratore di sistema di installarlo.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Avviso: il supporto Curl di PHP non è abilitato o non è installato. Impossibile montare condivisioni ownCloud / WebDAV o GoogleDrive. Chiedi all'amministratore di sistema di installarlo.", +"Note: " => "Nota:", +" and " => "e", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: il supporto a cURL di PHP non è abilitato o installato. Impossibile montare %s. Chiedi al tuo amministratore di sistema di installarlo.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: il supporto a FTP in PHP non è abilitato o installato. Impossibile montare %s. Chiedi al tuo amministratore di sistema di installarlo.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: \"%s\" non è installato. Impossibile montare %s. Chiedi al tuo amministratore di sistema di installarlo.", "External Storage" => "Archiviazione esterna", "Folder name" => "Nome della cartella", "External storage" => "Archiviazione esterna", "Configuration" => "Configurazione", "Options" => "Opzioni", -"Applicable" => "Applicabile", +"Available for" => "Disponibile per", "Add storage" => "Aggiungi archiviazione", -"None set" => "Nessuna impostazione", +"No user or group" => "Nessun utente o gruppo", "All Users" => "Tutti gli utenti", "Groups" => "Gruppi", "Users" => "Utenti", diff --git a/apps/files_external/l10n/ja.php b/apps/files_external/l10n/ja.php index 312dc85188d..52d66043e19 100644 --- a/apps/files_external/l10n/ja.php +++ b/apps/files_external/l10n/ja.php @@ -6,17 +6,13 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "有効なDropboxアプリのキーとパスワードを入力してください。", "Error configuring Google Drive storage" => "Googleドライブストレージの設定エラー", "Saved" => "保存されました", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "警告: \"smbclient\" がインストールされていません。CIFS/SMB共有のマウントはできません。システム管理者にインストールを依頼してください。", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "警告: PHPのFTPサポートが無効またはインストールされていません。FTP共有のマウントはできません。システム管理者にインストールを依頼してください。", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "警告: PHPのCurlサポートが無効またはインストールされていません。ownCloud / WebDAVまたはGoogleDriveのマウントはできません。システム管理者にインストールを依頼してください。", "External Storage" => "外部ストレージ", "Folder name" => "フォルダー名", "External storage" => "外部ストレージ", "Configuration" => "設定", "Options" => "オプション", -"Applicable" => "適用範囲", "Add storage" => "ストレージを追加", -"None set" => "未設定", +"No user or group" => "ユーザーもしくはグループがありません", "All Users" => "すべてのユーザー", "Groups" => "グループ", "Users" => "ユーザー", diff --git a/apps/files_external/l10n/ka_GE.php b/apps/files_external/l10n/ka_GE.php index 4953f91ce6a..d68dae88c02 100644 --- a/apps/files_external/l10n/ka_GE.php +++ b/apps/files_external/l10n/ka_GE.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "დაშვების მინიჭება", "Please provide a valid Dropbox app key and secret." => "გთხოვთ მიუთითოთ Dropbox აპლიკაციის გასაღები და კოდი.", "Error configuring Google Drive storage" => "შეცდომა Google Drive საცავის კონფიგურირების დროს", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "გაფრთხილება: \"smbclient\" არ არის ინსტალირებული. CIFS/SMB ზიარების მონტირება შეუძლებელია. გთხოვთ თხოვოთ თქვენს სისტემურ ადმინისტრატორებს დააინსტალიროს ის.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "გაფრთხილება: FTP მხარდაჭერა არ არის აქტიური ან დაინსტალირებული. FTP ზიარის მონტირება შეუძლებელია. გთხოვთ თხოვოთ თქვენს სისტემურ ადმინისტრატორებს დააინსტალიროს ის.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "გაფრთხილება:PHP–ის Curl მხარდაჭერა არ არის ჩართული ან ინსტალირებული. ownCloud / WebDAV ან GoogleDrive–ის მონტირება შეუძლებელია. თხოვეთ თქვენს ადმინისტრატორს დააინსტალიროს ის.", "External Storage" => "ექსტერნალ საცავი", "Folder name" => "ფოლდერის სახელი", "External storage" => "ექსტერნალ საცავი", "Configuration" => "კონფიგურაცია", "Options" => "ოფცია", -"Applicable" => "მიღებადი", "Add storage" => "საცავის დამატება", -"None set" => "არაფერია მითითებული", "All Users" => "ყველა მომხმარებელი", "Groups" => "ჯგუფები", "Users" => "მომხმარებელი", diff --git a/apps/files_external/l10n/km.php b/apps/files_external/l10n/km.php index 4586f866a74..75879f2300e 100644 --- a/apps/files_external/l10n/km.php +++ b/apps/files_external/l10n/km.php @@ -1,6 +1,7 @@ "ឈ្មោះ​ថត", +"Options" => "ជម្រើស", "Groups" => "ក្រុ", "Users" => "អ្នកប្រើ", "Delete" => "លុប" diff --git a/apps/files_external/l10n/ko.php b/apps/files_external/l10n/ko.php index 088a419e1c1..371cba3e12d 100644 --- a/apps/files_external/l10n/ko.php +++ b/apps/files_external/l10n/ko.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "접근 권한 부여", "Please provide a valid Dropbox app key and secret." => "올바른 Dropbox 앱 키와 암호를 입력하십시오.", "Error configuring Google Drive storage" => "Google 드라이브 저장소 설정 오류", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "경고: \"smbclient\"가 설치되지 않았습니다. CIFS/SMB 공유 자원에 연결할 수 없습니다. 시스템 관리자에게 설치를 요청하십시오.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "경고: PHP FTP 지원이 비활성화되어 있거나 설치되지 않았습니다. FTP 공유를 마운트할 수 없습니다. 시스템 관리자에게 설치를 요청하십시오.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "경고: PHP Curl 지원이 비활성화되어 있거나 설치되지 않았습니다. 다른 ownCloud, WebDAV, Google 드라이브 공유를 마운트할 수 없습니다. 시스템 관리자에게 설치를 요청하십시오.", "External Storage" => "외부 저장소", "Folder name" => "폴더 이름", "External storage" => "외부 저장소", "Configuration" => "설정", "Options" => "옵션", -"Applicable" => "적용 가능", "Add storage" => "저장소 추가", -"None set" => "설정되지 않음", "All Users" => "모든 사용자", "Groups" => "그룹", "Users" => "사용자", diff --git a/apps/files_external/l10n/lt_LT.php b/apps/files_external/l10n/lt_LT.php index c96119c8b68..fdf1ee70136 100644 --- a/apps/files_external/l10n/lt_LT.php +++ b/apps/files_external/l10n/lt_LT.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Suteikti priėjimą", "Please provide a valid Dropbox app key and secret." => "Prašome įvesti teisingus Dropbox \"app key\" ir \"secret\".", "Error configuring Google Drive storage" => "Klaida nustatinėjant Google Drive talpyklą", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Įspėjimas: \"smbclient\" nėra įdiegtas. CIFS/SMB dalinimasis nėra galimas. Prašome susisiekti su sistemos administratoriumi kad būtų įdiegtas \"smbclient\"", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Įspėjimas: FTP palaikymas PHP sistemoje nėra įjungtas arba nėra įdiegtas. FTP dalinimosi įjungimas nėra galimas. Prašome susisiekti su sistemos administratoriumi kad būtų įdiegtas FTP palaikymas. ", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Įspėjimas: \"Curl\" palaikymas PHP terpėje nėra įjungtas arba įdiegtas. ownCloud/WebDAV ar GoogleDrive įjungimas nebus įmanomas. Prašome susisiekti su sistemos administratoriumi kad būtų įdiegtas arba įjungtas \"Curl\" palaikymas.", "External Storage" => "Išorinės saugyklos", "Folder name" => "Katalogo pavadinimas", "External storage" => "Išorinė saugykla", "Configuration" => "Konfigūracija", "Options" => "Nustatymai", -"Applicable" => "Pritaikyti", "Add storage" => "Pridėti saugyklą", -"None set" => "Nieko nepasirinkta", "All Users" => "Visi vartotojai", "Groups" => "Grupės", "Users" => "Vartotojai", diff --git a/apps/files_external/l10n/lv.php b/apps/files_external/l10n/lv.php index 18e56178892..e1037b50328 100644 --- a/apps/files_external/l10n/lv.php +++ b/apps/files_external/l10n/lv.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Piešķirt pieeju", "Please provide a valid Dropbox app key and secret." => "Lūdzu, norādiet derīgu Dropbox lietotnes atslēgu un noslēpumu.", "Error configuring Google Drive storage" => "Kļūda, konfigurējot Google Drive krātuvi", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Brīdinājums: nav uzinstalēts “smbclient”. Nevar montēt CIFS/SMB koplietojumus. Lūdzu, vaicājiet savam sistēmas administratoram, lai to uzinstalē.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Brīdinājums: uz PHP nav aktivēts vai instalēts FTP atbalsts. Nevar montēt FTP koplietojumus. Lūdzu, vaicājiet savam sistēmas administratoram, lai to uzinstalē.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Brīdinājums: PHP Curl atbalsts nav instalēts. OwnCloud / WebDAV vai GoogleDrive montēšana nav iespējama. Lūdziet sistēmas administratoram lai tas tiek uzstādīts.", "External Storage" => "Ārējā krātuve", "Folder name" => "Mapes nosaukums", "External storage" => "Ārējā krātuve", "Configuration" => "Konfigurācija", "Options" => "Opcijas", -"Applicable" => "Piemērojams", "Add storage" => "Pievienot krātuvi", -"None set" => "Neviens nav iestatīts", "All Users" => "Visi lietotāji", "Groups" => "Grupas", "Users" => "Lietotāji", diff --git a/apps/files_external/l10n/mk.php b/apps/files_external/l10n/mk.php index b59bb138f1d..507c0a74559 100644 --- a/apps/files_external/l10n/mk.php +++ b/apps/files_external/l10n/mk.php @@ -5,14 +5,10 @@ $TRANSLATIONS = array( "Grant access" => "Дозволи пристап", "Please provide a valid Dropbox app key and secret." => "Ве молам доставите валиден Dropbox клуч и тајна лозинка.", "Error configuring Google Drive storage" => "Грешка при конфигурација на Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Внимание: \"smbclient\" не е инсталиран. Не е можно монтирање на CIFS/SMB дискови. Замолете го Вашиот систем администратор да го инсталира.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Внимание: Не е овозможена или инсталирани FTP подршка во PHP. Не е можно монтирање на FTP дискови. Замолете го Вашиот систем администратор да го инсталира.", "External Storage" => "Надворешно складиште", "Folder name" => "Име на папка", "Configuration" => "Конфигурација", "Options" => "Опции", -"Applicable" => "Применливо", -"None set" => "Ништо поставено", "All Users" => "Сите корисници", "Groups" => "Групи", "Users" => "Корисници", diff --git a/apps/files_external/l10n/nb_NO.php b/apps/files_external/l10n/nb_NO.php index c103112dbe3..95c9b47f412 100644 --- a/apps/files_external/l10n/nb_NO.php +++ b/apps/files_external/l10n/nb_NO.php @@ -5,17 +5,13 @@ $TRANSLATIONS = array( "Grant access" => "Gi tilgang", "Please provide a valid Dropbox app key and secret." => "Vær vennlig å oppgi gyldig Dropbox appnøkkel og hemmelighet.", "Error configuring Google Drive storage" => "Feil med konfigurering av Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Advarsel: \"smbclient\" er ikke installert. Kan ikke montere CIFS/SMB mapper. Ta kontakt med din systemadministrator for å installere det.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Advarsel: FTP støtte i PHP er ikke slått på eller innstallert. Kan ikke montere FTP mapper. Ta kontakt med din systemadministrator for å innstallere det.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Advarsel: Curl støtte i PHP er ikke aktivert eller innstallert. Kan ikke montere owncloud/WebDAV eller Googledrive. Ta kontakt med din systemadministrator for å innstallerer det.", +"Saved" => "Lagret", "External Storage" => "Ekstern lagring", "Folder name" => "Mappenavn", "External storage" => "Ekstern lagringsplass", "Configuration" => "Konfigurasjon", "Options" => "Innstillinger", -"Applicable" => "Anvendelig", "Add storage" => "Legg til lagringsplass", -"None set" => "Ingen valgt", "All Users" => "Alle brukere", "Groups" => "Grupper", "Users" => "Brukere", diff --git a/apps/files_external/l10n/nl.php b/apps/files_external/l10n/nl.php index 4fa579775f9..c055be50f87 100644 --- a/apps/files_external/l10n/nl.php +++ b/apps/files_external/l10n/nl.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Geef een geldige Dropbox key en secret.", "Error configuring Google Drive storage" => "Fout tijdens het configureren van Google Drive opslag", "Saved" => "Bewaard", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Waarschuwing: \"smbclient\" is niet geïnstalleerd. Mounten van CIFS/SMB shares is niet mogelijk. Vraag uw beheerder om smbclient te installeren.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Waarschuwing: FTP ondersteuning in PHP is niet geactiveerd of geïnstalleerd. Mounten van FTP shares is niet mogelijk. Vraag uw beheerder FTP ondersteuning te installeren.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Waarschuwing: Curl ondersteuning in PHP is niet geactiveerd of geïnstalleerd. Mounten van ownCloud / WebDAV of GoogleDrive is niet mogelijk. Vraag uw systeembeheerder dit te installeren.", +"Note: " => "Let op: ", +" and " => "en", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Let op: Curl ondersteuning in PHP is niet geactiveerd of geïnstalleerd. Mounten van %s is niet mogelijk. Vraag uw systeembeheerder dit te installeren.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Let op: FTP ondersteuning in PHP is niet geactiveerd of geïnstalleerd. Mounten van %s is niet mogelijk. Vraag uw beheerder dit te installeren.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Let op: \"%s\" is niet geïnstalleerd. Mounten van %s is niet mogelijk. Vraag uw beheerder om dit te installeren.", "External Storage" => "Externe opslag", "Folder name" => "Mapnaam", "External storage" => "Externe opslag", "Configuration" => "Configuratie", "Options" => "Opties", -"Applicable" => "Van toepassing", +"Available for" => "Beschikbaar voor", "Add storage" => "Toevoegen opslag", -"None set" => "Niets ingesteld", +"No user or group" => "Geen gebruiker of groep", "All Users" => "Alle gebruikers", "Groups" => "Groepen", "Users" => "Gebruikers", diff --git a/apps/files_external/l10n/pl.php b/apps/files_external/l10n/pl.php index ece0620f754..246e12b6ac8 100644 --- a/apps/files_external/l10n/pl.php +++ b/apps/files_external/l10n/pl.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Proszę podać prawidłowy klucz aplikacji Dropbox i klucz sekretny.", "Error configuring Google Drive storage" => "Wystąpił błąd podczas konfigurowania zasobu Google Drive", "Saved" => "Zapisano", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Ostrzeżenie: \"smbclient\" nie jest zainstalowany. Zamontowanie katalogów CIFS/SMB nie jest możliwe. Skontaktuj sie z administratorem w celu zainstalowania.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Ostrzeżenie: Wsparcie dla FTP w PHP nie jest zainstalowane lub włączone. Skontaktuj sie z administratorem w celu zainstalowania lub włączenia go.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Ostrzeżenie: Wsparcie dla Curl w PHP nie jest zainstalowane lub włączone. Montowanie WebDAV lub GoogleDrive nie będzie możliwe. Skontaktuj się z administratorem w celu zainstalowania lub włączenia tej opcji.", +"Note: " => "Uwaga: ", +" and " => "oraz", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Uwaga: Wsparcie dla cURL w PHP nie zostało włączone lub zainstalowane. Zamontowanie %s nie jest możliwe. Proszę poproś Twojego administratora o zainstalowanie go.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Uwaga: Wsparcie dla FTP w PHP nie zostało włączone lub zainstalowane. Zamontowanie %s nie jest możliwe. Proszę poproś Twojego administratora o zainstalowanie go.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Uwaga: \"%s\" nie jest zainstalowane. Zamontowanie %s nie jest możliwe. Proszę poproś Twojego administratora o zainstalowanie go.", "External Storage" => "Zewnętrzna zasoby dyskowe", "Folder name" => "Nazwa folderu", "External storage" => "Zewnętrzne zasoby dyskowe", "Configuration" => "Konfiguracja", "Options" => "Opcje", -"Applicable" => "Zastosowanie", +"Available for" => "Dostępne przez", "Add storage" => "Dodaj zasoby dyskowe", -"None set" => "Nie ustawione", +"No user or group" => "Brak użytkownika lub grupy", "All Users" => "Wszyscy uzytkownicy", "Groups" => "Grupy", "Users" => "Użytkownicy", diff --git a/apps/files_external/l10n/pt_BR.php b/apps/files_external/l10n/pt_BR.php index fbb945c5439..9a5a39f2358 100644 --- a/apps/files_external/l10n/pt_BR.php +++ b/apps/files_external/l10n/pt_BR.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Por favor forneça um app key e secret válido do Dropbox", "Error configuring Google Drive storage" => "Erro ao configurar armazenamento do Google Drive", "Saved" => "Salvo", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Aviso: \"smbclient\" não está instalado. Impossível montar compartilhamentos de CIFS/SMB. Por favor, peça ao seu administrador do sistema para instalá-lo.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Aviso: O suporte para FTP do PHP não está ativado ou instalado. Impossível montar compartilhamentos FTP. Por favor, peça ao seu administrador do sistema para instalá-lo.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => " Aviso: O suport a Curl em PHP não está habilitado ou instalado. A montagem do ownCloud / WebDAV ou GoogleDrive não é possível. Por favor, solicite ao seu administrador do sistema instalá-lo.", +"Note: " => "Nota:", +" and " => "e", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: O suporte cURL do PHP não está habilitado ou instalado. Montagem de %s não é possível. Por favor, solicite ao seu administrador do sistema para instalá-lo.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: O suporte FTP no PHP não está habilitado ou instalado. Montagem de %s não é possível. Por favor, solicite ao seu administrador do sistema para instalá-lo.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Nota: \"%s\" não está instalado. Montagem de %s não é possível. Por favor, solicite ao seu administrador do sistema para instalá-lo.", "External Storage" => "Armazenamento Externo", "Folder name" => "Nome da pasta", "External storage" => "Armazenamento Externo", "Configuration" => "Configuração", "Options" => "Opções", -"Applicable" => "Aplicável", +"Available for" => "Disponível para", "Add storage" => "Adicionar Armazenamento", -"None set" => "Nenhum definido", +"No user or group" => "Nenhum usuário ou grupo", "All Users" => "Todos os Usuários", "Groups" => "Grupos", "Users" => "Usuários", diff --git a/apps/files_external/l10n/pt_PT.php b/apps/files_external/l10n/pt_PT.php index eb4d8feb41a..d0b70006ea1 100644 --- a/apps/files_external/l10n/pt_PT.php +++ b/apps/files_external/l10n/pt_PT.php @@ -6,17 +6,12 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Por favor forneça uma \"app key\" e \"secret\" do Dropbox válidas.", "Error configuring Google Drive storage" => "Erro ao configurar o armazenamento do Google Drive", "Saved" => "Guardado", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Atenção: O cliente \"smbclient\" não está instalado. Não é possível montar as partilhas CIFS/SMB . Peça ao seu administrador para instalar.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Aviso: O suporte FTP no PHP não está activate ou instalado. Não é possível montar as partilhas FTP. Peça ao seu administrador para instalar.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Atenção:
O suporte PHP para o Curl não está activado ou instalado. A montagem do ownCloud/WebDav ou GoolgeDriver não é possível. Por favor contacte o administrador para o instalar.", "External Storage" => "Armazenamento Externo", "Folder name" => "Nome da pasta", "External storage" => "Armazenamento Externo", "Configuration" => "Configuração", "Options" => "Opções", -"Applicable" => "Aplicável", "Add storage" => "Adicionar armazenamento", -"None set" => "Não definido", "All Users" => "Todos os utilizadores", "Groups" => "Grupos", "Users" => "Utilizadores", diff --git a/apps/files_external/l10n/ro.php b/apps/files_external/l10n/ro.php index a90b0299e17..3fc56c67d33 100644 --- a/apps/files_external/l10n/ro.php +++ b/apps/files_external/l10n/ro.php @@ -6,17 +6,12 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Prezintă te rog o cheie de Dropbox validă și parola", "Error configuring Google Drive storage" => "Eroare la configurarea mediului de stocare Google Drive", "Saved" => "Salvat", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Atenție: \"smbclient\" nu este instalat. Montarea mediilor CIFS/SMB partajate nu este posibilă. Solicită administratorului sistemului tău să îl instaleaze.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Atenție: suportul pentru FTP în PHP nu este activat sau instalat. Montarea mediilor FPT partajate nu este posibilă. Solicită administratorului sistemului tău să îl instaleze.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Atentie: Suportul Curl nu este pornit / instalat in configuratia PHP! Montarea ownCloud / WebDAV / GoogleDrive nu este posibila! Intrebati administratorul sistemului despre aceasta problema!", "External Storage" => "Stocare externă", "Folder name" => "Denumire director", "External storage" => "Stocare externă", "Configuration" => "Configurație", "Options" => "Opțiuni", -"Applicable" => "Aplicabil", "Add storage" => "Adauga stocare", -"None set" => "Niciunul", "All Users" => "Toți utilizatorii", "Groups" => "Grupuri", "Users" => "Utilizatori", diff --git a/apps/files_external/l10n/ru.php b/apps/files_external/l10n/ru.php index 66d6f9fa6b8..f282f3969e5 100644 --- a/apps/files_external/l10n/ru.php +++ b/apps/files_external/l10n/ru.php @@ -5,22 +5,19 @@ $TRANSLATIONS = array( "Grant access" => "Предоставление доступа", "Please provide a valid Dropbox app key and secret." => "Пожалуйста, предоставьте действующий ключ Dropbox и пароль.", "Error configuring Google Drive storage" => "Ошибка при настройке хранилища Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Внимание: \"smbclient\" не установлен. Подключение по CIFS/SMB невозможно. Пожалуйста, обратитесь к системному администратору, чтобы установить его.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Внимание: Поддержка FTP не включена в PHP. Подключение по FTP невозможно. Пожалуйста, обратитесь к системному администратору, чтобы включить.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Внимание: Поддержка Curl в PHP не включена или не установлена. Подключение ownCloud / WebDAV или GoogleDrive невозможно. Попросите вашего системного администратора установить его.", +"Saved" => "Сохранено", "External Storage" => "Внешний носитель", "Folder name" => "Имя папки", "External storage" => "Внешний носитель данных", "Configuration" => "Конфигурация", "Options" => "Опции", -"Applicable" => "Применимый", "Add storage" => "Добавить носитель данных", -"None set" => "Не установлено", "All Users" => "Все пользователи", "Groups" => "Группы", "Users" => "Пользователи", "Delete" => "Удалить", "Enable User External Storage" => "Включить пользовательские внешние носители", +"Allow users to mount the following external storage" => "Разрешить пользователям монтировать следующую внешнюю систему хранения данных", "SSL root certificates" => "Корневые сертификаты SSL", "Import Root Certificate" => "Импортировать корневые сертификаты" ); diff --git a/apps/files_external/l10n/si_LK.php b/apps/files_external/l10n/si_LK.php index ac41f596340..a9f39a3bbc9 100644 --- a/apps/files_external/l10n/si_LK.php +++ b/apps/files_external/l10n/si_LK.php @@ -9,8 +9,6 @@ $TRANSLATIONS = array( "Folder name" => "ෆොල්ඩරයේ නම", "Configuration" => "වින්‍යාසය", "Options" => "විකල්පයන්", -"Applicable" => "අදාළ", -"None set" => "කිසිවක් නැත", "All Users" => "සියළු පරිශීලකයන්", "Groups" => "කණ්ඩායම්", "Users" => "පරිශීලකයන්", diff --git a/apps/files_external/l10n/sk_SK.php b/apps/files_external/l10n/sk_SK.php index aa288982576..de32fb5ffb1 100644 --- a/apps/files_external/l10n/sk_SK.php +++ b/apps/files_external/l10n/sk_SK.php @@ -5,17 +5,13 @@ $TRANSLATIONS = array( "Grant access" => "Povoliť prístup", "Please provide a valid Dropbox app key and secret." => "Zadajte platný kľúč aplikácie a heslo Dropbox", "Error configuring Google Drive storage" => "Chyba pri konfigurácii úložiska Google drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Upozornenie: \"smbclient\" nie je nainštalovaný. Nie je možné pripojenie oddielov CIFS/SMB. Požiadajte administrátora systému, nech ho nainštaluje.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Upozornenie: Podpora FTP v PHP nie je povolená alebo nainštalovaná. Nie je možné pripojenie oddielov FTP. Požiadajte administrátora systému, nech ho nainštaluje.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Varovanie: nie je nainštalovaná, alebo povolená, podpora Curl v PHP. Nie je možné pripojenie oddielov ownCloud, WebDAV, či GoogleDrive. Prosím požiadajte svojho administrátora systému, nech ju nainštaluje.", +"Saved" => "Uložené", "External Storage" => "Externé úložisko", "Folder name" => "Názov priečinka", "External storage" => "Externé úložisko", "Configuration" => "Nastavenia", "Options" => "Možnosti", -"Applicable" => "Aplikovateľné", "Add storage" => "Pridať úložisko", -"None set" => "Žiadne nastavené", "All Users" => "Všetci používatelia", "Groups" => "Skupiny", "Users" => "Používatelia", diff --git a/apps/files_external/l10n/sl.php b/apps/files_external/l10n/sl.php index 05e626fcf83..bb34494a5d7 100644 --- a/apps/files_external/l10n/sl.php +++ b/apps/files_external/l10n/sl.php @@ -6,17 +6,14 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Vpisati je treba veljaven ključ programa in kodo za Dropbox", "Error configuring Google Drive storage" => "Napaka nastavljanja shrambe Google Drive", "Saved" => "Shranjeno", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Opozorilo: paket \"smbclient\" ni nameščen. Priklapljanje pogonov CIFS/SMB ne bo mogoče.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Opozorilo: podpora FTP v PHP ni omogočena ali pa ni nameščena. Priklapljanje pogonov FTP zato ne bo mogoče.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Opozorilo: podpora za Curl v PHP ni omogočena ali pa ni nameščena. Priklapljanje točke ownCloud / WebDAV ali GoogleDrive zato ne bo mogoče. Zahtevane pakete je treba pred uporabo namestiti.", "External Storage" => "Zunanja podatkovna shramba", "Folder name" => "Ime mape", "External storage" => "Zunanja shramba", "Configuration" => "Nastavitve", "Options" => "Možnosti", -"Applicable" => "Se uporablja", +"Available for" => "Na voljo za", "Add storage" => "Dodaj shrambo", -"None set" => "Ni nastavljeno", +"No user or group" => "Ni uporabnika ali skupine", "All Users" => "Vsi uporabniki", "Groups" => "Skupine", "Users" => "Uporabniki", diff --git a/apps/files_external/l10n/sv.php b/apps/files_external/l10n/sv.php index 183df674b9d..2992460d283 100644 --- a/apps/files_external/l10n/sv.php +++ b/apps/files_external/l10n/sv.php @@ -5,22 +5,26 @@ $TRANSLATIONS = array( "Grant access" => "Bevilja åtkomst", "Please provide a valid Dropbox app key and secret." => "Ange en giltig Dropbox nyckel och hemlighet.", "Error configuring Google Drive storage" => "Fel vid konfigurering av Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Varning: \"smb-klienten\" är inte installerad. Montering av CIFS/SMB delningar är inte möjligt. Kontakta din systemadministratör för att få den installerad.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Varning: Stöd för FTP i PHP är inte aktiverat eller installerat. Montering av FTP-delningar är inte möjligt. Kontakta din systemadministratör för att få det installerat.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Varning: Curl-stöd i PHP är inte aktiverat eller installerat. Montering av ownCloud / WebDAV eller GoogleDrive är inte möjligt. Vänligen be din administratör att installera det.", +"Saved" => "Sparad", +"Note: " => " OBS: ", +" and " => "och", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => " OBS: cURL stöd i PHP inte är aktiverat eller installeras. Montering av %s är inte möjlig. Be din systemadministratör för att installera det.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => " OBS: Den FTP-stöd i PHP inte är aktiverat eller installeras. Montering av %s är inte möjlig. Be din systemadministratör för att installera det.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => " OBS: \"%s\" är inte installerat. Montering av %s är inte möjlig. Be din systemadministratör för att installera det.", "External Storage" => "Extern lagring", "Folder name" => "Mappnamn", "External storage" => "Extern lagring", "Configuration" => "Konfiguration", "Options" => "Alternativ", -"Applicable" => "Tillämplig", +"Available for" => "Tillgänglig för", "Add storage" => "Lägg till lagring", -"None set" => "Ingen angiven", +"No user or group" => "Ingen användare eller grupp", "All Users" => "Alla användare", "Groups" => "Grupper", "Users" => "Användare", "Delete" => "Radera", "Enable User External Storage" => "Aktivera extern lagring för användare", +"Allow users to mount the following external storage" => "Tillåt användare att montera följande extern lagring", "SSL root certificates" => "SSL rotcertifikat", "Import Root Certificate" => "Importera rotcertifikat" ); diff --git a/apps/files_external/l10n/ta_LK.php b/apps/files_external/l10n/ta_LK.php index 94ddaf9c5e1..fe5d2a8bc87 100644 --- a/apps/files_external/l10n/ta_LK.php +++ b/apps/files_external/l10n/ta_LK.php @@ -9,8 +9,6 @@ $TRANSLATIONS = array( "Folder name" => "கோப்புறை பெயர்", "Configuration" => "தகவமைப்பு", "Options" => "தெரிவுகள்", -"Applicable" => "பயன்படத்தக்க", -"None set" => "தொகுப்பில்லா", "All Users" => "பயனாளர்கள் எல்லாம்", "Groups" => "குழுக்கள்", "Users" => "பயனாளர்", diff --git a/apps/files_external/l10n/th_TH.php b/apps/files_external/l10n/th_TH.php index a1a56a4d2e4..e3653eb41f7 100644 --- a/apps/files_external/l10n/th_TH.php +++ b/apps/files_external/l10n/th_TH.php @@ -5,14 +5,10 @@ $TRANSLATIONS = array( "Grant access" => "อนุญาตให้เข้าถึงได้", "Please provide a valid Dropbox app key and secret." => "กรุณากรอกรหัส app key ของ Dropbox และรหัสลับ", "Error configuring Google Drive storage" => "เกิดข้อผิดพลาดในการกำหนดค่าการจัดเก็บข้อมูลในพื้นที่ของ Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "คำเตือน: \"smbclient\" ยังไม่ได้ถูกติดตั้ง. การชี้ CIFS/SMB เพื่อแชร์ข้อมูลไม่สามารถกระทำได้ กรุณาสอบถามข้อมูลเพิ่มเติมจากผู้ดูแลระบบเพื่อติดตั้ง.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "คำเตือน: การสนับสนุนการใช้งาน FTP ในภาษา PHP ยังไม่ได้ถูกเปิดใช้งานหรือถูกติดตั้ง. การชี้ FTP เพื่อแชร์ข้อมูลไม่สามารถดำเนินการได้ กรุณาสอบถามข้อมูลเพิ่มเติมจากผู้ดูแลระบบเพื่อติดตั้ง", "External Storage" => "พื้นทีจัดเก็บข้อมูลจากภายนอก", "Folder name" => "ชื่อโฟลเดอร์", "Configuration" => "การกำหนดค่า", "Options" => "ตัวเลือก", -"Applicable" => "สามารถใช้งานได้", -"None set" => "ยังไม่มีการกำหนด", "All Users" => "ผู้ใช้งานทั้งหมด", "Groups" => "กลุ่ม", "Users" => "ผู้ใช้งาน", diff --git a/apps/files_external/l10n/tr.php b/apps/files_external/l10n/tr.php index a835d6f174a..3646a47605d 100644 --- a/apps/files_external/l10n/tr.php +++ b/apps/files_external/l10n/tr.php @@ -6,17 +6,19 @@ $TRANSLATIONS = array( "Please provide a valid Dropbox app key and secret." => "Lütfen Dropbox app key ve secret temin ediniz", "Error configuring Google Drive storage" => "Google Drive depo yapılandırma hatası", "Saved" => "Kaydedildi", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Uyarı: \"smbclient\" kurulu değil. CIFS/SMB paylaşımlarını bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinize danışın.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Uyarı: PHP içerisinde FTP desteği etkin veya yüklü değil. FTP paylaşımlarını bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinize danışın.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Uyarı: PHP içerisinde Curl desteği etkin veya yüklü değil. OwnCloud / WebDAV veya GoogleDrive bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinizde danışın.", +"Note: " => "Not: ", +" and " => "ve", +"Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Not: PHP'de cURL desteği etkin veya kurulu değil. %s bağlaması mümkün olmayacak. Lütfen kurulumu için sistem yöneticilerinizle iletişime geçin.", +"Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Not: PHP'de FTP desteği etkin veya kurulu değil. %s bağlaması mümkün olmayacak. Lütfen kurulumu için sistem yöneticilerinizle iletişime geçin.", +"Note: \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "Not: \"%s\" kurulu değil. %s bağlaması mümkün olmayacak. Lütfen kurulumu için sistem yöneticilerinizle iletişime geçin.", "External Storage" => "Harici Depolama", -"Folder name" => "Dizin ismi", +"Folder name" => "Klasör ismi", "External storage" => "Harici depolama", "Configuration" => "Yapılandırma", "Options" => "Seçenekler", -"Applicable" => "Uygulanabilir", +"Available for" => "Kullanabilenler", "Add storage" => "Depo ekle", -"None set" => "Hiçbiri", +"No user or group" => "Kullanıcı veya grup yok", "All Users" => "Tüm Kullanıcılar", "Groups" => "Gruplar", "Users" => "Kullanıcılar", diff --git a/apps/files_external/l10n/uk.php b/apps/files_external/l10n/uk.php index a7c028aa935..533eba07eb1 100644 --- a/apps/files_external/l10n/uk.php +++ b/apps/files_external/l10n/uk.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Дозволити доступ", "Please provide a valid Dropbox app key and secret." => "Будь ласка, надайте дійсний ключ та пароль Dropbox.", "Error configuring Google Drive storage" => "Помилка при налаштуванні сховища Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Попередження: Клієнт \"smbclient\" не встановлено. Під'єднанатися до CIFS/SMB тек неможливо. Попрохайте системного адміністратора встановити його.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Попередження: Підтримка FTP в PHP не увімкнута чи не встановлена. Під'єднанатися до FTP тек неможливо. Попрохайте системного адміністратора встановити її.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Попередження: Підтримка CURL в PHP не увімкнута чи не встановлена. Під'єднанатися OwnCloud / WebDav або Google Drive неможливе. Попрохайте системного адміністратора встановити її.", "External Storage" => "Зовнішні сховища", "Folder name" => "Ім'я теки", "External storage" => "Зовнішнє сховище", "Configuration" => "Налаштування", "Options" => "Опції", -"Applicable" => "Придатний", "Add storage" => "Додати сховище", -"None set" => "Не встановлено", "All Users" => "Усі користувачі", "Groups" => "Групи", "Users" => "Користувачі", diff --git a/apps/files_external/l10n/vi.php b/apps/files_external/l10n/vi.php index 5fd00dc2bf5..787fc82832e 100644 --- a/apps/files_external/l10n/vi.php +++ b/apps/files_external/l10n/vi.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Cấp quyền truy cập", "Please provide a valid Dropbox app key and secret." => "Xin vui lòng cung cấp một ứng dụng Dropbox hợp lệ và mã bí mật.", "Error configuring Google Drive storage" => "Lỗi cấu hình lưu trữ Google Drive", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Cảnh báo: \"smbclient\" chưa được cài đặt. Mount CIFS/SMB shares là không thể thực hiện được. Hãy hỏi người quản trị hệ thống để cài đặt nó.", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Cảnh báo: FTP trong PHP chưa được cài đặt hoặc chưa được mở. Mount FTP shares là không thể. Xin hãy yêu cầu quản trị hệ thống của bạn cài đặt nó.", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "Cảnh báo: Tính năng Curl trong PHP chưa được kích hoạt hoặc cài đặt. Việc gắn kết ownCloud / WebDAV hay GoogleDrive không thực hiện được. Vui lòng liên hệ người quản trị để cài đặt nó.", "External Storage" => "Lưu trữ ngoài", "Folder name" => "Tên thư mục", "External storage" => "Lưu trữ ngoài", "Configuration" => "Cấu hình", "Options" => "Tùy chọn", -"Applicable" => "Áp dụng", "Add storage" => "Thêm bộ nhớ", -"None set" => "không", "All Users" => "Tất cả người dùng", "Groups" => "Nhóm", "Users" => "Người dùng", diff --git a/apps/files_external/l10n/zh_CN.php b/apps/files_external/l10n/zh_CN.php index bb85d0e4f49..40d5158bf5c 100644 --- a/apps/files_external/l10n/zh_CN.php +++ b/apps/files_external/l10n/zh_CN.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "授权", "Please provide a valid Dropbox app key and secret." => "请提供有效的Dropbox应用key和secret", "Error configuring Google Drive storage" => "配置Google Drive存储时出错", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "警告:“smbclient” 尚未安装。CIFS/SMB 分享挂载无法实现。请咨询系统管理员进行安装。", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "警告:PHP中尚未启用或安装FTP。FTP 分享挂载无法实现。请咨询系统管理员进行安装。", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "警告: PHP中未启用或未安装Curl支持。ownCloud / WebDAV 或 GoogleDrive 不能挂载。请请求您的系统管理员安装该它。", "External Storage" => "外部存储", "Folder name" => "目录名称", "External storage" => "外部存储", "Configuration" => "配置", "Options" => "选项", -"Applicable" => "适用的", "Add storage" => "添加存储", -"None set" => "未设置", "All Users" => "所有用户", "Groups" => "组", "Users" => "用户", diff --git a/apps/files_external/l10n/zh_TW.php b/apps/files_external/l10n/zh_TW.php index 7c256cd2ab7..ac480e405fb 100644 --- a/apps/files_external/l10n/zh_TW.php +++ b/apps/files_external/l10n/zh_TW.php @@ -5,17 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "允許存取", "Please provide a valid Dropbox app key and secret." => "請提供有效的 Dropbox app key 和 app secret 。", "Error configuring Google Drive storage" => "設定 Google Drive 儲存時發生錯誤", -"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "警告:未安裝 \"smbclient\" ,因此無法掛載 CIFS/SMB 分享,請洽您的系統管理員將其安裝。", -"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "警告:PHP 並未啓用 FTP 的支援,因此無法掛載 FTP 分享,請洽您的系統管理員將其安裝並啓用。", -"Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "警告:PHP 並未啓用 Curl 的支援,因此無法掛載 ownCloud/WebDAV 或 Google Drive 分享,請洽您的系統管理員將其安裝並啓用。", "External Storage" => "外部儲存", "Folder name" => "資料夾名稱", "External storage" => "外部儲存", "Configuration" => "設定", "Options" => "選項", -"Applicable" => "可用的", "Add storage" => "增加儲存區", -"None set" => "尚未設定", "All Users" => "所有使用者", "Groups" => "群組", "Users" => "使用者", diff --git a/apps/files_external/lib/amazons3.php b/apps/files_external/lib/amazons3.php index 06ccd5d16fa..2093fb7e58c 100644 --- a/apps/files_external/lib/amazons3.php +++ b/apps/files_external/lib/amazons3.php @@ -548,4 +548,16 @@ class AmazonS3 extends \OC\Files\Storage\Common { return false; } } + + /** + * check if curl is installed + */ + public static function checkDependencies() { + if (function_exists('curl_init')) { + return true; + } else { + return array('curl'); + } + } + } diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index c5b091336e1..71f6ae78878 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -5,6 +5,7 @@ * @author Michael Gapczynski * @copyright 2012 Michael Gapczynski mtgap@owncloud.com * @copyright 2014 Vincent Petry +* @copyright 2014 Robin McCorkell * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -38,6 +39,34 @@ class OC_Mount_Config { // whether to skip backend test (for unit tests, as this static class is not mockable) public static $skipTest = false; + private static $backends = array(); + + /** + * @param string $class + * @param array $definition + * @return bool + */ + public static function registerBackend($class, $definition) { + if (!isset($definition['backend'])) { + return false; + } + + OC_Mount_Config::$backends[$class] = $definition; + return true; + } + + /** + * Setup backends + * + * @return array of previously registered backends + */ + public static function setUp($backends = array()) { + $backup = self::$backends; + self::$backends = $backends; + + return $backup; + } + /** * Get details on each of the external storage backends, used for the mount config UI * If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded @@ -45,125 +74,32 @@ class OC_Mount_Config { * If the configuration parameter is a boolean, add a '!' to the beginning of the value * If the configuration parameter is optional, add a '&' to the beginning of the value * If the configuration parameter is hidden, add a '#' to the beginning of the value - * @return string + * @return array */ public static function getBackends() { - - // FIXME: do not rely on php key order for the options order in the UI - $backends['\OC\Files\Storage\Local']=array( - 'backend' => 'Local', - 'configuration' => array( - 'datadir' => 'Location')); - - $backends['\OC\Files\Storage\AmazonS3']=array( - 'backend' => 'Amazon S3 and compliant', - 'configuration' => array( - 'key' => 'Access Key', - 'secret' => '*Secret Key', - 'bucket' => 'Bucket', - 'hostname' => '&Hostname (optional)', - 'port' => '&Port (optional)', - 'region' => '&Region (optional)', - 'use_ssl' => '!Enable SSL', - 'use_path_style' => '!Enable Path Style')); - - $backends['\OC\Files\Storage\Dropbox']=array( - 'backend' => 'Dropbox', - 'configuration' => array( - 'configured' => '#configured', - 'app_key' => 'App key', - 'app_secret' => '*App secret', - 'token' => '#token', - 'token_secret' => '#token_secret'), - 'custom' => 'dropbox'); - - if(OC_Mount_Config::checkphpftp()) $backends['\OC\Files\Storage\FTP']=array( - 'backend' => 'FTP', - 'configuration' => array( - 'host' => 'Hostname', - 'user' => 'Username', - 'password' => '*Password', - 'root' => '&Root', - 'secure' => '!Secure ftps://')); - - if(OC_Mount_Config::checkcurl()) $backends['\OC\Files\Storage\Google']=array( - 'backend' => 'Google Drive', - 'configuration' => array( - 'configured' => '#configured', - 'client_id' => 'Client ID', - 'client_secret' => '*Client secret', - 'token' => '#token'), - 'custom' => 'google'); - - if(OC_Mount_Config::checkcurl()) { - $backends['\OC\Files\Storage\Swift'] = array( - 'backend' => 'OpenStack Object Storage', - 'configuration' => array( - 'user' => 'Username (required)', - 'bucket' => 'Bucket (required)', - 'region' => '&Region (optional for OpenStack Object Storage)', - 'key' => '*API Key (required for Rackspace Cloud Files)', - 'tenant' => '&Tenantname (required for OpenStack Object Storage)', - 'password' => '*Password (required for OpenStack Object Storage)', - 'service_name' => '&Service Name (required for OpenStack Object Storage)', - 'url' => '&URL of identity endpoint (required for OpenStack Object Storage)', - 'timeout' => '&Timeout of HTTP requests in seconds (optional)', - ) - ); - } - - if (!OC_Util::runningOnWindows()) { - if (OC_Mount_Config::checksmbclient()) { - $backends['\OC\Files\Storage\SMB'] = array( - 'backend' => 'SMB / CIFS', - 'configuration' => array( - 'host' => 'URL', - 'user' => 'Username', - 'password' => '*Password', - 'share' => 'Share', - 'root' => '&Root')); + $sortFunc = function($a, $b) { + return strcasecmp($a['backend'], $b['backend']); + }; + + $backEnds = array(); + + foreach (OC_Mount_Config::$backends as $class => $backend) { + if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) { + if (!method_exists($class, 'checkDependencies')) { + \OCP\Util::writeLog('files_external', + "Backend class $class has dependencies but doesn't provide method checkDependencies()", + \OCP\Util::DEBUG); + continue; + } elseif ($class::checkDependencies() !== true) { + continue; + } } + $backEnds[$class] = $backend; } - if(OC_Mount_Config::checkcurl()){ - $backends['\OC\Files\Storage\DAV']=array( - 'backend' => 'WebDAV', - 'configuration' => array( - 'host' => 'URL', - 'user' => 'Username', - 'password' => '*Password', - 'root' => '&Root', - 'secure' => '!Secure https://')); - $backends['\OC\Files\Storage\OwnCloud']=array( - 'backend' => 'ownCloud', - 'configuration' => array( - 'host' => 'URL', - 'user' => 'Username', - 'password' => '*Password', - 'root' => '&Remote subfolder', - 'secure' => '!Secure https://')); - } - - $backends['\OC\Files\Storage\SFTP']=array( - 'backend' => 'SFTP', - 'configuration' => array( - 'host' => 'URL', - 'user' => 'Username', - 'password' => '*Password', - 'root' => '&Root')); - - $backends['\OC\Files\Storage\iRODS']=array( - 'backend' => 'iRODS', - 'configuration' => array( - 'host' => 'Host', - 'port' => 'Port', - 'use_logon_credentials' => '!Use ownCloud login', - 'user' => 'Username', - 'password' => '*Password', - 'auth_mode' => 'Authentication Mode', - 'zone' => 'Zone')); - - return($backends); + uasort($backEnds, $sortFunc); + + return $backEnds; } /** @@ -185,7 +121,7 @@ class OC_Mount_Config { * @return array of mount point string as key, mountpoint config as value */ public static function getAbsoluteMountPoints($user) { - $mountPoints = array(); + $mountPoints = array(); $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data"); $mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json"); @@ -270,19 +206,25 @@ class OC_Mount_Config { */ public static function getPersonalBackends() { - $backends = self::getBackends(); + // Check whether the user has permissions to add personal storage backends + // return an empty array if this is not the case + if(OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') { + return array(); + } + + $backEnds = self::getBackends(); // Remove local storage and other disabled storages - unset($backends['\OC\Files\Storage\Local']); + unset($backEnds['\OC\Files\Storage\Local']); - $allowed_backends = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', '')); - foreach ($backends as $backend => $null) { - if (!in_array($backend, $allowed_backends)) { - unset($backends[$backend]); + $allowedBackEnds = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', '')); + foreach ($backEnds as $backend => $null) { + if (!in_array($backend, $allowedBackEnds)) { + unset($backEnds[$backend]); } } - return $backends; + return $backEnds; } /** @@ -304,18 +246,23 @@ class OC_Mount_Config { $mount['options'] = self::decryptPasswords($mount['options']); // Remove '/$user/files/' from mount point $mountPoint = substr($mountPoint, 13); - // Merge the mount point into the current mount points - if (isset($system[$mountPoint]) && $system[$mountPoint]['configuration'] == $mount['options']) { - $system[$mountPoint]['applicable']['groups'] - = array_merge($system[$mountPoint]['applicable']['groups'], array($group)); + + $config = array( + 'class' => $mount['class'], + 'mountpoint' => $mountPoint, + 'backend' => $backends[$mount['class']]['backend'], + 'options' => $mount['options'], + 'applicable' => array('groups' => array($group), 'users' => array()), + 'status' => self::getBackendStatus($mount['class'], $mount['options'], false) + ); + $hash = self::makeConfigHash($config); + // If an existing config exists (with same class, mountpoint and options) + if (isset($system[$hash])) { + // add the groups into that config + $system[$hash]['applicable']['groups'] + = array_merge($system[$hash]['applicable']['groups'], array($group)); } else { - $system[$mountPoint] = array( - 'class' => $mount['class'], - 'backend' => $backends[$mount['class']]['backend'], - 'configuration' => $mount['options'], - 'applicable' => array('groups' => array($group), 'users' => array()), - 'status' => self::getBackendStatus($mount['class'], $mount['options']) - ); + $system[$hash] = $config; } } } @@ -330,23 +277,27 @@ class OC_Mount_Config { $mount['options'] = self::decryptPasswords($mount['options']); // Remove '/$user/files/' from mount point $mountPoint = substr($mountPoint, 13); - // Merge the mount point into the current mount points - if (isset($system[$mountPoint]) && $system[$mountPoint]['configuration'] == $mount['options']) { - $system[$mountPoint]['applicable']['users'] - = array_merge($system[$mountPoint]['applicable']['users'], array($user)); + $config = array( + 'class' => $mount['class'], + 'mountpoint' => $mountPoint, + 'backend' => $backends[$mount['class']]['backend'], + 'options' => $mount['options'], + 'applicable' => array('groups' => array(), 'users' => array($user)), + 'status' => self::getBackendStatus($mount['class'], $mount['options'], false) + ); + $hash = self::makeConfigHash($config); + // If an existing config exists (with same class, mountpoint and options) + if (isset($system[$hash])) { + // add the users into that config + $system[$hash]['applicable']['users'] + = array_merge($system[$hash]['applicable']['users'], array($user)); } else { - $system[$mountPoint] = array( - 'class' => $mount['class'], - 'backend' => $backends[$mount['class']]['backend'], - 'configuration' => $mount['options'], - 'applicable' => array('groups' => array(), 'users' => array($user)), - 'status' => self::getBackendStatus($mount['class'], $mount['options']) - ); + $system[$hash] = $config; } } } } - return $system; + return array_values($system); } /** @@ -356,7 +307,7 @@ class OC_Mount_Config { */ public static function getPersonalMountPoints() { $mountPoints = self::readData(true); - $backends = self::getBackends(); + $backEnds = self::getBackends(); $uid = OCP\User::getUser(); $personal = array(); if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) { @@ -366,12 +317,13 @@ class OC_Mount_Config { $mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15); } $mount['options'] = self::decryptPasswords($mount['options']); - // Remove '/uid/files/' from mount point - $personal[substr($mountPoint, strlen($uid) + 8)] = array( + $personal[] = array( 'class' => $mount['class'], - 'backend' => $backends[$mount['class']]['backend'], - 'configuration' => $mount['options'], - 'status' => self::getBackendStatus($mount['class'], $mount['options']) + // Remove '/uid/files/' from mount point + 'mountpoint' => substr($mountPoint, strlen($uid) + 8), + 'backend' => $backEnds[$mount['class']]['backend'], + 'options' => $mount['options'], + 'status' => self::getBackendStatus($mount['class'], $mount['options'], true) ); } } @@ -384,7 +336,7 @@ class OC_Mount_Config { * @param array $options backend configuration options * @return bool true if the connection succeeded, false otherwise */ - private static function getBackendStatus($class, $options) { + private static function getBackendStatus($class, $options, $isPersonal) { if (self::$skipTest) { return true; } @@ -394,7 +346,7 @@ class OC_Mount_Config { if (class_exists($class)) { try { $storage = new $class($options); - return $storage->test(); + return $storage->test($isPersonal); } catch (Exception $exception) { \OCP\Util::logException('files_external', $exception); return false; @@ -461,7 +413,7 @@ class OC_Mount_Config { $mountPoints[$mountType] = $mount; } self::writeData($isPersonal, $mountPoints); - return self::getBackendStatus($class, $classOptions); + return self::getBackendStatus($class, $classOptions, $isPersonal); } /** @@ -596,54 +548,91 @@ class OC_Mount_Config { } /** - * check if smbclient is installed + * check dependencies */ - public static function checksmbclient() { - if(function_exists('shell_exec')) { - $output=shell_exec('command -v smbclient 2> /dev/null'); - return !empty($output); - }else{ - return false; + public static function checkDependencies() { + $dependencies = array(); + foreach (OC_Mount_Config::$backends as $class => $backend) { + if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) { + $result = $class::checkDependencies(); + if ($result !== true) { + if (!is_array($result)) { + $result = array($result); + } + foreach ($result as $key => $value) { + if (is_numeric($key)) { + OC_Mount_Config::addDependency($dependencies, $value, $backend['backend']); + } else { + OC_Mount_Config::addDependency($dependencies, $key, $backend['backend'], $value); + } + } + } + } + } + + if (count($dependencies) > 0) { + return OC_Mount_Config::generateDependencyMessage($dependencies); } + return ''; } - /** - * check if php-ftp is installed - */ - public static function checkphpftp() { - if(function_exists('ftp_login')) { - return true; - }else{ - return false; + private static function addDependency(&$dependencies, $module, $backend, $message=null) { + if (!isset($dependencies[$module])) { + $dependencies[$module] = array(); + } + + if ($message === null) { + $dependencies[$module][] = $backend; + } else { + $dependencies[$module][] = array('backend' => $backend, 'message' => $message); } } - /** - * check if curl is installed - */ - public static function checkcurl() { - return function_exists('curl_init'); + private static function generateDependencyMessage($dependencies) { + $l = new \OC_L10N('files_external'); + $dependencyMessage = ''; + foreach ($dependencies as $module => $backends) { + $dependencyGroup = array(); + foreach ($backends as $backend) { + if (is_array($backend)) { + $dependencyMessage .= '
' . $l->t('Note: ') . $backend['message']; + } else { + $dependencyGroup[] = $backend; + } + } + + if (count($dependencyGroup) > 0) { + $backends = ''; + for ($i = 0; $i < count($dependencyGroup); $i++) { + if ($i > 0 && $i === count($dependencyGroup) - 1) { + $backends .= $l->t(' and '); + } elseif ($i > 0) { + $backends .= ', '; + } + $backends .= '' . $dependencyGroup[$i] . ''; + } + $dependencyMessage .= '
' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends); + } + } + return $dependencyMessage; } /** - * check dependencies + * Returns a dependency missing message + * @param $l OC_L10N + * @param $module string + * @param $backend string + * @return string */ - public static function checkDependencies() { - $l= new OC_L10N('files_external'); - $txt=''; - if (!OC_Util::runningOnWindows()) { - if(!OC_Mount_Config::checksmbclient()) { - $txt.=$l->t('Warning: "smbclient" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it.').'
'; - } - } - if(!OC_Mount_Config::checkphpftp()) { - $txt.=$l->t('Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it.').'
'; + private static function getSingleDependencyMessage($l, $module, $backend) { + switch (strtolower($module)) { + case 'curl': + return $l->t('Note: The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend); + case 'ftp': + return $l->t('Note: The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend); + default: + return $l->t('Note: "%s" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.', array($module, $backend)); } - if(!OC_Mount_Config::checkcurl()) { - $txt.=$l->t('Warning: The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it.').'
'; - } - - return $txt; } /** @@ -712,4 +701,20 @@ class OC_Mount_Config { $cipher->setKey(\OCP\Config::getSystemValue('passwordsalt')); return $cipher; } + + /** + * Computes a hash based on the given configuration. + * This is mostly used to find out whether configurations + * are the same. + */ + private static function makeConfigHash($config) { + $data = json_encode( + array( + 'c' => $config['class'], + 'm' => $config['mountpoint'], + 'o' => $config['options'] + ) + ); + return hash('md5', $data); + } } diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php index 0214e18020c..38de3360f2b 100755 --- a/apps/files_external/lib/dropbox.php +++ b/apps/files_external/lib/dropbox.php @@ -311,4 +311,15 @@ class Dropbox extends \OC\Files\Storage\Common { return true; } + /** + * check if curl is installed + */ + public static function checkDependencies() { + if (function_exists('curl_init')) { + return true; + } else { + return array('curl'); + } + } + } diff --git a/apps/files_external/lib/ftp.php b/apps/files_external/lib/ftp.php index 00bf7a189ce..b3f8b1444ae 100644 --- a/apps/files_external/lib/ftp.php +++ b/apps/files_external/lib/ftp.php @@ -119,4 +119,16 @@ class FTP extends \OC\Files\Storage\StreamWrapper{ unlink($tmpFile); } } + + /** + * check if php-ftp is installed + */ + public static function checkDependencies() { + if (function_exists('ftp_login')) { + return(true); + } else { + return array('ftp'); + } + } + } diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php index 35457f68528..56c0d451651 100644 --- a/apps/files_external/lib/google.php +++ b/apps/files_external/lib/google.php @@ -586,4 +586,15 @@ class Google extends \OC\Files\Storage\Common { return false; } + /** + * check if curl is installed + */ + public static function checkDependencies() { + if (function_exists('curl_init')) { + return true; + } else { + return array('curl'); + } + } + } diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index f3f3b3ed7f3..b1d355323d9 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -134,4 +134,18 @@ class SMB extends \OC\Files\Storage\StreamWrapper{ } return $lastCtime; } + + /** + * check if smbclient is installed + */ + public static function checkDependencies() { + if (function_exists('shell_exec')) { + $output=shell_exec('command -v smbclient 2> /dev/null'); + if (!empty($output)) { + return true; + } + } + return array('smbclient'); + } + } diff --git a/apps/files_external/lib/smb_oc.php b/apps/files_external/lib/smb_oc.php new file mode 100644 index 00000000000..0c79c06c5df --- /dev/null +++ b/apps/files_external/lib/smb_oc.php @@ -0,0 +1,93 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +require_once __DIR__ . '/../3rdparty/smb4php/smb.php'; + +class SMB_OC extends \OC\Files\Storage\SMB { + private $username_as_share; + + public function __construct($params) { + if (isset($params['host']) && \OC::$session->exists('smb-credentials')) { + $host=$params['host']; + $this->username_as_share = ($params['username_as_share'] === 'true'); + + $params_auth = \OC::$session->get('smb-credentials'); + $user = \OC::$session->get('loginname'); + $password = $params_auth['password']; + + $root=isset($params['root'])?$params['root']:'/'; + $share = ''; + + if ($this->username_as_share) { + $share = '/'.$user; + } elseif (isset($params['share'])) { + $share = $params['share']; + } else { + throw new \Exception(); + } + parent::__construct(array( + "user" => $user, + "password" => $password, + "host" => $host, + "share" => $share, + "root" => $root + )); + } else { + throw new \Exception(); + } + } + + public static function login( $params ) { + \OC::$session->set('smb-credentials', $params); + } + + public function isSharable($path) { + return false; + } + + public function test($isPersonal = true) { + if ($isPersonal) { + if ($this->stat('')) { + return true; + } + return false; + } else { + $smb = new \smb(); + $pu = $smb->parse_url($this->constructUrl('')); + + // Attempt to connect anonymously + $pu['user'] = ''; + $pu['pass'] = ''; + + // Share cannot be checked if dynamic + if ($this->username_as_share) { + if ($smb->look($pu)) { + return true; + } else { + return false; + } + } + if (!$pu['share']) { + return false; + } + + // The following error messages are expected due to anonymous login + $regexp = array( + '(NT_STATUS_ACCESS_DENIED)' => 'skip' + ) + $smb->getRegexp(); + + if ($smb->client("-d 0 " . escapeshellarg('//' . $pu['host'] . '/' . $pu['share']) . " -c exit", $pu, $regexp)) { + return true; + } else { + return false; + } + } + } +} diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index 7a56fcfc8b7..a202d3843cb 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -65,6 +65,18 @@ class Swift extends \OC\Files\Storage\Common { return $path; } + const SUBCONTAINER_FILE='.subcontainers'; + + /** + * translate directory path to container name + * @param string $path + * @return string + */ + private function getContainerName($path) { + $path=trim(trim($this->root, '/') . "/".$path, '/.'); + return str_replace('/', '\\', $path); + } + /** * @param string $path */ @@ -251,6 +263,10 @@ class Swift extends \OC\Files\Storage\Common { $mtime = $object->extra_headers['X-Object-Meta-Timestamp']; } + if (!empty($mtime)) { + $mtime = floor($mtime); + } + $stat = array(); $stat['size'] = $object->content_length; $stat['mtime'] = $mtime; @@ -370,7 +386,7 @@ class Swift extends \OC\Files\Storage\Common { 'X-Object-Meta-Timestamp' => $mtime ) ); - return $object->Update($settings); + return $object->UpdateMetadata($settings); } else { $object = $this->container->DataObject(); if (is_null($mtime)) { @@ -486,4 +502,16 @@ class Swift extends \OC\Files\Storage\Common { ), $tmpFile); unlink($tmpFile); } + + /** + * check if curl is installed + */ + public static function checkDependencies() { + if (function_exists('curl_init')) { + return true; + } else { + return array('curl'); + } + } + } diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index 279ae716935..dc98dcfb808 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -267,7 +267,7 @@ class DAV extends \OC\Files\Storage\Common { $curl = curl_init(); curl_setopt($curl, CURLOPT_USERPWD, $this->user . ':' . $this->password); - curl_setopt($curl, CURLOPT_URL, $this->createBaseUri() . str_replace(' ', '%20', $target)); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri() . $this->encodePath($target)); curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path)); @@ -385,5 +385,16 @@ class DAV extends \OC\Files\Storage\Common { return false; } } + + /** + * check if curl is installed + */ + public static function checkDependencies() { + if (function_exists('curl_init')) { + return true; + } else { + return array('curl'); + } + } } diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index de44d3c8644..0d04e35e7fe 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -1,149 +1,152 @@ -
-
+

t('External Storage')); ?>

- '')) print_unescaped(''.$_['dependencies'].''); ?> - '> - - - - - - - - '.$l->t('Applicable').''); ?> - - - - - array())); ?> - $mount): ?> - > - + + + + + + + +
t('Folder name')); ?>t('External storage')); ?>t('Configuration')); ?> 
- - - + '')) print_unescaped(''.$_['dependencies'].''); ?> + '> + + + + + + + + '.$l->t('Available for').''); ?> + + + + + array())); ?> + + > + + + + - - - - - - - + + - - - - - - -
t('Folder name')); ?>t('External storage')); ?>t('Configuration')); ?> 
+ + + + + - - - - $value): ?> - - - - - - - - - - - - - + + + + $value): ?> + + + + class="optional" + data-parameter="" + value="" + placeholder="" /> + + + + + + class="optional" + data-parameter="" + value="" + placeholder="" /> - - - + + + - ' - data-applicable-users=''> - - class="remove" - style="visibility:hidden;" - ><?php p($l->t('Delete')); ?>
-
+
' + data-applicable-users=''> + + class="remove" + style="visibility:hidden;" + ><?php p($l->t('Delete')); ?>
+
- -
- /> - + +
+ /> + -

class="hidden"> - t('Allow users to mount the following external storage')); ?>
- $backend): ?> - /> -
- - -

- -
+

class="hidden"> + t('Allow users to mount the following external storage')); ?>
+ $backend): ?> + /> +
+ + +

+
-
-

t('SSL root certificates'));?>

'> @@ -163,6 +166,5 @@ - diff --git a/apps/files_external/tests/dynamicmountconfig.php b/apps/files_external/tests/dynamicmountconfig.php new file mode 100644 index 00000000000..81a31e14c60 --- /dev/null +++ b/apps/files_external/tests/dynamicmountconfig.php @@ -0,0 +1,103 @@ + + * + * 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 . + * + */ + +require_once __DIR__ . '/../../../lib/base.php'; + +require __DIR__ . '/../lib/config.php'; + +/** + * Class Test_Mount_Config_Dummy_Backend + */ +class Test_Mount_Config_Dummy_Backend { + public static $checkDependencies = true; + + public static function checkDependencies() { + return self::$checkDependencies; + } +} + +/** + * Class Test_Dynamic_Mount_Config + */ +class Test_Dynamic_Mount_Config extends \PHPUnit_Framework_TestCase { + + private $backup; + + public function testRegistration() { + + // second registration shall return false + $result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array( + 'backend' => 'Test Dummy', + 'configuration' => array(), + 'has_dependencies' => true)); + + $this->assertTrue($result); + } + + public function testDependencyGetBackend() { + + // is the backend listed? + Test_Mount_Config_Dummy_Backend::$checkDependencies = true; + $backEnds = OC_Mount_Config::getBackends(); + $this->assertArrayHasKey('Test_Mount_Config_Dummy_Backend', $backEnds); + + // backend shall not be listed + Test_Mount_Config_Dummy_Backend::$checkDependencies = false; + + $backEnds = OC_Mount_Config::getBackends(); + $this->assertArrayNotHasKey('Test_Mount_Config_Dummy_Backend', $backEnds); + + } + + public function testCheckDependencies() { + + Test_Mount_Config_Dummy_Backend::$checkDependencies = true; + $message = OC_Mount_Config::checkDependencies(); + $this->assertEmpty($message); + + // backend shall not be listed + Test_Mount_Config_Dummy_Backend::$checkDependencies = array('dummy'); + + $message = OC_Mount_Config::checkDependencies(); + $this->assertEquals('
Note: "dummy" is not installed. Mounting of Test Dummy is not possible. Please ask your system administrator to install it.', + $message); + + } + + protected function setUp() { + + $this->backup = OC_Mount_Config::setUp(); + + // register dummy backend + $result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array( + 'backend' => 'Test Dummy', + 'configuration' => array(), + 'has_dependencies' => true)); + + $this->assertTrue($result); + } + + protected function tearDown() + { + OC_Mount_Config::setUp($this->backup); + } +} diff --git a/apps/files_external/tests/mountconfig.php b/apps/files_external/tests/mountconfig.php index bf43bb31c38..c89874c94d5 100644 --- a/apps/files_external/tests/mountconfig.php +++ b/apps/files_external/tests/mountconfig.php @@ -211,14 +211,52 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { } + /** + * Provider for testing configurations with different + * "applicable" values (all, user, groups) + */ + public function applicableConfigProvider() { + return array( + // applicable to "all" + array( + OC_Mount_Config::MOUNT_TYPE_USER, + 'all', + array( + 'users' => array('all'), + 'groups' => array() + ) + ), + // applicable to single user + array( + OC_Mount_Config::MOUNT_TYPE_USER, + self::TEST_USER1, + array( + 'users' => array(self::TEST_USER1), + 'groups' => array() + ) + ), + // applicable to single group + array( + OC_Mount_Config::MOUNT_TYPE_GROUP, + self::TEST_GROUP1, + array( + 'users' => array(), + 'groups' => array(self::TEST_GROUP1) + ) + ), + ); + } + /** * Test reading and writing global config + * + * @dataProvider applicableConfigProvider */ - public function testReadWriteGlobalConfig() { - $mountType = OC_Mount_Config::MOUNT_TYPE_USER; - $applicable = 'all'; + public function testReadWriteGlobalConfig($mountType, $applicable, $expectApplicableArray) { + $mountType = $mountType; + $applicable = $applicable; $isPersonal = false; - $mountConfig = array( + $options = array( 'host' => 'smbhost', 'user' => 'smbuser', 'password' => 'smbpassword', @@ -231,7 +269,7 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { OC_Mount_Config::addMountPoint( '/ext', '\OC\Files\Storage\SMB', - $mountConfig, + $options, $mountType, $applicable, $isPersonal @@ -241,12 +279,13 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { // re-read config $config = OC_Mount_Config::getSystemMountPoints(); $this->assertEquals(1, count($config)); - $this->assertTrue(isset($config['ext'])); - $this->assertEquals('\OC\Files\Storage\SMB', $config['ext']['class']); - $savedMountConfig = $config['ext']['configuration']; - $this->assertEquals($mountConfig, $savedMountConfig); + $this->assertEquals('\OC\Files\Storage\SMB', $config[0]['class']); + $this->assertEquals('ext', $config[0]['mountpoint']); + $this->assertEquals($expectApplicableArray, $config[0]['applicable']); + $savedOptions = $config[0]['options']; + $this->assertEquals($options, $savedOptions); // key order needs to be preserved for the UI... - $this->assertEquals(array_keys($mountConfig), array_keys($savedMountConfig)); + $this->assertEquals(array_keys($options), array_keys($savedOptions)); } /** @@ -256,7 +295,7 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { $mountType = OC_Mount_Config::MOUNT_TYPE_USER; $applicable = self::TEST_USER1; $isPersonal = true; - $mountConfig = array( + $options = array( 'host' => 'smbhost', 'user' => 'smbuser', 'password' => 'smbpassword', @@ -269,7 +308,7 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { OC_Mount_Config::addMountPoint( '/ext', '\OC\Files\Storage\SMB', - $mountConfig, + $options, $mountType, $applicable, $isPersonal @@ -279,12 +318,12 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { // re-read config $config = OC_Mount_Config::getPersonalMountPoints(); $this->assertEquals(1, count($config)); - $this->assertTrue(isset($config['ext'])); - $this->assertEquals('\OC\Files\Storage\SMB', $config['ext']['class']); - $savedMountConfig = $config['ext']['configuration']; - $this->assertEquals($mountConfig, $savedMountConfig); + $this->assertEquals('\OC\Files\Storage\SMB', $config[0]['class']); + $this->assertEquals('ext', $config[0]['mountpoint']); + $savedOptions = $config[0]['options']; + $this->assertEquals($options, $savedOptions); // key order needs to be preserved for the UI... - $this->assertEquals(array_keys($mountConfig), array_keys($savedMountConfig)); + $this->assertEquals(array_keys($options), array_keys($savedOptions)); } /** @@ -362,7 +401,7 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { // re-read config, password was read correctly $config = OC_Mount_Config::getPersonalMountPoints(); - $savedMountConfig = $config['ext']['configuration']; + $savedMountConfig = $config[0]['options']; $this->assertEquals($mountConfig, $savedMountConfig); } @@ -475,4 +514,130 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase { $this->assertEquals(0, count($mountPoints)); } } + + /** + * Test the same config for multiple users. + * The config will be merged by getSystemMountPoints(). + */ + public function testConfigMerging() { + $mountType = OC_Mount_Config::MOUNT_TYPE_USER; + $isPersonal = false; + $options = array( + 'host' => 'smbhost', + 'user' => 'smbuser', + 'password' => 'smbpassword', + 'share' => 'smbshare', + 'root' => 'smbroot' + ); + + // write config + $this->assertTrue( + OC_Mount_Config::addMountPoint( + '/ext', + '\OC\Files\Storage\SMB', + $options, + OC_Mount_Config::MOUNT_TYPE_USER, + self::TEST_USER1, + $isPersonal + ) + ); + + $this->assertTrue( + OC_Mount_Config::addMountPoint( + '/ext', + '\OC\Files\Storage\SMB', + $options, + OC_Mount_Config::MOUNT_TYPE_USER, + self::TEST_USER2, + $isPersonal + ) + ); + + $this->assertTrue( + OC_Mount_Config::addMountPoint( + '/ext', + '\OC\Files\Storage\SMB', + $options, + OC_Mount_Config::MOUNT_TYPE_GROUP, + self::TEST_GROUP2, + $isPersonal + ) + ); + + $this->assertTrue( + OC_Mount_Config::addMountPoint( + '/ext', + '\OC\Files\Storage\SMB', + $options, + OC_Mount_Config::MOUNT_TYPE_GROUP, + self::TEST_GROUP1, + $isPersonal + ) + ); + + // re-read config + $config = OC_Mount_Config::getSystemMountPoints(); + $this->assertEquals(1, count($config)); + $this->assertEquals('\OC\Files\Storage\SMB', $config[0]['class']); + $this->assertEquals('ext', $config[0]['mountpoint']); + $this->assertEquals($options, $config[0]['options']); + $this->assertEquals(array(self::TEST_USER1, self::TEST_USER2), $config[0]['applicable']['users']); + $this->assertEquals(array(self::TEST_GROUP2, self::TEST_GROUP1), $config[0]['applicable']['groups']); + } + + /** + * Create then re-read mount points configs where the mount points + * have the same path, the config must NOT be merged. + */ + public function testRereadMountpointWithSamePath() { + $mountType = OC_Mount_Config::MOUNT_TYPE_USER; + $isPersonal = false; + $options1 = array( + 'host' => 'smbhost', + 'user' => 'smbuser', + 'password' => 'smbpassword', + 'share' => 'smbshare', + 'root' => 'smbroot' + ); + + // write config + $this->assertTrue( + OC_Mount_Config::addMountPoint( + '/ext', + '\OC\Files\Storage\SMB', + $options1, + $mountType, + self::TEST_USER1, + $isPersonal + ) + ); + + $options2 = array( + 'host' => 'anothersmbhost', + 'user' => 'anothersmbuser', + 'password' => 'anothersmbpassword', + 'share' => 'anothersmbshare', + 'root' => 'anothersmbroot' + ); + $this->assertTrue( + OC_Mount_Config::addMountPoint( + '/ext', + '\OC\Files\Storage\SMB', + $options2, + $mountType, + self::TEST_USER2, + $isPersonal + ) + ); + + // re-read config + $config = OC_Mount_Config::getSystemMountPoints(); + $this->assertEquals(2, count($config)); + $this->assertEquals('\OC\Files\Storage\SMB', $config[0]['class']); + $this->assertEquals('ext', $config[0]['mountpoint']); + $this->assertEquals($options1, $config[0]['options']); + $this->assertEquals('\OC\Files\Storage\SMB', $config[1]['class']); + $this->assertEquals('ext', $config[1]['mountpoint']); + $this->assertEquals($options2, $config[1]['options']); + } } diff --git a/apps/files_sharing/ajax/list.php b/apps/files_sharing/ajax/list.php new file mode 100644 index 00000000000..4b645496253 --- /dev/null +++ b/apps/files_sharing/ajax/list.php @@ -0,0 +1,91 @@ + + * + * 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 . + * + */ + +// only need filesystem apps +$RUNTIME_APPTYPES=array('filesystem'); + +// Init owncloud + +if(!\OC_App::isEnabled('files_sharing')){ + exit; +} + +if(!isset($_GET['t'])){ + \OC_Response::setStatus(400); //400 Bad Request + \OC_Log::write('core-preview', 'No token parameter was passed', \OC_Log::DEBUG); + exit; +} + +$token = $_GET['t']; + +$password = null; +if (isset($_POST['password'])) { + $password = $_POST['password']; +} + +$relativePath = null; +if (isset($_GET['dir'])) { + $relativePath = $_GET['dir']; +} + +$data = \OCA\Files_Sharing\Helper::setupFromToken($token, $relativePath, $password); + +$linkItem = $data['linkItem']; +// Load the files +$dir = $data['realPath']; + +$dir = \OC\Files\Filesystem::normalizePath($dir); +if (!\OC\Files\Filesystem::is_dir($dir . '/')) { + \OC_Response::setStatus(404); + \OCP\JSON::error(array('success' => false)); + exit(); +} + +$data = array(); +$baseUrl = OCP\Util::linkTo('files_sharing', 'index.php') . '?t=' . urlencode($token) . '&dir='; + +// make filelist +$files = \OCA\Files\Helper::getFiles($dir); + +$formattedFiles = array(); +foreach ($files as $file) { + $entry = \OCA\Files\Helper::formatFileInfo($file); + unset($entry['directory']); // for now + $entry['permissions'] = \OCP\PERMISSION_READ; + $formattedFiles[] = $entry; +} + +$data['directory'] = $relativePath; +$data['files'] = $formattedFiles; +$data['dirToken'] = $linkItem['token']; + +$permissions = $linkItem['permissions']; + +// if globally disabled +if (OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') { + // only allow reading + $permissions = \OCP\PERMISSION_READ; +} + +$data['permissions'] = $permissions; + +OCP\JSON::success(array('data' => $data)); diff --git a/apps/files_sharing/appinfo/update.php b/apps/files_sharing/appinfo/update.php index 4b716e764f4..ab32108ea25 100644 --- a/apps/files_sharing/appinfo/update.php +++ b/apps/files_sharing/appinfo/update.php @@ -71,19 +71,6 @@ if (version_compare($installedVersion, '0.3', '<')) { } // clean up oc_share table from files which are no longer exists -if (version_compare($installedVersion, '0.3.5', '<')) { - - // get all shares where the original file no longer exists - $findShares = \OC_DB::prepare('SELECT `file_source` FROM `*PREFIX*share` LEFT JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` WHERE `*PREFIX*filecache`.`fileid` IS NULL AND `*PREFIX*share`.`item_type` IN (\'file\', \'folder\')'); - $sharesFound = $findShares->execute(array())->fetchAll(); - - // delete those shares from the oc_share table - if (is_array($sharesFound) && !empty($sharesFound)) { - $delArray = array(); - foreach ($sharesFound as $share) { - $delArray[] = $share['file_source']; - } - $removeShares = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `file_source` IN (?)'); - $result = $removeShares->execute(array(implode(',', $delArray))); - } +if (version_compare($installedVersion, '0.3.5.6', '<')) { + \OC\Files\Cache\Shared_Updater::fixBrokenSharesOnAppUpdate(); } diff --git a/apps/files_sharing/appinfo/version b/apps/files_sharing/appinfo/version index 09e9157034c..8f91d33378e 100644 --- a/apps/files_sharing/appinfo/version +++ b/apps/files_sharing/appinfo/version @@ -1 +1 @@ -0.3.5 \ No newline at end of file +0.3.5.6 diff --git a/apps/files_sharing/css/mobile.css b/apps/files_sharing/css/mobile.css index 7d2116d190d..333c4c77fc9 100644 --- a/apps/files_sharing/css/mobile.css +++ b/apps/files_sharing/css/mobile.css @@ -1,4 +1,4 @@ -@media only screen and (max-width: 600px) { +@media only screen and (max-width: 768px) { /* make header scroll up for single shares, more view of content on small screens */ #header.share-file { @@ -45,5 +45,13 @@ table td.filename .nametext { display: none; } +/* ellipsis on file names */ +.nametext { + width: 60%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + } diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 5246a4b2fec..f0b9b04491f 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -35,6 +35,11 @@ body { background: #fff; text-align: center; margin: 45px auto 0; + min-height: 150px; +} + +#preview .notCreatable { + display: none; } #noPreview { diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index 06c168969de..9ce8985f1fd 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -8,16 +8,7 @@ * */ -/* global OC, FileList, FileActions */ - -// Override download path to files_sharing/public.php -function fileDownloadPath(dir, file) { - var url = $('#downloadURL').val(); - if (url.indexOf('&path=') != -1) { - url += '/'+file; - } - return url; -} +/* global OC, FileActions, FileList, Files */ $(document).ready(function() { @@ -31,31 +22,43 @@ $(document).ready(function() { action($('#filename').val()); } } - FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename) { - var tr = FileList.findFileEl(filename); - if (tr.length > 0) { - window.location = $(tr).find('a.name').attr('href'); - } - }); + } - // override since the format is different - FileList.getDownloadUrl = function(filename, dir) { - if ($.isArray(filename)) { - filename = JSON.stringify(filename); - } - var path = dir || FileList.getCurrentDirectory(); - var params = { - service: 'files', - t: $('#sharingToken').val(), - path: path, - download: null - }; - if (filename) { - params.files = filename; - } - return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params); + // override since the format is different + Files.getDownloadUrl = function(filename, dir) { + if ($.isArray(filename)) { + filename = JSON.stringify(filename); + } + var path = dir || FileList.getCurrentDirectory(); + var params = { + service: 'files', + t: $('#sharingToken').val(), + path: path, + files: filename, + download: null }; - } + return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params); + }; + + Files.getAjaxUrl = function(action, params) { + params = params || {}; + params.t = $('#sharingToken').val(); + return OC.filePath('files_sharing', 'ajax', action + '.php') + '?' + OC.buildQueryString(params); + }; + + FileList.linkTo = function(dir) { + var params = { + service: 'files', + t: $('#sharingToken').val(), + dir: dir + }; + return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params); + }; + + Files.generatePreviewUrl = function(urlSpec) { + urlSpec.t = $('#dirToken').val(); + return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec); + }; var file_upload_start = $('#file_upload_start'); file_upload_start.on('fileuploadadd', function(e, data) { diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 9f0ed12f935..3c7c9239a6c 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -1,15 +1,35 @@ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +/* global OC, t, FileList, FileActions */ $(document).ready(function() { var disableSharing = $('#disableSharing').data('status'), sharesLoaded = false; if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined' && !disableSharing) { + var oldCreateRow = FileList._createRow; + FileList._createRow = function(fileData) { + var tr = oldCreateRow.apply(this, arguments); + if (fileData.shareOwner) { + tr.attr('data-share-owner', fileData.shareOwner); + } + return tr; + }; + $('#fileList').on('fileActionsReady',function(){ - var allShared = $('#fileList').find('[data-share-owner]').find('[data-Action="Share"]'); + var allShared = $('#fileList').find('[data-share-owner] [data-Action="Share"]'); allShared.addClass('permanent'); allShared.find('span').text(function(){ - $owner = $(this).closest('tr').attr('data-share-owner'); + var $owner = $(this).closest('tr').attr('data-share-owner'); return ' ' + t('files_sharing', 'Shared by {owner}', {owner: $owner}); }); @@ -25,11 +45,6 @@ $(document).ready(function() { }); FileActions.register('all', 'Share', OC.PERMISSION_READ, OC.imagePath('core', 'actions/share'), function(filename) { - var dir = $('#dir').val(); - var item = dir + '/' + filename; - if (dir == '/') { - item = dir + filename; - } var tr = FileList.findFileEl(filename); var itemType = 'file'; if ($(tr).data('type') == 'dir') { diff --git a/apps/files_sharing/l10n/ast.php b/apps/files_sharing/l10n/ast.php new file mode 100644 index 00000000000..02a2f6fb628 --- /dev/null +++ b/apps/files_sharing/l10n/ast.php @@ -0,0 +1,6 @@ + "Compartíu por {owner}", +"Password" => "Contraseña" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files_sharing/l10n/et_EE.php b/apps/files_sharing/l10n/et_EE.php index af5891fcc7f..7150f05da22 100644 --- a/apps/files_sharing/l10n/et_EE.php +++ b/apps/files_sharing/l10n/et_EE.php @@ -11,6 +11,7 @@ $TRANSLATIONS = array( "sharing is disabled" => "jagamine on peatatud", "For more info, please ask the person who sent this link." => "Täpsema info saamiseks palun pöördu lingi saatnud isiku poole.", "shared by %s" => "jagas %s", +"Download %s" => "Laadi alla %s", "Direct link" => "Otsene link" ); $PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files_sharing/l10n/sk_SK.php b/apps/files_sharing/l10n/sk_SK.php index 4e9856da4a7..6856c0591f4 100644 --- a/apps/files_sharing/l10n/sk_SK.php +++ b/apps/files_sharing/l10n/sk_SK.php @@ -11,6 +11,7 @@ $TRANSLATIONS = array( "sharing is disabled" => "zdieľanie je zakázané", "For more info, please ask the person who sent this link." => "Pre viac informácií kontaktujte osobu, ktorá vám poslala tento odkaz.", "shared by %s" => "Zdieľa %s", +"Download %s" => "Stiahnuť %s", "Direct link" => "Priama linka" ); $PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/apps/files_sharing/l10n/sv.php b/apps/files_sharing/l10n/sv.php index 2d037f9186e..94b7edf6977 100644 --- a/apps/files_sharing/l10n/sv.php +++ b/apps/files_sharing/l10n/sv.php @@ -10,6 +10,8 @@ $TRANSLATIONS = array( "the link expired" => "giltighet för länken har gått ut", "sharing is disabled" => "delning är inaktiverat", "For more info, please ask the person who sent this link." => "För mer information, kontakta den person som skickade den här länken.", +"shared by %s" => "delad av %s", +"Download %s" => "Ladda ner %s", "Direct link" => "Direkt länk" ); $PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 01db29d72e2..eeb62c3cce2 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -20,6 +20,7 @@ */ namespace OC\Files\Cache; + use OCP\Share_Backend_Collection; /** @@ -50,7 +51,7 @@ class Shared_Cache extends Cache { \OC\Files\Filesystem::initMountPoints($source['fileOwner']); $mount = \OC\Files\Filesystem::getMountByNumericId($source['storage']); if (is_array($mount)) { - $fullPath = $mount[key($mount)]->getMountPoint().$source['path']; + $fullPath = $mount[key($mount)]->getMountPoint() . $source['path']; list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($fullPath); if ($storage) { $this->files[$target] = $internalPath; @@ -75,7 +76,7 @@ class Shared_Cache extends Cache { /** * get the stored metadata of a file or folder * - * @param string/int $file + * @param string /int $file * @return array */ public function get($file) { @@ -95,8 +96,8 @@ class Shared_Cache extends Cache { } else { $query = \OC_DB::prepare( 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,' - .' `size`, `mtime`, `encrypted`, `unencrypted_size`' - .' FROM `*PREFIX*filecache` WHERE `fileid` = ?'); + . ' `size`, `mtime`, `encrypted`, `unencrypted_size`' + . ' FROM `*PREFIX*filecache` WHERE `fileid` = ?'); $result = $query->execute(array($file)); $data = $result->fetchRow(); $data['fileid'] = (int)$data['fileid']; @@ -288,8 +289,7 @@ class Shared_Cache extends Cache { foreach ($files as $file) { if ($file['mimetype'] === 'httpd/unix-directory') { $exploreDirs[] = ltrim($dir . '/' . $file['name'], '/'); - } - else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) { + } else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) { // usersPath not reliable //$file['path'] = $file['usersPath']; $file['path'] = ltrim($dir . '/' . $file['name'], '/'); @@ -344,8 +344,6 @@ class Shared_Cache extends Cache { if ($row['encrypted'] or ($row['unencrypted_size'] > 0 and $row['mimetype'] === 'httpd/unix-directory')) { $row['encrypted_size'] = $row['size']; $row['size'] = $row['unencrypted_size']; - } else { - $row['size'] = $row['size']; } $files[] = $row; } @@ -402,4 +400,48 @@ class Shared_Cache extends Cache { return false; } + /** + * get the path of a file on this storage by it's id + * + * @param int $id + * @param string $pathEnd (optional) used internally for recursive calls + * @return string | null + */ + public function getPathById($id, $pathEnd = '') { + // direct shares are easy + if ($path = $this->getShareById($id)) { + return $path . $pathEnd; + } else { + // if the item is a direct share we try and get the path of the parent and append the name of the item to it + list($parent, $name) = $this->getParentInfo($id); + if ($parent > 0) { + return $this->getPathById($parent, '/' . $name . $pathEnd); + } else { + return null; + } + } + } + + private function getShareById($id) { + $item = \OCP\Share::getItemSharedWithBySource('file', $id); + if ($item) { + return trim($item['file_target'], '/'); + } + $item = \OCP\Share::getItemSharedWithBySource('folder', $id); + if ($item) { + return trim($item['file_target'], '/'); + } + return null; + } + + private function getParentInfo($id) { + $sql = 'SELECT `parent`, `name` FROM `*PREFIX*filecache` WHERE `fileid` = ?'; + $query = \OC_DB::prepare($sql); + $result = $query->execute(array($id)); + if ($row = $result->fetchRow()) { + return array($row['parent'], $row['name']); + } else { + return array(-1, ''); + } + } } diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php new file mode 100644 index 00000000000..b602fe3599d --- /dev/null +++ b/apps/files_sharing/lib/helper.php @@ -0,0 +1,114 @@ + false)); + exit(); + } + + if (!isset($linkItem['item_type'])) { + \OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR); + \OC_Response::setStatus(404); + \OCP\JSON::error(array('success' => false)); + exit(); + } + + if (isset($linkItem['share_with'])) { + if (!self::authenticate($linkItem, $password)) { + \OC_Response::setStatus(403); + \OCP\JSON::error(array('success' => false)); + exit(); + } + } + + $basePath = $path; + $rootName = basename($path); + + if ($relativePath !== null && \OC\Files\Filesystem::isReadable($basePath . $relativePath)) { + $path .= \OC\Files\Filesystem::normalizePath($relativePath); + } + + return array( + 'linkItem' => $linkItem, + 'basePath' => $basePath, + 'realPath' => $path + ); + } + + /** + * Authenticate link item with the given password + * or with the session if no password was given. + * @param array $linkItem link item array + * @param string $password optional password + * + * @return true if authorized, false otherwise + */ + public static function authenticate($linkItem, $password) { + if ($password !== null) { + if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_LINK) { + // Check Password + $forcePortable = (CRYPT_BLOWFISH != 1); + $hasher = new PasswordHash(8, $forcePortable); + if (!($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''), + $linkItem['share_with']))) { + return false; + } else { + // Save item id in session for future requests + \OC::$session->set('public_link_authenticated', $linkItem['id']); + } + } else { + \OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type'] + .' for share id '.$linkItem['id'], \OCP\Util::ERROR); + return false; + } + + } + else { + // not authenticated ? + if ( ! \OC::$session->exists('public_link_authenticated') + || \OC::$session->get('public_link_authenticated') !== $linkItem['id']) { + return false; + } + } + return true; + } +} diff --git a/apps/files_sharing/lib/updater.php b/apps/files_sharing/lib/updater.php index 23ebc9fb811..e3a7679292d 100644 --- a/apps/files_sharing/lib/updater.php +++ b/apps/files_sharing/lib/updater.php @@ -135,4 +135,19 @@ class Shared_Updater { } } + /** + * clean up oc_share table from files which are no longer exists + * + * This fixes issues from updates from files_sharing < 0.3.5.6 (ownCloud 4.5) + * It will just be called during the update of the app + */ + static public function fixBrokenSharesOnAppUpdate() { + // delete all shares where the original file no longer exists + $findAndRemoveShares = \OC_DB::prepare('DELETE FROM `*PREFIX*share` ' . + 'WHERE `file_source` NOT IN ( ' . + 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `item_type` IN (\'file\', \'folder\'))' + ); + $findAndRemoveShares->execute(array()); + } + } diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index fe61dd4d5a0..ce51eca6ddb 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -11,31 +11,6 @@ if ($appConfig->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') { exit(); } -function fileCmp($a, $b) { - if ($a['type'] == 'dir' and $b['type'] != 'dir') { - return -1; - } elseif ($a['type'] != 'dir' and $b['type'] == 'dir') { - return 1; - } else { - return strnatcasecmp($a['name'], $b['name']); - } -} - -function determineIcon($file, $sharingRoot, $sharingToken) { - // for folders we simply reuse the files logic - if($file['type'] == 'dir') { - return \OCA\Files\Helper::determineIcon($file); - } - - $relativePath = substr($file['path'], 6); - $relativePath = substr($relativePath, strlen($sharingRoot)); - if($file['isPreviewAvailable']) { - return OCP\publicPreview_icon($relativePath, $sharingToken) . '&c=' . $file['etag']; - } - $icon = OCP\mimetype_icon($file['mimetype']); - return substr($icon, 0, -3) . 'svg'; -} - if (isset($_GET['t'])) { $token = $_GET['t']; $linkItem = OCP\Share::getShareByToken($token, false); @@ -153,13 +128,6 @@ if (isset($path)) { $tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path)); $tmpl->assign('dirToken', $linkItem['token']); $tmpl->assign('sharingToken', $token); - $allowPublicUploadEnabled = (bool) ($linkItem['permissions'] & OCP\PERMISSION_CREATE); - if ($appConfig->getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') { - $allowPublicUploadEnabled = false; - } - if ($linkItem['item_type'] !== 'folder') { - $allowPublicUploadEnabled = false; - } $urlLinkIdentifiers= (isset($token)?'&t='.$token:'') .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'') @@ -170,64 +138,18 @@ if (isset($path)) { OCP\Util::addStyle('files', 'files'); OCP\Util::addStyle('files', 'upload'); + OCP\Util::addScript('files', 'breadcrumb'); OCP\Util::addScript('files', 'files'); OCP\Util::addScript('files', 'filelist'); OCP\Util::addscript('files', 'keyboardshortcuts'); $files = array(); $rootLength = strlen($basePath) + 1; - $totalSize = 0; - foreach (\OC\Files\Filesystem::getDirectoryContent($path) as $i) { - $totalSize += $i['size']; - $i['date'] = OCP\Util::formatDate($i['mtime']); - if ($i['type'] == 'file') { - $fileinfo = pathinfo($i['name']); - $i['basename'] = $fileinfo['filename']; - if (!empty($fileinfo['extension'])) { - $i['extension'] = '.' . $fileinfo['extension']; - } else { - $i['extension'] = ''; - } - } - $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']); - $i['directory'] = $getPath; - $i['permissions'] = OCP\PERMISSION_READ; - $i['icon'] = determineIcon($i, $basePath, $token); - $files[] = $i; - } - usort($files, "fileCmp"); - - // Make breadcrumb - $breadcrumb = array(); - $pathtohere = ''; - foreach (explode('/', $getPath) as $i) { - if ($i != '') { - $pathtohere .= '/' . $i; - $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i); - } - } - $list = new OCP\Template('files', 'part.list', ''); - $list->assign('files', $files); - $list->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path='); - $list->assign('downloadURL', - OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path='); - $list->assign('isPublic', true); - $list->assign('sharingtoken', $token); - $list->assign('sharingroot', $basePath); - $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); - $breadcrumbNav->assign('breadcrumb', $breadcrumb); - $breadcrumbNav->assign('rootBreadCrumb', $rootName); - $breadcrumbNav->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path='); $maxUploadFilesize=OCP\Util::maxUploadFilesize($path); - $fileHeader = (!isset($files) or count($files) > 0); - $emptyContent = ($allowPublicUploadEnabled and !$fileHeader); $freeSpace=OCP\Util::freeSpace($path); $uploadLimit=OCP\Util::uploadLimit(); $folder = new OCP\Template('files', 'index', ''); - $folder->assign('fileList', $list->fetchPage()); - $folder->assign('breadcrumb', $breadcrumbNav->fetchPage()); $folder->assign('dir', $getPath); - $folder->assign('isCreatable', $allowPublicUploadEnabled); $folder->assign('dirToken', $linkItem['token']); $folder->assign('permissions', OCP\PERMISSION_READ); $folder->assign('isPublic',true); @@ -239,15 +161,11 @@ if (isset($path)) { $folder->assign('uploadLimit', $uploadLimit); // PHP upload limit $folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); $folder->assign('usedSpacePercent', 0); - $folder->assign('fileHeader', $fileHeader); $folder->assign('disableSharing', true); $folder->assign('trash', false); - $folder->assign('emptyContent', $emptyContent); - $folder->assign('ajaxLoad', false); $tmpl->assign('folder', $folder->fetchPage()); $maxInputFileSize = OCP\Config::getSystemValue('maxZipInputSize', OCP\Util::computerFileSize('800 MB')); - $allowZip = OCP\Config::getSystemValue('allowZipDownload', true) - && ( $maxInputFileSize === 0 || $totalSize <= $maxInputFileSize); + $allowZip = OCP\Config::getSystemValue('allowZipDownload', true); $tmpl->assign('allowZipDownload', intval($allowZip)); $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=' . urlencode($getPath)); diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php index e2bbb548182..c7a848315ac 100644 --- a/apps/files_sharing/tests/api.php +++ b/apps/files_sharing/tests/api.php @@ -878,6 +878,29 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base { $this->assertSame($expectedResult, $shareApiDummy->correctPathTest($path, $folder)); } + /** + * @expectedException \Exception + */ + public function testShareNonExisting() { + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); + + $id = PHP_INT_MAX - 1; + \OCP\Share::shareItem('file', $id, \OCP\Share::SHARE_TYPE_LINK, \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + } + + /** + * @expectedException \Exception + */ + public function testShareNotOwner() { + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + \OC\Files\Filesystem::file_put_contents('foo.txt', 'bar'); + $info = \OC\Files\Filesystem::getFileInfo('foo.txt'); + + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); + + \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_LINK, \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + } + } /** @@ -886,5 +909,5 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base { class TestShareApi extends \OCA\Files\Share\Api { public function correctPathTest($path, $folder) { return self::correctPath($path, $folder); -} + } } diff --git a/apps/files_sharing/tests/cache.php b/apps/files_sharing/tests/cache.php index a75e1860527..47969833ab5 100644 --- a/apps/files_sharing/tests/cache.php +++ b/apps/files_sharing/tests/cache.php @@ -246,4 +246,43 @@ class Test_Files_Sharing_Cache extends Test_Files_Sharing_Base { } } + public function testGetPathByIdDirectShare() { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + \OC\Files\Filesystem::file_put_contents('test.txt', 'foo'); + $info = \OC\Files\Filesystem::getFileInfo('test.txt'); + \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL); + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/test.txt')); + list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/Shared/test.txt'); + /** + * @var \OC\Files\Storage\Shared $sharedStorage + */ + + $sharedCache = $sharedStorage->getCache(); + $this->assertEquals('test.txt', $sharedCache->getPathById($info->getId())); + } + + public function testGetPathByIdShareSubFolder() { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + \OC\Files\Filesystem::mkdir('foo'); + \OC\Files\Filesystem::mkdir('foo/bar'); + \OC\Files\Filesystem::touch('foo/bar/test.txt', 'bar'); + $folderInfo = \OC\Files\Filesystem::getFileInfo('foo'); + $fileInfo = \OC\Files\Filesystem::getFileInfo('foo/bar/test.txt'); + \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL); + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/foo')); + list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/Shared/foo'); + /** + * @var \OC\Files\Storage\Shared $sharedStorage + */ + + $sharedCache = $sharedStorage->getCache(); + $this->assertEquals('foo', $sharedCache->getPathById($folderInfo->getId())); + $this->assertEquals('foo/bar/test.txt', $sharedCache->getPathById($fileInfo->getId())); + } } diff --git a/apps/files_sharing/tests/updater.php b/apps/files_sharing/tests/updater.php new file mode 100644 index 00000000000..79ae4879b64 --- /dev/null +++ b/apps/files_sharing/tests/updater.php @@ -0,0 +1,91 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +/** + * Class Test_Files_Sharing_Updater + */ +class Test_Files_Sharing_Updater extends \PHPUnit_Framework_TestCase { + + function setUp() { + // some previous tests didn't clean up and therefore this has to be done here + // FIXME: DIRTY HACK - TODO: find tests, that don't clean up and fix it there + $this->tearDown(); + + // add items except one - because this is the test case for the broken share table + $addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` (`storage`, `path_hash`, ' . + '`parent`, `mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`) ' . + 'VALUES (1, ?, 1, 1, 1, 1, 1, 1)'); + $items = array(1, 3); + $fileIds = array(); + foreach($items as $item) { + // the number is used as path_hash + $addItems->execute(array($item)); + $fileIds[] = \OC_DB::insertId('*PREFIX*filecache'); + } + + $addShares = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`file_source`, `item_type`, `uid_owner`) VALUES (?, \'file\', 1)'); + // the number is used as item_source + $addShares->execute(array($fileIds[0])); + $addShares->execute(array(200)); // id of "deleted" file + $addShares->execute(array($fileIds[1])); + } + + function tearDown() { + $removeShares = \OC_DB::prepare('DELETE FROM `*PREFIX*share`'); + $removeShares->execute(); + $removeItems = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache`'); + $removeItems->execute(); + } + + /** + * @medium + */ + function testRemoveBrokenShares() { + // check if there are just 3 shares (see setUp - precondition: empty table) + $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`'); + $result = $countShares->execute()->fetchOne(); + $this->assertEquals(3, $result); + + // check if there are just 2 items (see setUp - precondition: empty table) + $countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`'); + $result = $countItems->execute()->fetchOne(); + $this->assertEquals(2, $result); + + // execute actual code which should be tested + \OC\Files\Cache\Shared_Updater::fixBrokenSharesOnAppUpdate(); + + // check if there are just 2 shares (one gets killed by the code as there is no filecache entry for this) + $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`'); + $result = $countShares->execute()->fetchOne(); + $this->assertEquals(2, $result); + + // check if the share of file '200' is removed as there is no entry for this in filecache table + $countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share` WHERE `file_source` = 200'); + $result = $countShares->execute()->fetchOne(); + $this->assertEquals(0, $result); + + // check if there are just 2 items + $countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`'); + $result = $countItems->execute()->fetchOne(); + $this->assertEquals(2, $result); + } +} diff --git a/apps/files_trashbin/ajax/list.php b/apps/files_trashbin/ajax/list.php index 124a236bcbd..89a55114524 100644 --- a/apps/files_trashbin/ajax/list.php +++ b/apps/files_trashbin/ajax/list.php @@ -1,30 +1,11 @@ assign('breadcrumb', $breadcrumb, false); - $breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php') . '?dir='); - $breadcrumbNav->assign('home', OCP\Util::linkTo('files', 'index.php')); - - $data['breadcrumb'] = $breadcrumbNav->fetchPage(); -} - // make filelist try { $files = \OCA\Files_Trashbin\Helper::getTrashFiles($dir); @@ -33,19 +14,11 @@ try { exit(); } -$dirlisting = false; -if ($dir && $dir !== '/') { - $dirlisting = true; -} - $encodedDir = \OCP\Util::encodePath($dir); -$list = new OCP\Template('files_trashbin', 'part.list', ''); -$list->assign('files', $files, false); -$list->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php'). '?dir='.$encodedDir); -$list->assign('downloadURL', OCP\Util::linkToRoute('download', array('file' => '/'))); -$list->assign('dirlisting', $dirlisting); -$list->assign('disableDownloadActions', true); -$data['files'] = $list->fetchPage(); + +$data['permissions'] = 0; +$data['directory'] = $dir; +$data['files'] = \OCA\Files_Trashbin\Helper::formatFileInfos($files); OCP\JSON::success(array('data' => $data)); diff --git a/apps/files_trashbin/ajax/preview.php b/apps/files_trashbin/ajax/preview.php index ce64d9ecc9f..32905b2a71c 100644 --- a/apps/files_trashbin/ajax/preview.php +++ b/apps/files_trashbin/ajax/preview.php @@ -34,7 +34,7 @@ try{ if ($view->is_dir($file)) { $mimetype = 'httpd/unix-directory'; } else { - $pathInfo = pathinfo($file); + $pathInfo = pathinfo(ltrim($file, '/')); $fileName = $pathInfo['basename']; // if in root dir if ($pathInfo['dirname'] === '.') { diff --git a/apps/files_trashbin/ajax/undelete.php b/apps/files_trashbin/ajax/undelete.php index 9c3ccba7ed8..2b00078669e 100644 --- a/apps/files_trashbin/ajax/undelete.php +++ b/apps/files_trashbin/ajax/undelete.php @@ -19,7 +19,7 @@ if (isset($_POST['allfiles']) and $_POST['allfiles'] === 'true') { foreach (OCA\Files_Trashbin\Helper::getTrashFiles($dir) as $file) { $fileName = $file['name']; if (!$dirListing) { - $fileName .= '.d' . $file['timestamp']; + $fileName .= '.d' . $file['mtime']; } $list[] = $fileName; } diff --git a/apps/files_trashbin/css/trash.css b/apps/files_trashbin/css/trash.css index 97819f4e80b..7ca3e355fc2 100644 --- a/apps/files_trashbin/css/trash.css +++ b/apps/files_trashbin/css/trash.css @@ -1,3 +1,4 @@ -#fileList td a.file, #fileList td a.file span { +#fileList tr[data-type="file"] td a.name, +#fileList tr[data-type="file"] td a.name span { cursor: default; } diff --git a/apps/files_trashbin/index.php b/apps/files_trashbin/index.php index f0c5b0508b8..e63fe1e4188 100644 --- a/apps/files_trashbin/index.php +++ b/apps/files_trashbin/index.php @@ -11,6 +11,7 @@ $tmpl = new OCP\Template('files_trashbin', 'index', 'user'); OCP\Util::addStyle('files', 'files'); OCP\Util::addStyle('files_trashbin', 'trash'); +OCP\Util::addScript('files', 'breadcrumb'); OCP\Util::addScript('files', 'filelist'); // filelist overrides OCP\Util::addScript('files_trashbin', 'filelist'); @@ -34,48 +35,7 @@ if ($isIE8 && isset($_GET['dir'])){ exit(); } -$ajaxLoad = false; - -if (!$isIE8){ - try { - $files = \OCA\Files_Trashbin\Helper::getTrashFiles($dir); - } catch (Exception $e) { - header('Location: ' . OCP\Util::linkTo('files_trashbin', 'index.php')); - exit(); - } -} -else{ - $files = array(); - $ajaxLoad = true; -} - -$dirlisting = false; -if ($dir && $dir !== '/') { - $dirlisting = true; -} - -$breadcrumb = \OCA\Files_Trashbin\Helper::makeBreadcrumb($dir); - -$breadcrumbNav = new OCP\Template('files_trashbin', 'part.breadcrumb', ''); -$breadcrumbNav->assign('breadcrumb', $breadcrumb); -$breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php') . '?dir='); -$breadcrumbNav->assign('home', OCP\Util::linkTo('files', 'index.php')); - -$list = new OCP\Template('files_trashbin', 'part.list', ''); -$list->assign('files', $files); - -$encodedDir = \OCP\Util::encodePath($dir); -$list->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php'). '?dir='.$encodedDir); -$list->assign('downloadURL', OCP\Util::linkTo('files_trashbin', 'download.php') . '?file='.$encodedDir); -$list->assign('dirlisting', $dirlisting); -$list->assign('disableDownloadActions', true); - -$tmpl->assign('dirlisting', $dirlisting); -$tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage()); -$tmpl->assign('fileList', $list->fetchPage()); -$tmpl->assign('files', $files); $tmpl->assign('dir', $dir); $tmpl->assign('disableSharing', true); -$tmpl->assign('ajaxLoad', true); $tmpl->printPage(); diff --git a/apps/files_trashbin/js/disableDefaultActions.js b/apps/files_trashbin/js/disableDefaultActions.js index afa80cacd6b..50ceaf4696f 100644 --- a/apps/files_trashbin/js/disableDefaultActions.js +++ b/apps/files_trashbin/js/disableDefaultActions.js @@ -1,4 +1,3 @@ /* disable download and sharing actions */ var disableDownloadActions = true; -var disableSharing = true; var trashBinApp = true; diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js index a88459b0a9a..7795daf2775 100644 --- a/apps/files_trashbin/js/filelist.js +++ b/apps/files_trashbin/js/filelist.js @@ -1,61 +1,78 @@ -/* globals OC, FileList, t */ -// override reload with own ajax call -FileList.reload = function(){ - FileList.showMask(); - if (FileList._reloadCall){ - FileList._reloadCall.abort(); - } - $.ajax({ - url: OC.filePath('files_trashbin','ajax','list.php'), - data: { - dir : $('#dir').val(), - breadcrumb: true - }, - error: function(result) { - FileList.reloadCallback(result); - }, - success: function(result) { - FileList.reloadCallback(result); +/* global OC, t, FileList */ +(function() { + FileList.appName = t('files_trashbin', 'Deleted files'); + + FileList._deletedRegExp = new RegExp(/^(.+)\.d[0-9]+$/); + + /** + * Convert a file name in the format filename.d12345 to the real file name. + * This will use basename. + * The name will not be changed if it has no ".d12345" suffix. + * @param name file name + * @return converted file name + */ + FileList.getDeletedFileName = function(name) { + name = OC.basename(name); + var match = FileList._deletedRegExp.exec(name); + if (match && match.length > 1) { + name = match[1]; } - }); -}; - -FileList.appName = t('files_trashbin', 'Deleted files'); - -FileList._deletedRegExp = new RegExp(/^(.+)\.d[0-9]+$/); - -/** - * Convert a file name in the format filename.d12345 to the real file name. - * This will use basename. - * The name will not be changed if it has no ".d12345" suffix. - * @param name file name - * @return converted file name - */ -FileList.getDeletedFileName = function(name) { - name = OC.basename(name); - var match = FileList._deletedRegExp.exec(name); - if (match && match.length > 1) { - name = match[1]; - } - return name; -}; -var oldSetCurrentDir = FileList.setCurrentDir; -FileList.setCurrentDir = function(targetDir) { - oldSetCurrentDir.apply(this, arguments); - - var baseDir = OC.basename(targetDir); - if (baseDir !== '') { - FileList.setPageTitle(FileList.getDeletedFileName(baseDir)); - } -}; - -FileList.linkTo = function(dir){ - return OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); -} - -FileList.updateEmptyContent = function(){ - var $fileList = $('#fileList'); - var exists = $fileList.find('tr:first').exists(); - $('#emptycontent').toggleClass('hidden', exists); - $('#filestable th').toggleClass('hidden', !exists); -} + return name; + }; + + var oldSetCurrentDir = FileList._setCurrentDir; + FileList._setCurrentDir = function(targetDir) { + oldSetCurrentDir.apply(this, arguments); + + var baseDir = OC.basename(targetDir); + if (baseDir !== '') { + FileList.setPageTitle(FileList.getDeletedFileName(baseDir)); + } + }; + + var oldCreateRow = FileList._createRow; + FileList._createRow = function() { + // FIXME: MEGAHACK until we find a better solution + var tr = oldCreateRow.apply(this, arguments); + tr.find('td.filesize').remove(); + return tr; + }; + + FileList._onClickBreadCrumb = function(e) { + var $el = $(e.target).closest('.crumb'), + index = $el.index(), + $targetDir = $el.data('dir'); + // first one is home, let the link makes it default action + if (index !== 0) { + e.preventDefault(); + FileList.changeDirectory($targetDir); + } + }; + + var oldAdd = FileList.add; + FileList.add = function(fileData, options) { + options = options || {}; + var dir = FileList.getCurrentDirectory(); + var dirListing = dir !== '' && dir !== '/'; + // show deleted time as mtime + if (fileData.mtime) { + fileData.mtime = parseInt(fileData.mtime, 10); + } + if (!dirListing) { + fileData.displayName = fileData.name; + fileData.name = fileData.name + '.d' + Math.floor(fileData.mtime / 1000); + } + return oldAdd.call(this, fileData, options); + }; + + FileList.linkTo = function(dir){ + return OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); + }; + + FileList.updateEmptyContent = function(){ + var $fileList = $('#fileList'); + var exists = $fileList.find('tr:first').exists(); + $('#emptycontent').toggleClass('hidden', exists); + $('#filestable th').toggleClass('hidden', !exists); + }; +})(); diff --git a/apps/files_trashbin/js/trash.js b/apps/files_trashbin/js/trash.js index 6aade210505..5cd49e19aaa 100644 --- a/apps/files_trashbin/js/trash.js +++ b/apps/files_trashbin/js/trash.js @@ -8,9 +8,26 @@ * */ -/* global OC, t, FileList, FileActions */ - +/* global OC, t, BreadCrumb, FileActions, FileList, Files */ $(document).ready(function() { + var deletedRegExp = new RegExp(/^(.+)\.d[0-9]+$/); + + /** + * Convert a file name in the format filename.d12345 to the real file name. + * This will use basename. + * The name will not be changed if it has no ".d12345" suffix. + * @param name file name + * @return converted file name + */ + function getDeletedFileName(name) { + name = OC.basename(name); + var match = deletedRegExp.exec(name); + if (match && match.length > 1) { + name = match[1]; + } + return name; + } + function removeCallback(result) { if (result.status !== 'success') { OC.dialogs.alert(result.data.message, t('core', 'Error')); @@ -18,13 +35,18 @@ $(document).ready(function() { var files = result.data.success; for (var i = 0; i < files.length; i++) { - FileList.findFileEl(OC.basename(files[i].filename)).remove(); + FileList.remove(OC.basename(files[i].filename), {updateSummary: false}); } FileList.updateFileSummary(); FileList.updateEmptyContent(); enableActions(); } + Files.updateStorageStatistics = function() { + // no op because the trashbin doesn't have + // storage info like free space / used space + }; + if (typeof FileActions !== 'undefined') { FileActions.register('all', 'Restore', OC.PERMISSION_READ, OC.imagePath('core', 'actions/history'), function(filename) { var tr = FileList.findFileEl(filename); @@ -69,7 +91,6 @@ $(document).ready(function() { } procesSelection(); }); - $('.undelete').click('click', function(event) { event.preventDefault(); var allFiles = $('#select_all').is(':checked'); @@ -84,7 +105,7 @@ $(document).ready(function() { }; } else { - files = getSelectedFiles('name'); + files = Files.getSelectedFiles('name'); for (var i = 0; i < files.length; i++) { var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete"); deleteAction.removeClass('delete-icon').addClass('progress-icon'); @@ -126,7 +147,7 @@ $(document).ready(function() { }; } else { - files = getSelectedFiles('name'); + files = Files.getSelectedFiles('name'); params = { files: JSON.stringify(files), dir: FileList.getCurrentDirectory() @@ -153,7 +174,7 @@ $(document).ready(function() { } FileList.hideMask(); // simply remove all files - FileList.update(''); + FileList.setFiles([]); enableActions(); } else { @@ -186,7 +207,7 @@ $(document).ready(function() { var filename = $(this).parent().parent().attr('data-file'); var tr = FileList.findFileEl(filename); var renaming = tr.data('renaming'); - if(!renaming && !FileList.isLoading(filename)){ + if(!renaming){ if(mime.substr(0, 5) === 'text/'){ //no texteditor for now return; } @@ -198,47 +219,61 @@ $(document).ready(function() { action(filename); } } - - // event handlers for breadcrumb items - $('#controls').delegate('.crumb:not(.home) a', 'click', onClickBreadcrumb); }); - FileActions.actions.dir = { - // only keep 'Open' action for navigation - 'Open': FileActions.actions.dir.Open + /** + * Override crumb URL maker (hacky!) + */ + FileList.breadcrumb.getCrumbUrl = function(part, index) { + if (index === 0) { + return OC.linkTo('files', 'index.php'); + } + return OC.linkTo('files_trashbin', 'index.php')+"?dir=" + encodeURIComponent(part.dir); }; -}); -/** - * @brief get a list of selected files - * @param string property (option) the property of the file requested - * @return array - * - * possible values for property: name, mime, size and type - * if property is set, an array with that property for each file is returnd - * if it's ommited an array of objects with all properties is returned - */ -function getSelectedFiles(property){ - var elements=$('td.filename input:checkbox:checked').parent().parent(); - var files=[]; - elements.each(function(i,element){ - var file={ - name:$(element).attr('data-file'), - timestamp:$(element).attr('data-timestamp'), - type:$(element).attr('data-type') + Files.generatePreviewUrl = function(urlSpec) { + return OC.generateUrl('/apps/files_trashbin/ajax/preview.php?') + $.param(urlSpec); + }; + + Files.getDownloadUrl = function(action, params) { + // no downloads + return '#'; + }; + + Files.getAjaxUrl = function(action, params) { + var q = ''; + if (params) { + q = '?' + OC.buildQueryString(params); + } + return OC.filePath('files_trashbin', 'ajax', action + '.php') + q; + }; + + + /** + * Override crumb making to add "Deleted Files" entry + * and convert files with ".d" extensions to a more + * user friendly name. + */ + var oldMakeCrumbs = BreadCrumb.prototype._makeCrumbs; + BreadCrumb.prototype._makeCrumbs = function() { + var parts = oldMakeCrumbs.apply(this, arguments); + // duplicate first part + parts.unshift(parts[0]); + parts[1] = { + dir: '/', + name: t('files_trashbin', 'Deleted Files') }; - if(property){ - files.push(file[property]); - }else{ - files.push(file); + for (var i = 2; i < parts.length; i++) { + parts[i].name = getDeletedFileName(parts[i].name); } - }); - return files; -} + return parts; + }; -function fileDownloadPath(dir, file) { - return OC.filePath('files_trashbin', '', 'download.php') + '?file='+encodeURIComponent(file); -} + FileActions.actions.dir = { + // only keep 'Open' action for navigation + 'Open': FileActions.actions.dir.Open + }; +}); function enableActions() { $(".action").css("display", "inline"); diff --git a/apps/files_trashbin/l10n/ar.php b/apps/files_trashbin/l10n/ar.php index 68c51d1cc7d..4084daa127a 100644 --- a/apps/files_trashbin/l10n/ar.php +++ b/apps/files_trashbin/l10n/ar.php @@ -4,6 +4,7 @@ $TRANSLATIONS = array( "Couldn't restore %s" => "تعذّر استرجاع %s ", "Deleted files" => "حذف الملفات", "Error" => "خطأ", +"restored" => "تمت الاستعادة", "Nothing in here. Your trash bin is empty!" => "لا يوجد شيء هنا. سلة المهملات خاليه.", "Name" => "اسم", "Restore" => "استعيد", diff --git a/apps/files_trashbin/l10n/ast.php b/apps/files_trashbin/l10n/ast.php new file mode 100644 index 00000000000..91c122bd4d3 --- /dev/null +++ b/apps/files_trashbin/l10n/ast.php @@ -0,0 +1,8 @@ + "Fallu", +"Name" => "Nome", +"Restore" => "Restaurar", +"Delete" => "Desaniciar" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files_trashbin/l10n/tr.php b/apps/files_trashbin/l10n/tr.php index c1234cdfb0c..ff4227e38c7 100644 --- a/apps/files_trashbin/l10n/tr.php +++ b/apps/files_trashbin/l10n/tr.php @@ -1,15 +1,15 @@ "%s alıcı olarak silinemedi", -"Couldn't restore %s" => "%s eri yüklenemedi", +"Couldn't restore %s" => "%s geri yüklenemedi", "Deleted files" => "Silinmiş dosyalar", "Error" => "Hata", +"Deleted Files" => "Silinen Dosyalar", "restored" => "geri yüklendi", "Nothing in here. Your trash bin is empty!" => "Burada hiçbir şey yok. Çöp kutunuz tamamen boş!", "Name" => "İsim", "Restore" => "Geri yükle", "Deleted" => "Silindi", -"Delete" => "Sil", -"Deleted Files" => "Silinen Dosyalar" +"Delete" => "Sil" ); $PLURAL_FORMS = "nplurals=2; plural=(n > 1);"; diff --git a/apps/files_trashbin/lib/helper.php b/apps/files_trashbin/lib/helper.php index 9c24332a964..e6ca73520a6 100644 --- a/apps/files_trashbin/lib/helper.php +++ b/apps/files_trashbin/lib/helper.php @@ -27,6 +27,10 @@ class Helper if ($dirContent === false) { return $result; } + + list($storage, $internalPath) = $view->resolvePath($dir); + $absoluteDir = $view->getAbsolutePath($dir); + if (is_resource($dirContent)) { while (($entryName = readdir($dirContent)) !== false) { if (!\OC\Files\Filesystem::isIgnoredDir($entryName)) { @@ -40,76 +44,41 @@ class Helper $parts = explode('/', ltrim($dir, '/')); $timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1); } - $result[] = array( - 'id' => $id, - 'timestamp' => $timestamp, - 'mime' => \OC_Helper::getFileNameMimeType($id), + $i = array( + 'name' => $id, + 'mtime' => $timestamp, + 'mimetype' => \OC_Helper::getFileNameMimeType($id), 'type' => $view->is_dir($dir . '/' . $entryName) ? 'dir' : 'file', - 'location' => $dir, + 'directory' => ($dir === '/') ? '' : $dir, ); + $result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i); } } closedir($dirContent); } - $files = array(); - $id = 0; - list($storage, $internalPath) = $view->resolvePath($dir); - $absoluteDir = $view->getAbsolutePath($dir); - foreach ($result as $r) { - $i = array(); - $i['id'] = $id++; - $i['name'] = $r['id']; - $i['date'] = \OCP\Util::formatDate($r['timestamp']); - $i['timestamp'] = $r['timestamp']; - $i['etag'] = $r['timestamp']; // add fake etag, it is only needed to identify the preview image - $i['mimetype'] = $r['mime']; - $i['type'] = $r['type']; - if ($i['type'] === 'file') { - $fileinfo = pathinfo($r['id']); - $i['basename'] = $fileinfo['filename']; - $i['extension'] = isset($fileinfo['extension']) ? ('.'.$fileinfo['extension']) : ''; - } - $i['directory'] = $r['location']; - if ($i['directory'] === '/') { - $i['directory'] = ''; - } - $i['permissions'] = \OCP\PERMISSION_READ; - if (\OCP\App::isEnabled('files_encryption')) { - $i['isPreviewAvailable'] = false; - } else { - $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($r['mime']); - } - $i['icon'] = \OCA\Files\Helper::determineIcon($i); - $files[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i); - } - - usort($files, array('\OCA\Files\Helper', 'fileCmp')); + usort($result, array('\OCA\Files\Helper', 'fileCmp')); - return $files; + return $result; } /** - * Splits the given path into a breadcrumb structure. - * @param string $dir path to process - * @return array where each entry is a hash of the absolute - * directory path and its name + * Format file infos for JSON + * @param \OCP\Files\FileInfo[] $fileInfos file infos */ - public static function makeBreadcrumb($dir){ - // Make breadcrumb - $pathtohere = ''; - $breadcrumb = array(); - foreach (explode('/', $dir) as $i) { - if ($i !== '') { - if ( preg_match('/^(.+)\.d[0-9]+$/', $i, $match) ) { - $name = $match[1]; - } else { - $name = $i; - } - $pathtohere .= '/' . $i; - $breadcrumb[] = array('dir' => $pathtohere, 'name' => $name); + public static function formatFileInfos($fileInfos) { + $files = array(); + $id = 0; + foreach ($fileInfos as $i) { + $entry = \OCA\Files\Helper::formatFileInfo($i); + $entry['id'] = $id++; + $entry['etag'] = $entry['mtime']; // add fake etag, it is only needed to identify the preview image + $entry['permissions'] = \OCP\PERMISSION_READ; + if (\OCP\App::isEnabled('files_encryption')) { + $entry['isPreviewAvailable'] = false; } + $files[] = $entry; } - return $breadcrumb; + return $files; } } diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index f9264d4352c..b6c61c9b1c3 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -1,12 +1,11 @@
- -
+
-
class="hidden">t('Nothing in here. Your trash bin is empty!'))?>
+ - + @@ -40,6 +39,5 @@
-
diff --git a/apps/files_trashbin/templates/part.breadcrumb.php b/apps/files_trashbin/templates/part.breadcrumb.php deleted file mode 100644 index fdf78c190d0..00000000000 --- a/apps/files_trashbin/templates/part.breadcrumb.php +++ /dev/null @@ -1,19 +0,0 @@ -
- - - - -
svg" - data-dir=''> - -
-200) $relative_date_color = 200; - $name = \OCP\Util::encodePath($file['name']); - $directory = \OCP\Util::encodePath($file['directory']); ?> - ' - - id="" - data-file="" - data-timestamp='' - data-dirlisting=1 - - id="" - data-file="" - data-timestamp='' - data-dirlisting=0 - > - - - - - style="background-image:url()" - - - style="background-image:url()" - - style="background-image:url()" - - - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ownCloud supports simple version control for files. The versioning app expires old versions automatically to make sure that - the user doesn't run out of space. Following pattern is used to delete + the user doesn't run out of space. The following pattern is used to delete old versions: For the first 10 seconds ownCloud keeps one version every 2 seconds; For the first hour ownCloud keeps one version every minute; diff --git a/apps/files_versions/js/versions.js b/apps/files_versions/js/versions.js index 4adf14745de..b452bc25b13 100644 --- a/apps/files_versions/js/versions.js +++ b/apps/files_versions/js/versions.js @@ -11,7 +11,7 @@ $(document).ready(function(){ // Add versions button to 'files/index.php' FileActions.register( 'file' - , t('files_versions', 'Versions') + , 'Versions' , OC.PERMISSION_UPDATE , function() { // Specify icon for hitory button @@ -36,6 +36,7 @@ $(document).ready(function(){ createVersionsDropdown(filename, file); } } + , t('files_versions', 'Versions') ); } diff --git a/apps/files_versions/l10n/ast.php b/apps/files_versions/l10n/ast.php new file mode 100644 index 00000000000..4869d70b54d --- /dev/null +++ b/apps/files_versions/l10n/ast.php @@ -0,0 +1,8 @@ + "Versiones", +"More versions..." => "Más versiones...", +"No other versions available" => "Nun hai otres versiones disponibles", +"Restore" => "Restaurar" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/user_ldap/appinfo/info.xml b/apps/user_ldap/appinfo/info.xml index 9cc908e8522..e4a4375a737 100644 --- a/apps/user_ldap/appinfo/info.xml +++ b/apps/user_ldap/appinfo/info.xml @@ -2,8 +2,8 @@ user_ldap LDAP user and group backend - Authenticate users and groups by LDAP respectively Active - Directory. + Authenticate users and groups through LDAP, such as OpenLDAP + or Active Directory. This app is not compatible with the WebDAV user backend. diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php index cef9ca3c4cf..40d9dec1410 100644 --- a/apps/user_ldap/group_ldap.php +++ b/apps/user_ldap/group_ldap.php @@ -276,6 +276,84 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface { return $groupUsers; } + /** + * @brief returns the number of users in a group, who match the search term + * @param string the internal group name + * @param string optional, a search string + * @returns int | bool + */ + public function countUsersInGroup($gid, $search = '') { + $cachekey = 'countUsersInGroup-'.$gid.'-'.$search; + if(!$this->enabled || !$this->groupExists($gid)) { + return false; + } + $groupUsers = $this->access->connection->getFromCache($cachekey); + if(!is_null($groupUsers)) { + return $groupUsers; + } + + $groupDN = $this->access->groupname2dn($gid); + if(!$groupDN) { + // group couldn't be found, return empty resultset + $this->access->connection->writeToCache($cachekey, false); + return false; + } + + $members = array_keys($this->_groupMembers($groupDN)); + if(!$members) { + //in case users could not be retrieved, return empty resultset + $this->access->connection->writeToCache($cachekey, false); + return false; + } + + if(empty($search)) { + $groupUsers = count($members); + $this->access->connection->writeToCache($cachekey, $groupUsers); + return $groupUsers; + } + $isMemberUid = + (strtolower($this->access->connection->ldapGroupMemberAssocAttr) + === 'memberuid'); + + //we need to apply the search filter + //alternatives that need to be checked: + //a) get all users by search filter and array_intersect them + //b) a, but only when less than 1k 10k ?k users like it is + //c) put all DNs|uids in a LDAP filter, combine with the search string + // and let it count. + //For now this is not important, because the only use of this method + //does not supply a search string + $groupUsers = array(); + foreach($members as $member) { + if($isMemberUid) { + //we got uids, need to get their DNs to 'tranlsate' them to usernames + $filter = $this->access->combineFilterWithAnd(array( + \OCP\Util::mb_str_replace('%uid', $member, + $this->access->connection->ldapLoginFilter, 'UTF-8'), + $this->access->getFilterPartForUserSearch($search) + )); + $ldap_users = $this->access->fetchListOfUsers($filter, 'dn'); + if(count($ldap_users) < 1) { + continue; + } + $groupUsers[] = $this->access->dn2username($ldap_users[0]); + } else { + //we need to apply the search filter now + if(!$this->access->readAttribute($member, + $this->access->connection->ldapUserDisplayName, + $this->access->getFilterPartForUserSearch($search))) { + continue; + } + // dn2username will also check if the users belong to the allowed base + if($ocname = $this->access->dn2username($member)) { + $groupUsers[] = $ocname; + } + } + } + + return count($groupUsers); + } + /** * @brief get a list of all display names in a group * @returns array with display names (value) and user ids(key) @@ -299,9 +377,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface { * @brief get a list of all groups * @returns array with group names * - * Returns a list with all groups + * Returns a list with all groups (used by getGroups) */ - public function getGroups($search = '', $limit = -1, $offset = 0) { + protected function getGroupsChunk($search = '', $limit = -1, $offset = 0) { if(!$this->enabled) { return array(); } @@ -334,6 +412,48 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface { return $ldap_groups; } + /** + * @brief get a list of all groups using a paged search + * @returns array with group names + * + * Returns a list with all groups + * Uses a paged search if available to override a + * server side search limit. + * (active directory has a limit of 1000 by default) + */ + public function getGroups($search = '', $limit = -1, $offset = 0) { + if(!$this->enabled) { + return array(); + } + $pagingsize = $this->access->connection->ldapPagingSize; + if ((! $this->access->connection->hasPagedResultSupport) + || empty($pagingsize)) { + return $this->getGroupsChunk($search, $limit, $offset); + } + $maxGroups = 100000; // limit max results (just for safety reasons) + if ($limit > -1) { + $overallLimit = min($limit, $maxGroups); + } else { + $overallLimit = $maxGroups; + } + $chunkOffset = $offset; + $allGroups = array(); + while ($chunkOffset < $overallLimit) { + $chunkLimit = min($pagingsize, $overallLimit - $chunkOffset); + $ldapGroups = $this->getGroupsChunk($search, $chunkLimit, $chunkOffset); + $nread = count($ldapGroups); + \OCP\Util::writeLog('user_ldap', 'getGroups('.$search.'): read '.$nread.' at offset '.$chunkOffset.' (limit: '.$chunkLimit.')', \OCP\Util::DEBUG); + if ($nread) { + $allGroups = array_merge($allGroups, $ldapGroups); + $chunkOffset += $nread; + } + if ($nread < $chunkLimit) { + break; + } + } + return $allGroups; + } + public function groupMatchesFilter($group) { return (strripos($group, $this->groupSearch) !== false); } @@ -376,6 +496,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface { * compared with OC_USER_BACKEND_CREATE_USER etc. */ public function implementsActions($actions) { - return (bool)(OC_GROUP_BACKEND_GET_DISPLAYNAME & $actions); + return (bool)(( + OC_GROUP_BACKEND_GET_DISPLAYNAME + | OC_GROUP_BACKEND_COUNT_USERS + ) & $actions); } } diff --git a/apps/user_ldap/group_proxy.php b/apps/user_ldap/group_proxy.php index 4404bd7fe3a..c0009736239 100644 --- a/apps/user_ldap/group_proxy.php +++ b/apps/user_ldap/group_proxy.php @@ -144,6 +144,17 @@ class Group_Proxy extends lib\Proxy implements \OCP\GroupInterface { return $users; } + /** + * @brief returns the number of users in a group, who match the search term + * @param string the internal group name + * @param string optional, a search string + * @returns int | bool + */ + public function countUsersInGroup($gid, $search = '') { + return $this->handleRequest( + $gid, 'countUsersInGroup', array($gid, $search)); + } + /** * @brief get a list of all display names in a group * @returns array with display names (value) and user ids(key) diff --git a/apps/user_ldap/l10n/ast.php b/apps/user_ldap/l10n/ast.php new file mode 100644 index 00000000000..2c022880019 --- /dev/null +++ b/apps/user_ldap/l10n/ast.php @@ -0,0 +1,11 @@ + "Falló'l borráu", +"Error" => "Fallu", +"_%s group found_::_%s groups found_" => array("",""), +"_%s user found_::_%s users found_" => array("",""), +"Save" => "Guardar", +"Password" => "Contraseña", +"Continue" => "Continuar" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/user_ldap/l10n/az.php b/apps/user_ldap/l10n/az.php index bba52d53a1a..3a1e002311c 100644 --- a/apps/user_ldap/l10n/az.php +++ b/apps/user_ldap/l10n/az.php @@ -1,6 +1,6 @@ array(""), -"_%s user found_::_%s users found_" => array("") +"_%s group found_::_%s groups found_" => array("",""), +"_%s user found_::_%s users found_" => array("","") ); -$PLURAL_FORMS = "nplurals=1; plural=0;"; +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/user_ldap/l10n/bn_BD.php b/apps/user_ldap/l10n/bn_BD.php index 0b43a27df94..90f7b572a95 100644 --- a/apps/user_ldap/l10n/bn_BD.php +++ b/apps/user_ldap/l10n/bn_BD.php @@ -13,7 +13,6 @@ $TRANSLATIONS = array( "Password" => "কূটশব্দ", "For anonymous access, leave DN and Password empty." => "অজ্ঞাতকুলশীল অধিগমনের জন্য DN এবং কূটশব্দটি ফাঁকা রাখুন।", "You can specify Base DN for users and groups in the Advanced tab" => "সুচারু ট্যঅবে গিয়ে আপনি ব্যবহারকারি এবং গোষ্ঠীসমূহের জন্য ভিত্তি DN নির্ধারণ করতে পারেন।", -"Case insensitve LDAP server (Windows)" => "বর্ণ অসংবেদী LDAP সার্ভার (উইন্ডোজ)", "Turn off SSL certificate validation." => "SSL সনদপত্র যাচাইকরণ বন্ধ রাক।", "in seconds. A change empties the cache." => "সেকেন্ডে। কোন পরিবর্তন ক্যাসে খালি করবে।", "User Display Name Field" => "ব্যবহারকারীর প্রদর্শিতব্য নামের ক্ষেত্র", diff --git a/apps/user_ldap/l10n/ca.php b/apps/user_ldap/l10n/ca.php index 940c6ea8b66..98b1cf74640 100644 --- a/apps/user_ldap/l10n/ca.php +++ b/apps/user_ldap/l10n/ca.php @@ -70,7 +70,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Port de la còpia de seguretat (rèplica)", "Disable Main Server" => "Desactiva el servidor principal", "Only connect to the replica server." => "Connecta només al servidor rèplica.", -"Case insensitve LDAP server (Windows)" => "Servidor LDAP sense distinció entre majúscules i minúscules (Windows)", "Turn off SSL certificate validation." => "Desactiva la validació de certificat SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "No es recomana, useu-ho només com a prova! Importeu el certificat SSL del servidor LDAP al servidor %s només si la connexió funciona amb aquesta opció.", "Cache Time-To-Live" => "Memòria de cau Time-To-Live", diff --git a/apps/user_ldap/l10n/cs_CZ.php b/apps/user_ldap/l10n/cs_CZ.php index 536834ee8b5..d4039e9ef10 100644 --- a/apps/user_ldap/l10n/cs_CZ.php +++ b/apps/user_ldap/l10n/cs_CZ.php @@ -70,7 +70,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Záložní (kopie) port", "Disable Main Server" => "Zakázat hlavní server", "Only connect to the replica server." => "Připojit jen k záložnímu serveru.", -"Case insensitve LDAP server (Windows)" => "LDAP server nerozlišující velikost znaků (Windows)", "Turn off SSL certificate validation." => "Vypnout ověřování SSL certifikátu.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Nedoporučuje se, určeno pouze k testovacímu použití. Pokud spojení funguje jen s touto volbou, importujte SSL certifikát vašeho LDAP serveru na server %s.", "Cache Time-To-Live" => "TTL vyrovnávací paměti", diff --git a/apps/user_ldap/l10n/da.php b/apps/user_ldap/l10n/da.php index e375598c9bd..8264a18116c 100644 --- a/apps/user_ldap/l10n/da.php +++ b/apps/user_ldap/l10n/da.php @@ -35,7 +35,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Backup (Replika) Port", "Disable Main Server" => "Deaktiver Hovedserver", "Only connect to the replica server." => "Forbind kun til replika serveren.", -"Case insensitve LDAP server (Windows)" => "Ikke versalfølsom LDAP server (Windows)", "Turn off SSL certificate validation." => "Deaktiver SSL certifikat validering", "Cache Time-To-Live" => "Cache Time-To-Live", "User Display Name Field" => "User Display Name Field", diff --git a/apps/user_ldap/l10n/de.php b/apps/user_ldap/l10n/de.php index 8dad9b34539..43336520739 100644 --- a/apps/user_ldap/l10n/de.php +++ b/apps/user_ldap/l10n/de.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Backup Port", "Disable Main Server" => "Hauptserver deaktivieren", "Only connect to the replica server." => "Nur zum Replikat-Server verbinden.", -"Case insensitve LDAP server (Windows)" => "LDAP-Server (Windows: Groß- und Kleinschreibung bleibt unbeachtet)", +"Case insensitive LDAP server (Windows)" => "LDAP-Server (Windows - Groß- und Kleinschreibung bleibt unbeachtet)", "Turn off SSL certificate validation." => "Schalte die SSL-Zertifikatsprüfung aus.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Nur für Testzwecke geeignet, sollte Standardmäßig nicht verwendet werden. Falls die Verbindung nur mit dieser Option funktioniert, importiere das SSL-Zertifikat des LDAP-Servers in deinen %s Server.", "Cache Time-To-Live" => "Speichere Time-To-Live zwischen", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Assoziation zwischen Gruppe und Benutzer", "Nested Groups" => "Eingebundene Gruppen", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Wenn aktiviert, werden Gruppen, die Gruppen enthalten, unterstützt. (Funktioniert nur, wenn das Merkmal des Gruppenmitgliedes den Domain-Namen enthält.)", +"Paging chunksize" => "Seitenstücke (Paging chunksize)", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Die Größe der Seitenstücke (Chunksize) wird für seitenbezogene LDAP-Suchen verwendet die sehr viele Ergebnisse z.B. Nutzer- und Gruppenaufzählungen liefern. (Die Einstellung 0 deaktiviert das seitenbezogene LDAP-Suchen in diesen Situationen)", "Special Attributes" => "Spezielle Eigenschaften", "Quota Field" => "Kontingent Feld", "Quota Default" => "Standard Kontingent", diff --git a/apps/user_ldap/l10n/de_CH.php b/apps/user_ldap/l10n/de_CH.php index 5f8e2907f07..f60d425a2e6 100644 --- a/apps/user_ldap/l10n/de_CH.php +++ b/apps/user_ldap/l10n/de_CH.php @@ -42,7 +42,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Backup Port", "Disable Main Server" => "Hauptserver deaktivieren", "Only connect to the replica server." => "Nur zum Replikat-Server verbinden.", -"Case insensitve LDAP server (Windows)" => "LDAP-Server (Windows: Gross- und Kleinschreibung bleibt unbeachtet)", "Turn off SSL certificate validation." => "Schalten Sie die SSL-Zertifikatsprüfung aus.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Nur für Testzwecke geeignet, sollte Standardmäßig nicht verwendet werden. Falls die Verbindung nur mit dieser Option funktioniert, importieren Sie das SSL-Zertifikat des LDAP-Servers in Ihren %s Server.", "Cache Time-To-Live" => "Speichere Time-To-Live zwischen", diff --git a/apps/user_ldap/l10n/de_DE.php b/apps/user_ldap/l10n/de_DE.php index 6e6e29ea3db..21c149d1a1d 100644 --- a/apps/user_ldap/l10n/de_DE.php +++ b/apps/user_ldap/l10n/de_DE.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Backup Port", "Disable Main Server" => "Hauptserver deaktivieren", "Only connect to the replica server." => "Nur zum Replikat-Server verbinden.", -"Case insensitve LDAP server (Windows)" => "LDAP-Server (Windows: Groß- und Kleinschreibung bleibt unbeachtet)", +"Case insensitive LDAP server (Windows)" => "LDAP-Server (Windows: Groß- und Kleinschreibung bleibt unbeachtet)", "Turn off SSL certificate validation." => "Schalten Sie die SSL-Zertifikatsprüfung aus.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Nur für Testzwecke geeignet, sollte Standardmäßig nicht verwendet werden. Falls die Verbindung nur mit dieser Option funktioniert, importieren Sie das SSL-Zertifikat des LDAP-Servers in Ihren %s Server.", "Cache Time-To-Live" => "Speichere Time-To-Live zwischen", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Assoziation zwischen Gruppe und Benutzer", "Nested Groups" => "Eingebundene Gruppen", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Wenn aktiviert, werden Gruppen, die Gruppen enthalten, unterstützt. (Funktioniert nur, wenn das Merkmal des Gruppenmitgliedes den Domain-Namen enthält.)", +"Paging chunksize" => "Seitenstücke (Paging chunksize)", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Die Größe der Seitenstücke (Chunksize) wird für seitenbezogene LDAP-Suchen verwendet die sehr viele Ergebnisse z.B. Nutzer- und Gruppenaufzählungen liefern. (Die Einstellung 0 deaktiviert das seitenbezogene LDAP-Suchen in diesen Situationen)", "Special Attributes" => "Spezielle Eigenschaften", "Quota Field" => "Kontingent-Feld", "Quota Default" => "Standard-Kontingent", diff --git a/apps/user_ldap/l10n/el.php b/apps/user_ldap/l10n/el.php index 1e975911953..cfc5286a408 100644 --- a/apps/user_ldap/l10n/el.php +++ b/apps/user_ldap/l10n/el.php @@ -33,12 +33,14 @@ $TRANSLATIONS = array( "Save" => "Αποθήκευση", "Test Configuration" => "Δοκιμαστικες ρυθμισεις", "Help" => "Βοήθεια", +"Groups meeting these criteria are available in %s:" => "Οι ομάδες που πληρούν τα κριτήρια είναι διαθέσιμες σε %s:", "only those object classes:" => "μόνο αυτές οι κλάσεις αντικειμένων:", "only from those groups:" => "μόνο από αυτές τις ομάδες:", "Edit raw filter instead" => "Επεξεργασία πρωτογενούς φίλτρου αντί αυτού", "Raw LDAP filter" => "Πρωτογενές φίλτρο ", "The filter specifies which LDAP groups shall have access to the %s instance." => "Το φίλτρο καθορίζει ποιες ομάδες LDAP θα έχουν πρόσβαση στην εγκατάσταση %s.", "groups found" => "ομάδες βρέθηκαν", +"Users login with this attribute:" => "Οι χρήστες εισέρχονται με αυτό το χαρακτηριστικό:", "LDAP Username:" => "Όνομα χρήστη LDAP:", "LDAP Email Address:" => "Διεύθυνση ηλ. ταχυδρομείου LDAP:", "Other Attributes:" => "Άλλες Ιδιότητες:", @@ -53,6 +55,7 @@ $TRANSLATIONS = array( "For anonymous access, leave DN and Password empty." => "Για ανώνυμη πρόσβαση, αφήστε κενά τα πεδία DN και Pasword.", "One Base DN per line" => "Ένα DN Βάσης ανά γραμμή ", "You can specify Base DN for users and groups in the Advanced tab" => "Μπορείτε να καθορίσετε το Base DN για χρήστες και ομάδες από την καρτέλα Προηγμένες ρυθμίσεις", +"Limit %s access to users meeting these criteria:" => "Περιορισμός της πρόσβασης %s σε χρήστες που πληρούν τα κριτήρια:", "The filter specifies which LDAP users shall have access to the %s instance." => "Το φίλτρο καθορίζει ποιοι χρήστες LDAP θα έχουν πρόσβαση στην εγκατάσταση %s.", "users found" => "χρήστες βρέθηκαν", "Back" => "Επιστροφή", @@ -67,7 +70,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Δημιουργία αντιγράφων ασφαλείας (Replica) Υποδοχη", "Disable Main Server" => "Απενεργοποιηση του κεντρικου διακομιστη", "Only connect to the replica server." => "Σύνδεση μόνο με το διακομιστή-αντίγραφο.", -"Case insensitve LDAP server (Windows)" => "LDAP server (Windows) με διάκριση πεζών-ΚΕΦΑΛΑΙΩΝ", "Turn off SSL certificate validation." => "Απενεργοποίηση επικύρωσης πιστοποιητικού SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Δεν προτείνεται, χρησιμοποιείστε το μόνο για δοκιμές! Εάν η σύνδεση λειτουργεί μόνο με αυτή την επιλογή, εισάγετε το πιστοποιητικό SSL του διακομιστή LDAP στο %s διακομιστή σας.", "Cache Time-To-Live" => "Cache Time-To-Live", @@ -85,6 +87,7 @@ $TRANSLATIONS = array( "One Group Base DN per line" => "Μια ομαδικη Βάση DN ανά γραμμή", "Group Search Attributes" => "Ομάδα Χαρακτηριστικων Αναζήτηση", "Group-Member association" => "Group-Member association", +"Nested Groups" => "Φωλιασμένες ομάδες", "Special Attributes" => "Ειδικά Χαρακτηριστικά ", "Quota Field" => "Ποσοσταση πεδιου", "Quota Default" => "Προκαθισμενο πεδιο", diff --git a/apps/user_ldap/l10n/en_GB.php b/apps/user_ldap/l10n/en_GB.php index 4421a8035ca..6dfc3e53f0c 100644 --- a/apps/user_ldap/l10n/en_GB.php +++ b/apps/user_ldap/l10n/en_GB.php @@ -70,7 +70,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Backup (Replica) Port", "Disable Main Server" => "Disable Main Server", "Only connect to the replica server." => "Only connect to the replica server.", -"Case insensitve LDAP server (Windows)" => "Case insensitve LDAP server (Windows)", "Turn off SSL certificate validation." => "Turn off SSL certificate validation.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server.", "Cache Time-To-Live" => "Cache Time-To-Live", @@ -90,6 +89,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Group-Member association", "Nested Groups" => "Nested Groups", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)", +"Paging chunksize" => "Paging chunksize", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)", "Special Attributes" => "Special Attributes", "Quota Field" => "Quota Field", "Quota Default" => "Quota Default", diff --git a/apps/user_ldap/l10n/eo.php b/apps/user_ldap/l10n/eo.php index 0cae524bcc1..74928899c8a 100644 --- a/apps/user_ldap/l10n/eo.php +++ b/apps/user_ldap/l10n/eo.php @@ -35,7 +35,6 @@ $TRANSLATIONS = array( "Back" => "Antaŭen", "Connection Settings" => "Agordo de konekto", "Disable Main Server" => "Malkapabligi la ĉefan servilon", -"Case insensitve LDAP server (Windows)" => "LDAP-servilo blinda je litergrandeco (Vindozo)", "Turn off SSL certificate validation." => "Malkapabligi validkontrolon de SSL-atestiloj.", "Cache Time-To-Live" => "Vivotempo de la kaŝmemoro", "in seconds. A change empties the cache." => "sekunde. Ajna ŝanĝo malplenigas la kaŝmemoron.", diff --git a/apps/user_ldap/l10n/es.php b/apps/user_ldap/l10n/es.php index 1821aa8d446..2c294aff785 100644 --- a/apps/user_ldap/l10n/es.php +++ b/apps/user_ldap/l10n/es.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Puerto para copias de seguridad (Replica)", "Disable Main Server" => "Deshabilitar servidor principal", "Only connect to the replica server." => "Conectar sólo con el servidor de réplica.", -"Case insensitve LDAP server (Windows)" => "Servidor de LDAP no sensible a mayúsculas/minúsculas (Windows)", +"Case insensitive LDAP server (Windows)" => "Servidor de LDAP insensible a mayúsculas/minúsculas (Windows)", "Turn off SSL certificate validation." => "Apagar la validación por certificado SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "No se recomienda, ¡utilízalo únicamente para pruebas! Si la conexión únicamente funciona con esta opción, importa el certificado SSL del servidor LDAP en tu servidor %s.", "Cache Time-To-Live" => "Cache TTL", diff --git a/apps/user_ldap/l10n/es_AR.php b/apps/user_ldap/l10n/es_AR.php index 6323fe0c4ad..877141bcdc8 100644 --- a/apps/user_ldap/l10n/es_AR.php +++ b/apps/user_ldap/l10n/es_AR.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Puerto para copia de seguridad (réplica)", "Disable Main Server" => "Deshabilitar el Servidor Principal", "Only connect to the replica server." => "Conectarse únicamente al servidor de réplica.", -"Case insensitve LDAP server (Windows)" => "Servidor de LDAP sensible a mayúsculas/minúsculas (Windows)", "Turn off SSL certificate validation." => "Desactivar la validación por certificado SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "No es recomendado, ¡Usalo solamente para pruebas! Si la conexión únicamente funciona con esta opción, importá el certificado SSL del servidor LDAP en tu servidor %s.", "Cache Time-To-Live" => "Tiempo de vida del caché", diff --git a/apps/user_ldap/l10n/es_MX.php b/apps/user_ldap/l10n/es_MX.php index 09c99209a55..bb4c3700ec5 100644 --- a/apps/user_ldap/l10n/es_MX.php +++ b/apps/user_ldap/l10n/es_MX.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Puerto para copias de seguridad (Replica)", "Disable Main Server" => "Deshabilitar servidor principal", "Only connect to the replica server." => "Conectar sólo con el servidor de réplica.", -"Case insensitve LDAP server (Windows)" => "Servidor de LDAP no sensible a mayúsculas/minúsculas (Windows)", "Turn off SSL certificate validation." => "Apagar la validación por certificado SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "No se recomienda, ¡utilízalo únicamente para pruebas! Si la conexión únicamente funciona con esta opción, importa el certificado SSL del servidor LDAP en tu servidor %s.", "Cache Time-To-Live" => "Cache TTL", diff --git a/apps/user_ldap/l10n/et_EE.php b/apps/user_ldap/l10n/et_EE.php index 090accceda0..f52449bda8b 100644 --- a/apps/user_ldap/l10n/et_EE.php +++ b/apps/user_ldap/l10n/et_EE.php @@ -33,12 +33,14 @@ $TRANSLATIONS = array( "Save" => "Salvesta", "Test Configuration" => "Testi seadistust", "Help" => "Abiinfo", +"Groups meeting these criteria are available in %s:" => "Kriteeriumiga sobivad grupid on saadaval %s:", "only those object classes:" => "ainult need objektiklassid:", "only from those groups:" => "ainult nendest gruppidest:", "Edit raw filter instead" => "Selle asemel muuda filtrit", "Raw LDAP filter" => "LDAP filter", "The filter specifies which LDAP groups shall have access to the %s instance." => "Filter määrab millised LDAP grupid saavad ligipääsu sellele %s instantsile.", "groups found" => "gruppi leitud", +"Users login with this attribute:" => "Logimiseks kasutatkse atribuuti: ", "LDAP Username:" => "LDAP kasutajanimi:", "LDAP Email Address:" => "LDAP e-posti aadress:", "Other Attributes:" => "Muud atribuudid:", @@ -53,6 +55,7 @@ $TRANSLATIONS = array( "For anonymous access, leave DN and Password empty." => "Anonüümseks ligipääsuks jäta DN ja parool tühjaks.", "One Base DN per line" => "Üks baas-DN rea kohta", "You can specify Base DN for users and groups in the Advanced tab" => "Sa saad kasutajate ja gruppide baas DN-i määrata lisavalikute vahekaardilt", +"Limit %s access to users meeting these criteria:" => "Piira %s liigpääs kriteeriumiga sobivatele kasutajatele:", "The filter specifies which LDAP users shall have access to the %s instance." => "Filter määrab millised LDAP kasutajad pääsevad ligi %s instantsile.", "users found" => "kasutajat leitud", "Back" => "Tagasi", @@ -67,7 +70,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Varuserveri (replika) port", "Disable Main Server" => "Ära kasuta peaserverit", "Only connect to the replica server." => "Ühendu ainult replitseeriva serveriga.", -"Case insensitve LDAP server (Windows)" => "Mittetõstutundlik LDAP server (Windows)", "Turn off SSL certificate validation." => "Lülita SSL sertifikaadi kontrollimine välja.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Pole soovitatav, kasuta seda ainult testimiseks! Kui ühendus toimib ainult selle valikuga, siis impordi LDAP serveri SSL sertifikaat oma %s serverisse.", "Cache Time-To-Live" => "Puhvri iga", @@ -85,6 +87,8 @@ $TRANSLATIONS = array( "One Group Base DN per line" => "Üks grupi baas-DN rea kohta", "Group Search Attributes" => "Grupi otsingu atribuudid", "Group-Member association" => "Grupiliikme seotus", +"Nested Groups" => "Sisegrupp", +"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Sisse lülitamisel on toetatakse gruppe sisaldavad gruppe. (Toimib, kui grupi liikme atribuut sisaldab DN-e.)", "Special Attributes" => "Spetsiifilised atribuudid", "Quota Field" => "Mahupiirangu atribuut", "Quota Default" => "Vaikimisi mahupiirang", diff --git a/apps/user_ldap/l10n/eu.php b/apps/user_ldap/l10n/eu.php index a7bd52e50ac..c19cb034ad0 100644 --- a/apps/user_ldap/l10n/eu.php +++ b/apps/user_ldap/l10n/eu.php @@ -61,7 +61,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Babeskopia (Replica) Ataka", "Disable Main Server" => "Desgaitu Zerbitzari Nagusia", "Only connect to the replica server." => "Konektatu bakarrik erreplika zerbitzarira", -"Case insensitve LDAP server (Windows)" => "Maiuskulak eta minuskulak ezberditzen ez dituen LDAP zerbitzaria (windows)", "Turn off SSL certificate validation." => "Ezgaitu SSL ziurtagirien egiaztapena.", "Cache Time-To-Live" => "Katxearen Bizi-Iraupena", "in seconds. A change empties the cache." => "segundutan. Aldaketak katxea husten du.", diff --git a/apps/user_ldap/l10n/fa.php b/apps/user_ldap/l10n/fa.php index 688a6ee0d42..62a949f88bd 100644 --- a/apps/user_ldap/l10n/fa.php +++ b/apps/user_ldap/l10n/fa.php @@ -34,7 +34,6 @@ $TRANSLATIONS = array( "Backup (Replica) Host" => "پشتیبان گیری (بدل) میزبان", "Backup (Replica) Port" => "پشتیبان گیری (بدل) پورت", "Disable Main Server" => "غیر فعال کردن سرور اصلی", -"Case insensitve LDAP server (Windows)" => "غیر حساس به بزرگی و کوچکی حروف LDAP سرور (ویندوز)", "Turn off SSL certificate validation." => "غیرفعال کردن اعتبار گواهی نامه SSL .", "Directory Settings" => "تنظیمات پوشه", "User Display Name Field" => "فیلد نام کاربر", diff --git a/apps/user_ldap/l10n/fi_FI.php b/apps/user_ldap/l10n/fi_FI.php index ac1dfcc5ab8..552fd9f923b 100644 --- a/apps/user_ldap/l10n/fi_FI.php +++ b/apps/user_ldap/l10n/fi_FI.php @@ -25,7 +25,6 @@ $TRANSLATIONS = array( "Continue" => "Jatka", "Connection Settings" => "Yhteysasetukset", "Disable Main Server" => "Poista pääpalvelin käytöstä", -"Case insensitve LDAP server (Windows)" => "Kirjainkoosta piittamaton LDAP-palvelin (Windows)", "Turn off SSL certificate validation." => "Poista käytöstä SSL-varmenteen vahvistus", "in seconds. A change empties the cache." => "sekunneissa. Muutos tyhjentää välimuistin.", "Directory Settings" => "Hakemistoasetukset", diff --git a/apps/user_ldap/l10n/fr.php b/apps/user_ldap/l10n/fr.php index dbcaadfc2a7..44b92077b92 100644 --- a/apps/user_ldap/l10n/fr.php +++ b/apps/user_ldap/l10n/fr.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Port du serveur de backup (réplique)", "Disable Main Server" => "Désactiver le serveur principal", "Only connect to the replica server." => "Se connecter uniquement au serveur de replica.", -"Case insensitve LDAP server (Windows)" => "Serveur LDAP insensible à la casse (Windows)", +"Case insensitive LDAP server (Windows)" => "Serveur LDAP insensible à la casse (Windows)", "Turn off SSL certificate validation." => "Désactiver la validation du certificat SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Non recommandé, à utiliser à des fins de tests uniquement. Si la connexion ne fonctionne qu'avec cette option, importez le certificat SSL du serveur LDAP dans le serveur %s.", "Cache Time-To-Live" => "Durée de vie du cache", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Association groupe-membre", "Nested Groups" => "Groupes imbriqués", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Si activé, les groupes contenant d'autres groupes sont supportés (fonctionne uniquement si l'attribut membre du groupe contient des DNs).", +"Paging chunksize" => "Dimensionnement des paginations", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "La taille d'une part (chunksize) est utilisée pour les recherches paginées de LDAP qui peuvent retourner des résultats par lots comme une énumération d'utilisateurs ou groupes. (Configurer à 0 pour désactiver les recherches paginées de LDAP.)", "Special Attributes" => "Attributs spéciaux", "Quota Field" => "Champ du quota", "Quota Default" => "Quota par défaut", diff --git a/apps/user_ldap/l10n/gl.php b/apps/user_ldap/l10n/gl.php index 802c6d0e435..82c484bb95d 100644 --- a/apps/user_ldap/l10n/gl.php +++ b/apps/user_ldap/l10n/gl.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Porto da copia de seguranza (Réplica)", "Disable Main Server" => "Desactivar o servidor principal", "Only connect to the replica server." => "Conectar só co servidor de réplica.", -"Case insensitve LDAP server (Windows)" => "Servidor LDAP que non distingue entre maiúsculas e minúsculas (Windows)", +"Case insensitive LDAP server (Windows)" => "Servidor LDAP non sensíbel a maiúsculas (Windows)", "Turn off SSL certificate validation." => "Desactiva a validación do certificado SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Non recomendado, utilizar só para probas! Se a conexión só funciona con esta opción importa o certificado SSL do servidor LDAP no seu servidor %s.", "Cache Time-To-Live" => "Tempo de persistencia da caché", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Asociación de grupos e membros", "Nested Groups" => "Grupos aniñados", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Se está activado, admítense grupos que conteñen grupos. (Só funciona se o atributo de membro de grupo conten os DN.)", +"Paging chunksize" => "Tamaño dos fragmentos paxinados", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Tamaño dos fragmentos utilizados para as buscas LDAP paxinadas, que poden devolver resultados voluminosos como usuario ou enumeración de grupo. (Se se establece a 0, desactívanse as buscas LDAP paxinadas nesas situacións.)", "Special Attributes" => "Atributos especiais", "Quota Field" => "Campo de cota", "Quota Default" => "Cota predeterminada", diff --git a/apps/user_ldap/l10n/hu_HU.php b/apps/user_ldap/l10n/hu_HU.php index 277ae96fcd4..34daa25ce68 100644 --- a/apps/user_ldap/l10n/hu_HU.php +++ b/apps/user_ldap/l10n/hu_HU.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "A másodkiszolgáló (replika) portszáma", "Disable Main Server" => "A fő szerver kihagyása", "Only connect to the replica server." => "Csak a másodlagos (másolati) kiszolgálóhoz kapcsolódjunk.", -"Case insensitve LDAP server (Windows)" => "Az LDAP-kiszolgáló nem tesz különbséget a kis- és nagybetűk között (Windows)", "Turn off SSL certificate validation." => "Ne ellenőrizzük az SSL-tanúsítvány érvényességét", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Használata nem javasolt (kivéve tesztelési céllal). Ha a kapcsolat csak ezzel a beállítással működik, akkor importálja az LDAP-kiszolgáló SSL tanúsítványát a(z) %s kiszolgálóra!", "Cache Time-To-Live" => "A gyorsítótár tárolási időtartama", diff --git a/apps/user_ldap/l10n/id.php b/apps/user_ldap/l10n/id.php index 03071bb1d0f..1d42031a498 100644 --- a/apps/user_ldap/l10n/id.php +++ b/apps/user_ldap/l10n/id.php @@ -39,7 +39,6 @@ $TRANSLATIONS = array( "Give an optional backup host. It must be a replica of the main LDAP/AD server." => "Berikan pilihan host cadangan. Harus merupakan replika dari server LDAP/AD utama.", "Backup (Replica) Port" => "Port Cadangan (Replika)", "Disable Main Server" => "Nonaktifkan Server Utama", -"Case insensitve LDAP server (Windows)" => "Server LDAP dengan kapitalisasi tidak sensitif (Windows)", "Turn off SSL certificate validation." => "matikan validasi sertivikat SSL", "Cache Time-To-Live" => "Gunakan Tembolok untuk Time-To-Live", "in seconds. A change empties the cache." => "dalam detik. perubahan mengosongkan cache", diff --git a/apps/user_ldap/l10n/it.php b/apps/user_ldap/l10n/it.php index 4436127747f..095a0619ee1 100644 --- a/apps/user_ldap/l10n/it.php +++ b/apps/user_ldap/l10n/it.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Porta di backup (Replica)", "Disable Main Server" => "Disabilita server principale", "Only connect to the replica server." => "Collegati solo al server di replica.", -"Case insensitve LDAP server (Windows)" => "Case insensitve LDAP server (Windows)", +"Case insensitive LDAP server (Windows)" => "Server LDAP non sensibile alle maiuscole (Windows)", "Turn off SSL certificate validation." => "Disattiva il controllo del certificato SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Non consigliata, da utilizzare solo per test! Se la connessione funziona solo con questa opzione, importa il certificate SSL del server LDAP sul tuo server %s.", "Cache Time-To-Live" => "Tempo di vita della cache", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Associazione gruppo-utente ", "Nested Groups" => "Gruppi nidificati", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Quando è attivato, i gruppi che contengono altri gruppi sono supportati. (Funziona solo se l'attributo del gruppo membro contiene DN.)", +"Paging chunksize" => "Dimensione del blocco di paginazione", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Dimensione del blocco per le ricerche LDAP paginate che potrebbero restituire risultati pesanti come l'enumerazione di utenti o gruppi.(L'impostazione a 0 disabilita le ricerche LDAP paginate in questi casi.)", "Special Attributes" => "Attributi speciali", "Quota Field" => "Campo Quota", "Quota Default" => "Quota predefinita", diff --git a/apps/user_ldap/l10n/ja.php b/apps/user_ldap/l10n/ja.php index d13deafe6c3..e7e4706c46a 100644 --- a/apps/user_ldap/l10n/ja.php +++ b/apps/user_ldap/l10n/ja.php @@ -70,7 +70,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "バックアップ(レプリカ)ポート", "Disable Main Server" => "メインサーバーを無効にする", "Only connect to the replica server." => "レプリカサーバーにのみ接続します。", -"Case insensitve LDAP server (Windows)" => "大文字/小文字を区別しないLDAPサーバー(Windows)", "Turn off SSL certificate validation." => "SSL証明書の確認を無効にする。", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "推奨されません、テストにおいてのみ使用してください!このオプションでのみ接続が動作する場合は、LDAP サーバーのSSL証明書を %s サーバーにインポートしてください。", "Cache Time-To-Live" => "キャッシュのTTL", diff --git a/apps/user_ldap/l10n/jv.php b/apps/user_ldap/l10n/jv.php new file mode 100644 index 00000000000..3a1e002311c --- /dev/null +++ b/apps/user_ldap/l10n/jv.php @@ -0,0 +1,6 @@ + array("",""), +"_%s user found_::_%s users found_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/user_ldap/l10n/ka_GE.php b/apps/user_ldap/l10n/ka_GE.php index ffdf7655517..3ee307b55cc 100644 --- a/apps/user_ldap/l10n/ka_GE.php +++ b/apps/user_ldap/l10n/ka_GE.php @@ -37,7 +37,6 @@ $TRANSLATIONS = array( "Give an optional backup host. It must be a replica of the main LDAP/AD server." => "მიუთითეთ რაიმე ბექაფ ჰოსტი. ის უნდა იყოს ძირითადი LDAP/AD სერვერის რეპლიკა.", "Backup (Replica) Port" => "ბექაფ (რეპლიკა) პორტი", "Disable Main Server" => "გამორთეთ ძირითადი სერვერი", -"Case insensitve LDAP server (Windows)" => "LDAP server (Windows)", "Turn off SSL certificate validation." => "გამორთეთ SSL სერთიფიკატის ვალიდაცია.", "Cache Time-To-Live" => "ქეშის სიცოცხლის ხანგრძლივობა", "in seconds. A change empties the cache." => "წამებში. ცვლილება ასუფთავებს ქეშს.", diff --git a/apps/user_ldap/l10n/ko.php b/apps/user_ldap/l10n/ko.php index 5dd2151a411..1ae63bd4d21 100644 --- a/apps/user_ldap/l10n/ko.php +++ b/apps/user_ldap/l10n/ko.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "백업 (복제) 포트", "Disable Main Server" => "주 서버 비활성화", "Only connect to the replica server." => "복제 서버에만 연결합니다.", -"Case insensitve LDAP server (Windows)" => "서버에서 대소문자를 구분하지 않음 (Windows)", "Turn off SSL certificate validation." => "SSL 인증서 유효성 검사를 해제합니다.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "테스트 목적으로만 사용하십시오! 이 옵션을 사용해야만 연결할 수 있으면 %s 서버에 LDAP 서버의 SSL 인증서를 설치하십시오.", "Cache Time-To-Live" => "캐시 유지 시간", diff --git a/apps/user_ldap/l10n/lv.php b/apps/user_ldap/l10n/lv.php index 769f17e6338..e3cb206e2d6 100644 --- a/apps/user_ldap/l10n/lv.php +++ b/apps/user_ldap/l10n/lv.php @@ -36,7 +36,6 @@ $TRANSLATIONS = array( "Give an optional backup host. It must be a replica of the main LDAP/AD server." => "Norādi rezerves serveri (nav obligāti). Tam ir jābūt galvenā LDAP/AD servera kopijai.", "Backup (Replica) Port" => "Rezerves (kopijas) ports", "Disable Main Server" => "Deaktivēt galveno serveri", -"Case insensitve LDAP server (Windows)" => "Reģistrnejutīgs LDAP serveris (Windows)", "Turn off SSL certificate validation." => "Izslēgt SSL sertifikātu validēšanu.", "Cache Time-To-Live" => "Kešatmiņas dzīvlaiks", "in seconds. A change empties the cache." => "sekundēs. Izmaiņas iztukšos kešatmiņu.", diff --git a/apps/user_ldap/l10n/nb_NO.php b/apps/user_ldap/l10n/nb_NO.php index 0b60752e9d9..dd4af3e759e 100644 --- a/apps/user_ldap/l10n/nb_NO.php +++ b/apps/user_ldap/l10n/nb_NO.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Reserve (Replika) Port", "Disable Main Server" => "Deaktiver hovedtjeneren", "Only connect to the replica server." => "Koble til bare replika-tjeneren.", -"Case insensitve LDAP server (Windows)" => "Case-insensitiv LDAP tjener (Windows)", "Turn off SSL certificate validation." => "Slå av SSL-sertifikat validering", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Ikke anbefalt, bruk kun for testing! Hvis tilkobling bare virker med dette valget, importer LDAP-tjenerens SSL-sertifikat i %s-serveren din.", "Cache Time-To-Live" => "Levetid i mellomlager", diff --git a/apps/user_ldap/l10n/nl.php b/apps/user_ldap/l10n/nl.php index 55e4e07033a..196e5a52d12 100644 --- a/apps/user_ldap/l10n/nl.php +++ b/apps/user_ldap/l10n/nl.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Backup (Replica) Poort", "Disable Main Server" => "Deactiveren hoofdserver", "Only connect to the replica server." => "Maak alleen een verbinding met de replica server.", -"Case insensitve LDAP server (Windows)" => "Niet-hoofdlettergevoelige LDAP server (Windows)", +"Case insensitive LDAP server (Windows)" => "Niet-hoofdlettergevoelige LDAP server (Windows)", "Turn off SSL certificate validation." => "Schakel SSL certificaat validatie uit.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Niet aanbevolen, gebruik alleen om te testen! Als de connectie alleen werkt met deze optie, importeer dan het SSL-certificaat van de LDAP-server naar uw %s server.", "Cache Time-To-Live" => "Cache time-to-live", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Groepslid associatie", "Nested Groups" => "Geneste groepen", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Wanneer ingeschakeld worden groepen binnen groepen ondersteund. (Werkt alleen als het groepslid attribuut DNs bevat)", +"Paging chunksize" => "Paging chunkgrootte", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "De chunkgrootte die wordt gebruikt voor LDAP opvragingen die in grote aantallen resulteren, zoals gebruiker- of groepsverzamelingen. (Instellen op 0 deactiveert gepagede LDAP opvragingen in dergelijke situaties.)", "Special Attributes" => "Speciale attributen", "Quota Field" => "Quota veld", "Quota Default" => "Quota standaard", diff --git a/apps/user_ldap/l10n/pl.php b/apps/user_ldap/l10n/pl.php index 5c6d3d7022e..988e44dbe38 100644 --- a/apps/user_ldap/l10n/pl.php +++ b/apps/user_ldap/l10n/pl.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Kopia zapasowa (repliki) Port", "Disable Main Server" => "Wyłącz serwer główny", "Only connect to the replica server." => "Połącz tylko do repliki serwera.", -"Case insensitve LDAP server (Windows)" => "Wielkość liter serwera LDAP (Windows)", +"Case insensitive LDAP server (Windows)" => "Serwer LDAP nie rozróżniający wielkości liter (Windows)", "Turn off SSL certificate validation." => "Wyłączyć sprawdzanie poprawności certyfikatu SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Nie polecane, używać tylko w celu testowania! Jeśli połączenie działa tylko z tą opcją, zaimportuj certyfikat SSL serwera LDAP na swój %s.", "Cache Time-To-Live" => "Przechowuj czas życia", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Członek grupy stowarzyszenia", "Nested Groups" => "Grupy zagnieżdżone", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Kiedy włączone, grupy, które zawierają grupy, są wspierane. (Działa tylko, jeśli członek grupy ma ustawienie DNs)", +"Paging chunksize" => "Wielkość stronicowania", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Długość łańcucha jest używana do stronicowanych wyszukiwań LDAP, które mogą zwracać duże zbiory jak lista grup, czy użytkowników. (Ustawienie na 0 wyłącza stronicowane wyszukiwania w takich sytuacjach.)", "Special Attributes" => "Specjalne atrybuty", "Quota Field" => "Pole przydziału", "Quota Default" => "Przydział domyślny", diff --git a/apps/user_ldap/l10n/pt_BR.php b/apps/user_ldap/l10n/pt_BR.php index 786bee4c8ae..0c15694e3ff 100644 --- a/apps/user_ldap/l10n/pt_BR.php +++ b/apps/user_ldap/l10n/pt_BR.php @@ -70,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Porta do Backup (Réplica)", "Disable Main Server" => "Desativar Servidor Principal", "Only connect to the replica server." => "Conectar-se somente ao servidor de réplica.", -"Case insensitve LDAP server (Windows)" => "Servidor LDAP sensível à caixa alta (Windows)", +"Case insensitive LDAP server (Windows)" => "Servidor LDAP(Windows) não distigue maiúscula de minúscula", "Turn off SSL certificate validation." => "Desligar validação de certificado SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Não recomendado, use-o somente para teste! Se a conexão só funciona com esta opção, importar o certificado SSL do servidor LDAP em seu servidor %s.", "Cache Time-To-Live" => "Cache Time-To-Live", @@ -90,6 +90,8 @@ $TRANSLATIONS = array( "Group-Member association" => "Associação Grupo-Membro", "Nested Groups" => "Grupos Aninhados", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Quando habilitado, os grupos que contêm os grupos são suportados. (Só funciona se o atributo de membro de grupo contém DNs.)", +"Paging chunksize" => "Bloco de paginação", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Tamanho do bloco usado para pesquisas LDAP paginados que podem retornar resultados volumosos como usuário ou grupo de enumeração. (Defini-lo 0 desativa paginada pesquisas LDAP nessas situações.)", "Special Attributes" => "Atributos Especiais", "Quota Field" => "Campo de Cota", "Quota Default" => "Cota Padrão", diff --git a/apps/user_ldap/l10n/pt_PT.php b/apps/user_ldap/l10n/pt_PT.php index 37142c8175a..e2754785c65 100644 --- a/apps/user_ldap/l10n/pt_PT.php +++ b/apps/user_ldap/l10n/pt_PT.php @@ -65,7 +65,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Porta do servidor de backup (Replica)", "Disable Main Server" => "Desactivar servidor principal", "Only connect to the replica server." => "Ligar apenas ao servidor de réplicas.", -"Case insensitve LDAP server (Windows)" => "Servidor LDAP (Windows) não sensível a maiúsculas.", "Turn off SSL certificate validation." => "Desligar a validação de certificado SSL.", "Cache Time-To-Live" => "Cache do tempo de vida dos objetos no servidor", "in seconds. A change empties the cache." => "em segundos. Uma alteração esvazia a cache.", diff --git a/apps/user_ldap/l10n/ro.php b/apps/user_ldap/l10n/ro.php index 0214be3f787..26394db0f85 100644 --- a/apps/user_ldap/l10n/ro.php +++ b/apps/user_ldap/l10n/ro.php @@ -19,7 +19,6 @@ $TRANSLATIONS = array( "Back" => "Înapoi", "Continue" => "Continuă", "Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Atenție Modulul PHP LDAP nu este instalat, infrastructura nu va funcționa. Contactează administratorul sistemului pentru al instala.", -"Case insensitve LDAP server (Windows)" => "Server LDAP insensibil la majuscule (Windows)", "Turn off SSL certificate validation." => "Oprește validarea certificatelor SSL ", "in seconds. A change empties the cache." => "în secunde. O schimbare curăță memoria tampon.", "User Display Name Field" => "Câmpul cu numele vizibil al utilizatorului", diff --git a/apps/user_ldap/l10n/ru.php b/apps/user_ldap/l10n/ru.php index d9685368cbc..2cf331d24c0 100644 --- a/apps/user_ldap/l10n/ru.php +++ b/apps/user_ldap/l10n/ru.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Порт резервного сервера", "Disable Main Server" => "Отключить главный сервер", "Only connect to the replica server." => "Подключаться только к серверу-реплике.", -"Case insensitve LDAP server (Windows)" => "Нечувствительный к регистру сервер LDAP (Windows)", "Turn off SSL certificate validation." => "Отключить проверку сертификата SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Не рекомендуется, используйте только в режиме тестирования! Если соединение работает только с этой опцией, импортируйте на ваш %s сервер SSL-сертификат сервера LDAP.", "Cache Time-To-Live" => "Кэш времени жизни", diff --git a/apps/user_ldap/l10n/sk_SK.php b/apps/user_ldap/l10n/sk_SK.php index 460064593ee..edda4244336 100644 --- a/apps/user_ldap/l10n/sk_SK.php +++ b/apps/user_ldap/l10n/sk_SK.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Záložný server (kópia) port", "Disable Main Server" => "Zakázať hlavný server", "Only connect to the replica server." => "Pripojiť sa len k záložnému serveru.", -"Case insensitve LDAP server (Windows)" => "LDAP server nerozlišuje veľkosť znakov (Windows)", "Turn off SSL certificate validation." => "Vypnúť overovanie SSL certifikátu.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Neodporúčané, použite iba pri testovaní! Pokiaľ spojenie funguje iba z daným nastavením, importujte SSL certifikát LDAP servera do vášho %s servera.", "Cache Time-To-Live" => "Životnosť objektov vo vyrovnávacej pamäti", diff --git a/apps/user_ldap/l10n/sl.php b/apps/user_ldap/l10n/sl.php index b2a21b6e029..54c91103a3e 100644 --- a/apps/user_ldap/l10n/sl.php +++ b/apps/user_ldap/l10n/sl.php @@ -67,7 +67,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Vrata varnostne kopije (replike)", "Disable Main Server" => "Onemogoči glavni strežnik", "Only connect to the replica server." => "Poveži le s podvojenim strežnikom.", -"Case insensitve LDAP server (Windows)" => "Strežnik LDAP ne upošteva velikosti črk (Windows)", "Turn off SSL certificate validation." => "Onemogoči določanje veljavnosti potrdila SSL.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Možnosti ni priporočljivo uporabiti; namenjena je zgolj preizkušanju! Če deluje povezava le s to možnostjo, je treba uvoziti potrdilo SSL strežnika LDAP na strežnik %s.", "Cache Time-To-Live" => "Predpomni podatke TTL", @@ -85,6 +84,7 @@ $TRANSLATIONS = array( "One Group Base DN per line" => "Eno osnovno ime skupine na vrstico", "Group Search Attributes" => "Skupinski atributi iskanja", "Group-Member association" => "Povezava član-skupina", +"Nested Groups" => "Gnezdene skupine", "Special Attributes" => "Posebni atributi", "Quota Field" => "Polje količinske omejitve", "Quota Default" => "Privzeta količinska omejitev", diff --git a/apps/user_ldap/l10n/sq.php b/apps/user_ldap/l10n/sq.php index 0f18ac02351..03ff204bbca 100644 --- a/apps/user_ldap/l10n/sq.php +++ b/apps/user_ldap/l10n/sq.php @@ -38,7 +38,6 @@ $TRANSLATIONS = array( "Give an optional backup host. It must be a replica of the main LDAP/AD server." => "Jepni një pritës rezervë. Duhet të jetë replikimi i serverit AD/LDAP kryesor.", "Backup (Replica) Port" => "Porta rezervë (Replika)", "Disable Main Server" => "Ç'aktivizoni serverin kryesor", -"Case insensitve LDAP server (Windows)" => " Server LDAP i pavëmëndshëm ndaj gërmëzimit të madh apo jo (Windows)", "Turn off SSL certificate validation." => "Ç'aktivizoni kontrollin e certifikatës SSL.", "Cache Time-To-Live" => "Cache Time-To-Live", "in seconds. A change empties the cache." => "në sekonda Ndryshimi boshatis 'cache'-n.", diff --git a/apps/user_ldap/l10n/sr.php b/apps/user_ldap/l10n/sr.php index d2ce2cf08b6..fb016fdd17e 100644 --- a/apps/user_ldap/l10n/sr.php +++ b/apps/user_ldap/l10n/sr.php @@ -14,7 +14,6 @@ $TRANSLATIONS = array( "Password" => "Лозинка", "For anonymous access, leave DN and Password empty." => "За анониман приступ, оставите поља DN и лозинка празним.", "Back" => "Назад", -"Case insensitve LDAP server (Windows)" => "LDAP сервер осетљив на велика и мала слова (Windows)", "Turn off SSL certificate validation." => "Искључите потврду SSL сертификата.", "in seconds. A change empties the cache." => "у секундама. Промена испражњава кеш меморију.", "User Display Name Field" => "Име приказа корисника", diff --git a/apps/user_ldap/l10n/sv.php b/apps/user_ldap/l10n/sv.php index 0108cfcb0e4..2a4f8b19655 100644 --- a/apps/user_ldap/l10n/sv.php +++ b/apps/user_ldap/l10n/sv.php @@ -33,12 +33,14 @@ $TRANSLATIONS = array( "Save" => "Spara", "Test Configuration" => "Testa konfigurationen", "Help" => "Hjälp", +"Groups meeting these criteria are available in %s:" => "Grupper som uppfyller dessa kriterier finns i %s:", "only those object classes:" => "Endast de objekt-klasserna:", "only from those groups:" => "endast ifrån de här grupperna:", "Edit raw filter instead" => "Redigera rått filter istället", "Raw LDAP filter" => "Rått LDAP-filter", "The filter specifies which LDAP groups shall have access to the %s instance." => "Filtret specifierar vilka LDAD-grupper som ska ha åtkomst till %s instans", "groups found" => "grupper hittade", +"Users login with this attribute:" => "Användare loggar in med detta attribut:", "LDAP Username:" => "LDAP användarnamn:", "LDAP Email Address:" => "LDAP e-postadress:", "Other Attributes:" => "Övriga attribut:", @@ -53,6 +55,7 @@ $TRANSLATIONS = array( "For anonymous access, leave DN and Password empty." => "För anonym åtkomst, lämna DN och lösenord tomt.", "One Base DN per line" => "Ett Start DN per rad", "You can specify Base DN for users and groups in the Advanced tab" => "Du kan ange start DN för användare och grupper under fliken Avancerat", +"Limit %s access to users meeting these criteria:" => "Begränsa %s tillgång till användare som uppfyller dessa kriterier:", "The filter specifies which LDAP users shall have access to the %s instance." => "Filtret specifierar vilka LDAP-användare som skall ha åtkomst till %s instans", "users found" => "användare funna", "Back" => "Tillbaka", @@ -67,7 +70,7 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "Säkerhetskopierins-port (Replika)", "Disable Main Server" => "Inaktivera huvudserver", "Only connect to the replica server." => "Anslut endast till replikaservern.", -"Case insensitve LDAP server (Windows)" => "LDAP-servern är okänslig för gemener och versaler (Windows)", +"Case insensitive LDAP server (Windows)" => "om okänslig LDAP-server (Windows)", "Turn off SSL certificate validation." => "Stäng av verifiering av SSL-certifikat.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Rekommenderas inte, använd endast för test! Om anslutningen bara fungerar med denna inställning behöver du importera LDAP-serverns SSL-certifikat till din %s server.", "Cache Time-To-Live" => "Cache Time-To-Live", @@ -85,6 +88,10 @@ $TRANSLATIONS = array( "One Group Base DN per line" => "En Grupp start DN per rad", "Group Search Attributes" => "Gruppsökningsattribut", "Group-Member association" => "Attribut för gruppmedlemmar", +"Nested Groups" => "Undergrupper", +"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "När den är påslagen, stöds grupper som innehåller grupper. (Fungerar endast om gruppmedlemmens attribut innehåller DNs.)", +"Paging chunksize" => "Paging klusterstorlek", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Klusterstorlek som används för paged LDAP sökningar som kan komma att returnera skrymmande resultat som uppräknande av användare eller grupper. (Inställning av denna till 0 inaktiverar paged LDAP sökningar i de situationerna)", "Special Attributes" => "Specialattribut", "Quota Field" => "Kvotfält", "Quota Default" => "Datakvot standard", diff --git a/apps/user_ldap/l10n/ta_LK.php b/apps/user_ldap/l10n/ta_LK.php index c7efcf05894..27a3068f963 100644 --- a/apps/user_ldap/l10n/ta_LK.php +++ b/apps/user_ldap/l10n/ta_LK.php @@ -13,7 +13,6 @@ $TRANSLATIONS = array( "Password" => "கடவுச்சொல்", "You can specify Base DN for users and groups in the Advanced tab" => "நீங்கள் பயனாளர்களுக்கும் மேன்மை தத்தலில் உள்ள குழுவிற்கும் தள DN ஐ குறிப்பிடலாம் ", "Back" => "பின்னுக்கு", -"Case insensitve LDAP server (Windows)" => "உணர்ச்சியான LDAP சேவையகம் (சாளரங்கள்)", "Turn off SSL certificate validation." => "SSL சான்றிதழின் செல்லுபடியை நிறுத்திவிடவும்", "in seconds. A change empties the cache." => "செக்கன்களில். ஒரு மாற்றம் இடைமாற்றுநினைவகத்தை வெற்றிடமாக்கும்.", "User Display Name Field" => "பயனாளர் காட்சிப்பெயர் புலம்", diff --git a/apps/user_ldap/l10n/th_TH.php b/apps/user_ldap/l10n/th_TH.php index 2202a2f0a83..1c6dbe0473f 100644 --- a/apps/user_ldap/l10n/th_TH.php +++ b/apps/user_ldap/l10n/th_TH.php @@ -31,7 +31,6 @@ $TRANSLATIONS = array( "Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "คำเตือน: โมดูล PHP LDAP ยังไม่ได้ถูกติดตั้ง, ระบบด้านหลังจะไม่สามารถทำงานได้ กรุณาติดต่อผู้ดูแลระบบของคุณเพื่อทำการติดตั้งโมดูลดังกล่าว", "Connection Settings" => "ตั้งค่าการเชื่อมต่อ", "Disable Main Server" => "ปิดใช้งานเซิร์ฟเวอร์หลัก", -"Case insensitve LDAP server (Windows)" => "เซิร์ฟเวอร์ LDAP ประเภท Case insensitive (วินโดวส์)", "Turn off SSL certificate validation." => "ปิดใช้งานการตรวจสอบความถูกต้องของใบรับรองความปลอดภัย SSL", "in seconds. A change empties the cache." => "ในอีกไม่กี่วินาที ระบบจะเปลี่ยนแปลงข้อมูลในแคชให้ว่างเปล่า", "Directory Settings" => "ตั้งค่าไดเร็กทอรี่", diff --git a/apps/user_ldap/l10n/tr.php b/apps/user_ldap/l10n/tr.php index fa829a7427c..48e39c8523c 100644 --- a/apps/user_ldap/l10n/tr.php +++ b/apps/user_ldap/l10n/tr.php @@ -45,51 +45,53 @@ $TRANSLATIONS = array( "LDAP Email Address:" => "LDAP E-posta Adresi:", "Other Attributes:" => "Diğer Nitelikler", "Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" => "Oturum açma girişimi olduğunda uygulanacak filtreyi tanımlar. %%uid, oturum işleminde kullanıcı adı ile değiştirilir. Örneğin: \"uid=%%uid\"", -"Add Server Configuration" => "Sunucu Uyunlama birlemek ", +"Add Server Configuration" => "Sunucu Yapılandırması Ekle", "Host" => "Sunucu", -"You can omit the protocol, except you require SSL. Then start with ldaps://" => "Protokol atlamak edesin, sadece SSL istiyorsaniz. O zaman, idapsile baslamak. ", +"You can omit the protocol, except you require SSL. Then start with ldaps://" => "SSL gerektirmediğiniz takdirde protokol belirtmeyebilirsiniz. Ardından ldaps:// ile başlayın", "Port" => "Port", "User DN" => "Kullanıcı DN", -"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN musterinin, kimle baglamaya yapacagiz,meselâ uid=agent.dc mesela, dc=com Gecinme adisiz ici, DN ve Parola bos birakmak. ", +"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "İstemci kullanıcısının yapılacağı atamanın DN'i örn. uid=agent,dc=örnek,dc=com. Anonim erişim için DN ve Parolayı boş bırakın.", "Password" => "Parola", "For anonymous access, leave DN and Password empty." => "Anonim erişim için DN ve Parola alanlarını boş bırakın.", -"One Base DN per line" => "Bir Tabani DN herbir dizi. ", -"You can specify Base DN for users and groups in the Advanced tab" => "Base DN kullanicileri ve kaynaklari icin tablosu Advanced tayin etmek ederiz. ", +"One Base DN per line" => "Her satırda tek bir Base DN", +"You can specify Base DN for users and groups in the Advanced tab" => "Gelişmiş sekmesinde kullanıcılar ve gruplar için Base DN belirtebilirsiniz.", "Limit %s access to users meeting these criteria:" => "%s erişimini, şu kriterle eşleşen kullanıcılara sınırla:", "The filter specifies which LDAP users shall have access to the %s instance." => "Filtre, %s örneğine erişmesi gereken LDAP kullanıcılarını belirtir.", "users found" => "kullanıcı bulundu", "Back" => "Geri", "Continue" => "Devam et", "Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behavior. Please ask your system administrator to disable one of them." => "Uyarı: user_ldap ve user_webdavauth uygulamaları uyumlu değil. Beklenmedik bir davranışla karşılaşabilirsiniz. Lütfen ikisinden birini devre dışı bırakmak için sistem yöneticinizle iletişime geçin.", -"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Ihbar Modulu PHP LDAP yuklemdi degil, backend calismacak. Lutfen sistem yonetici sormak yuklemek icin.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Uyarı: PHP LDAP modülü kurulu değil, arka uç çalışmayacak. Lütfen kurulumu için sistem yöneticinizle iletişime geçin.", "Connection Settings" => "Bağlantı ayarları", "Configuration Active" => "Yapılandırma Etkin", -"When unchecked, this configuration will be skipped." => "Ne zaman iptal, bu uynnlama isletici ", -"Backup (Replica) Host" => "Sigorta Kopya Cephe ", -"Give an optional backup host. It must be a replica of the main LDAP/AD server." => "Bir kopya cevre vermek, kopya sunucu onemli olmali. ", -"Backup (Replica) Port" => "Kopya Port ", +"When unchecked, this configuration will be skipped." => "İşaretli değilse, bu yapılandırma atlanacaktır.", +"Backup (Replica) Host" => "Yedek (Replica) Sunucu", +"Give an optional backup host. It must be a replica of the main LDAP/AD server." => "İsteğe bağlı bir yedek sunucusu belirtin. Ana LDAP/AD sunucusunun bir kopyası olmalıdır.", +"Backup (Replica) Port" => "Yedek (Replica) Bağlantı Noktası", "Disable Main Server" => "Ana sunucuyu devredışı birak", "Only connect to the replica server." => "Sadece kopya sunucuya bağlan.", -"Case insensitve LDAP server (Windows)" => "Dusme sunucu LDAP zor degil. (Windows)", +"Case insensitive LDAP server (Windows)" => "Büyük küçük harf duyarsız LDAP sunucusu (Windows)", "Turn off SSL certificate validation." => "SSL sertifika doğrulamasını kapat.", "Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." => "Önerilmez, sadece test için kullanın! Eğer bağlantı sadece bu seçenekle çalışıyorsa %s sunucunuza LDAP sunucusunun SSL sertifikasını ekleyin.", -"Cache Time-To-Live" => "Cache Time-To-Live ", +"Cache Time-To-Live" => "Önbellek Time-To-Live Değeri", "in seconds. A change empties the cache." => "saniye cinsinden. Bir değişiklik önbelleği temizleyecektir.", -"Directory Settings" => "Parametrar Listesin Adresinin ", -"User Display Name Field" => "Ekran Adi Kullanici, (Alan Adi Kullanici Ekrane)", +"Directory Settings" => "Dizin Ayarları", +"User Display Name Field" => "Kullanıcı Görünen Ad Alanı", "The LDAP attribute to use to generate the user's display name." => "Kullanıcının görünen adını oluşturmak için kullanılacak LDAP niteliği.", "Base User Tree" => "Temel Kullanıcı Ağacı", -"One User Base DN per line" => "Bir Temel Kullanici DN her dizgi ", -"User Search Attributes" => "Kategorii Arama Kullanici ", +"One User Base DN per line" => "Her satırda Tek Kullanıcı Base DN'i", +"User Search Attributes" => "Kullanıcı Arama Nitelikleri", "Optional; one attribute per line" => "Tercihe bağlı; her bir satırda bir öznitelik", -"Group Display Name Field" => "Grub Ekrane Alani Adi", +"Group Display Name Field" => "Grup Görünen Ad Alanı", "The LDAP attribute to use to generate the groups's display name." => "Grubun görünen adını oluşturmak için kullanılacak LDAP niteliği.", "Base Group Tree" => "Temel Grup Ağacı", -"One Group Base DN per line" => "Bir Grubu Tabani DN her dizgi. ", -"Group Search Attributes" => "Kategorii Arama Grubu", +"One Group Base DN per line" => "Her satırda Tek Grup Base DN'i", +"Group Search Attributes" => "Grup Arama Nitelikleri", "Group-Member association" => "Grup-Üye işbirliği", "Nested Groups" => "İç içe Gruplar", "When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Etkinleştirildiğinde, grup içeren gruplar desteklenir (Sadece grup üyesi DN niteliği içeriyorsa çalışır).", +"Paging chunksize" => "Sayfalama yığın boyutu", +"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "Yığın boyutu, kullanıcı veya grup numaralandırması benzeri hantal sonuçlar döndürebilen sayfalandırılmış LDAP aramaları için kullanılır. (0 yapmak bu durumlarda sayfalandırılmış LDAP aramalarını devre dışı bırakır.)", "Special Attributes" => "Özel Öznitelikler", "Quota Field" => "Kota Alanı", "Quota Default" => "Öntanımlı Kota", diff --git a/apps/user_ldap/l10n/uk.php b/apps/user_ldap/l10n/uk.php index e87348ec44d..5f4db6d5a03 100644 --- a/apps/user_ldap/l10n/uk.php +++ b/apps/user_ldap/l10n/uk.php @@ -39,7 +39,6 @@ $TRANSLATIONS = array( "Give an optional backup host. It must be a replica of the main LDAP/AD server." => "Вкажіть додатковий резервний сервер. Він повинен бути копією головного LDAP/AD сервера.", "Backup (Replica) Port" => "Порт сервера для резервних копій", "Disable Main Server" => "Вимкнути Головний Сервер", -"Case insensitve LDAP server (Windows)" => "Нечутливий до регістру LDAP сервер (Windows)", "Turn off SSL certificate validation." => "Вимкнути перевірку SSL сертифіката.", "Cache Time-To-Live" => "Час актуальності Кеша", "in seconds. A change empties the cache." => "в секундах. Зміна очищує кеш.", diff --git a/apps/user_ldap/l10n/vi.php b/apps/user_ldap/l10n/vi.php index 84d001cb596..21b9783897e 100644 --- a/apps/user_ldap/l10n/vi.php +++ b/apps/user_ldap/l10n/vi.php @@ -21,7 +21,6 @@ $TRANSLATIONS = array( "Connection Settings" => "Connection Settings", "Backup (Replica) Port" => "Cổng sao lưu (Replica)", "Disable Main Server" => "Tắt máy chủ chính", -"Case insensitve LDAP server (Windows)" => "Trường hợp insensitve LDAP máy chủ (Windows)", "Turn off SSL certificate validation." => "Tắt xác thực chứng nhận SSL", "in seconds. A change empties the cache." => "trong vài giây. Một sự thay đổi bộ nhớ cache.", "Directory Settings" => "Directory Settings", diff --git a/apps/user_ldap/l10n/zh_CN.php b/apps/user_ldap/l10n/zh_CN.php index aae100ef9ad..d56f394f644 100644 --- a/apps/user_ldap/l10n/zh_CN.php +++ b/apps/user_ldap/l10n/zh_CN.php @@ -42,7 +42,6 @@ $TRANSLATIONS = array( "Backup (Replica) Port" => "备份 (镜像) 端口", "Disable Main Server" => "禁用主服务器", "Only connect to the replica server." => "只能连接到复制服务器", -"Case insensitve LDAP server (Windows)" => "大小写敏感LDAP服务器(Windows)", "Turn off SSL certificate validation." => "关闭SSL证书验证", "Cache Time-To-Live" => "缓存存活时间", "in seconds. A change empties the cache." => "以秒计。修改将清空缓存。", diff --git a/apps/user_ldap/l10n/zh_TW.php b/apps/user_ldap/l10n/zh_TW.php index a7ae04cd167..a0975b92238 100644 --- a/apps/user_ldap/l10n/zh_TW.php +++ b/apps/user_ldap/l10n/zh_TW.php @@ -41,7 +41,6 @@ $TRANSLATIONS = array( "Give an optional backup host. It must be a replica of the main LDAP/AD server." => "可以選擇性設定備用主機,必須是 LDAP/AD 中央伺服器的複本。", "Backup (Replica) Port" => "備用(複本)連接埠", "Disable Main Server" => "停用主伺服器", -"Case insensitve LDAP server (Windows)" => "不區分大小寫的 LDAP 伺服器 (Windows)", "Turn off SSL certificate validation." => "關閉 SSL 憑證檢查", "Cache Time-To-Live" => "快取的存活時間", "in seconds. A change empties the cache." => "以秒為單位。變更後會清空快取。", diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index d42b1c05820..c9ed1e648a2 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -77,6 +77,7 @@ class Configuration { 'ldapExpertUUIDGroupAttr' => null, 'lastJpegPhotoLookup' => null, 'ldapNestedGroups' => false, + 'ldapPagingSize' => null, ); /** @@ -344,6 +345,7 @@ class Configuration { 'has_memberof_filter_support' => 0, 'last_jpegPhoto_lookup' => 0, 'ldap_nested_groups' => 0, + 'ldap_paging_size' => 500, ); } @@ -395,7 +397,8 @@ class Configuration { 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr', 'has_memberof_filter_support' => 'hasMemberOfFilterSupport', 'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup', - 'ldap_nested_groups' => 'ldapNestedGroups', + 'ldap_nested_groups' => 'ldapNestedGroups', + 'ldap_paging_size' => 'ldapPagingSize', ); return $array; } diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index e79090febc1..3854af617c1 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -869,12 +869,14 @@ class Wizard extends LDAPUtility { * @param string $attr the attribute of which a list of values shall be returned * @param $lfw bool, whether the last filter is a wildcard which shall not * be processed if there were already findings, defaults to true + * @param int $dnReadLimit the amount of how many DNs should be analyzed. + * The lower, the faster * @param string $maxF string. if not null, this variable will have the filter that * yields most result entries * @return mixed, an array with the values on success, false otherwise * */ - private function cumulativeSearchOnAttribute($filters, $attr, $lfw = true, &$maxF = null) { + public function cumulativeSearchOnAttribute($filters, $attr, $lfw = true, $dnReadLimit = 3, &$maxF = null) { $dnRead = array(); $foundItems = array(); $maxEntries = 0; @@ -884,11 +886,16 @@ class Wizard extends LDAPUtility { } $base = $this->configuration->ldapBase[0]; $cr = $this->getConnection(); - if(!is_resource($cr)) { + if(!$this->ldap->isResource($cr)) { return false; } + $lastFilter = null; + if(isset($filters[count($filters)-1])) { + $lastFilter = $filters[count($filters)-1]; + } foreach($filters as $filter) { - if($lfw && count($foundItems) > 0) { + if($lfw && $lastFilter === $filter && count($foundItems) > 0) { + //skip when the filter is a wildcard and results were found continue; } $rr = $this->ldap->search($cr, $base, $filter, array($attr)); @@ -902,8 +909,10 @@ class Wizard extends LDAPUtility { $maxEntries = $entries; $maxF = $filter; } + $dnReadCount = 0; do { $entry = $this->ldap->$getEntryFunc($cr, $rr); + $getEntryFunc = 'nextEntry'; if(!$this->ldap->isResource($entry)) { continue 2; } @@ -916,13 +925,14 @@ class Wizard extends LDAPUtility { $state = $this->getAttributeValuesFromEntry($attributes, $attr, $newItems); + $dnReadCount++; $foundItems = array_merge($foundItems, $newItems); $this->resultCache[$dn][$attr] = $newItems; $dnRead[] = $dn; - $getEntryFunc = 'nextEntry'; $rr = $entry; //will be expected by nextEntry next round - } while($state === self::LRESULT_PROCESSED_SKIP - || $this->ldap->isResource($entry)); + } while(($state === self::LRESULT_PROCESSED_SKIP + || $this->ldap->isResource($entry)) + && ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit)); } } @@ -950,9 +960,19 @@ class Wizard extends LDAPUtility { $objectclasses[$key] = $p.$value; } $maxEntryObjC = ''; + + //how deep to dig? + //When looking for objectclasses, testing few entries is sufficient, + //when looking for group we need to get all names, though. + if(strtolower($attr) === 'objectclass') { + $dig = 3; + } else { + $dig = 0; + } + $availableFeatures = $this->cumulativeSearchOnAttribute($objectclasses, $attr, - true, $maxEntryObjC); + true, $dig, $maxEntryObjC); if(is_array($availableFeatures) && count($availableFeatures) > 0) { natcasesort($availableFeatures); diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index 79c4ae224c3..0a111225a70 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -1,5 +1,5 @@
-
+
    $title) { ?>
  • @@ -23,7 +23,7 @@

    -

    >

    +

    >


@@ -37,6 +37,7 @@

+

t('Special Attributes'));?>

diff --git a/apps/user_ldap/tests/group_ldap.php b/apps/user_ldap/tests/group_ldap.php new file mode 100644 index 00000000000..ecbd42319e3 --- /dev/null +++ b/apps/user_ldap/tests/group_ldap.php @@ -0,0 +1,115 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ + +namespace OCA\user_ldap\tests; + +namespace OCA\user_ldap\tests; + +use \OCA\user_ldap\GROUP_LDAP as GroupLDAP; +use \OCA\user_ldap\lib\Access; +use \OCA\user_ldap\lib\Connection; +use \OCA\user_ldap\lib\ILDAPWrapper; + +class Test_Group_Ldap extends \PHPUnit_Framework_TestCase { + private function getAccessMock() { + static $conMethods; + static $accMethods; + + if(is_null($conMethods) || is_null($accMethods)) { + $conMethods = get_class_methods('\OCA\user_ldap\lib\Connection'); + $accMethods = get_class_methods('\OCA\user_ldap\lib\Access'); + } + $lw = $this->getMock('\OCA\user_ldap\lib\ILDAPWrapper'); + $connector = $this->getMock('\OCA\user_ldap\lib\Connection', + $conMethods, + array($lw, null, null)); + $access = $this->getMock('\OCA\user_ldap\lib\Access', + $accMethods, + array($connector, $lw)); + + return $access; + } + + private function enableGroups($access) { + $access->connection->expects($this->any()) + ->method('__get') + ->will($this->returnCallback(function($name) { +// if($name === 'ldapLoginFilter') { +// return '%uid'; +// } + return 1; + })); + } + + public function testCountEmptySearchString() { + $access = $this->getAccessMock(); + + $this->enableGroups($access); + + $access->expects($this->any()) + ->method('groupname2dn') + ->will($this->returnValue('cn=group,dc=foo,dc=bar')); + + $access->expects($this->any()) + ->method('readAttribute') + ->will($this->returnValue(array('u11', 'u22', 'u33', 'u34'))); + + $groupBackend = new GroupLDAP($access); + $users = $groupBackend->countUsersInGroup('group'); + + $this->assertSame(4, $users); + } + + public function testCountWithSearchString() { + $access = $this->getAccessMock(); + + $this->enableGroups($access); + + $access->expects($this->any()) + ->method('groupname2dn') + ->will($this->returnValue('cn=group,dc=foo,dc=bar')); + + $access->expects($this->any()) + ->method('readAttribute') + ->will($this->returnCallback(function($name) { + //the search operation will call readAttribute, thus we need + //to anaylze the "dn". All other times we just need to return + //something that is neither null or false, but once an array + //with the users in the group – so we do so all other times for + //simplicicity. + if(strpos($name, 'u') === 0) { + return strpos($name, '3'); + } + return array('u11', 'u22', 'u33', 'u34'); + })); + + $access->expects($this->any()) + ->method('dn2username') + ->will($this->returnValue('foobar')); + + $groupBackend = new GroupLDAP($access); + $users = $groupBackend->countUsersInGroup('group', '3'); + + $this->assertSame(2, $users); + } + +} \ No newline at end of file diff --git a/apps/user_ldap/tests/wizard.php b/apps/user_ldap/tests/wizard.php new file mode 100644 index 00000000000..2b5cabc705d --- /dev/null +++ b/apps/user_ldap/tests/wizard.php @@ -0,0 +1,210 @@ +. +* +*/ + +namespace OCA\user_ldap\tests; + +use \OCA\user_ldap\lib\Wizard; + +// use \OCA\user_ldap\USER_LDAP as UserLDAP; +// use \OCA\user_ldap\lib\Access; +// use \OCA\user_ldap\lib\Configuration; +// use \OCA\user_ldap\lib\ILDAPWrapper; + +class Test_Wizard extends \PHPUnit_Framework_TestCase { + public function setUp() { + //we need to make sure the consts are defined, otherwise tests will fail + //on systems without php5_ldap + $ldapConsts = array('LDAP_OPT_PROTOCOL_VERSION', + 'LDAP_OPT_REFERRALS', 'LDAP_OPT_NETWORK_TIMEOUT'); + foreach($ldapConsts as $const) { + if(!defined($const)) { + define($const, 42); + } + } + } + + private function getWizardAndMocks() { + static $conMethods; + + if(is_null($conMethods)) { + $conMethods = get_class_methods('\OCA\user_ldap\lib\Configuration'); + } + $lw = $this->getMock('\OCA\user_ldap\lib\ILDAPWrapper'); + $conf = $this->getMock('\OCA\user_ldap\lib\Configuration', + $conMethods, + array($lw, null, null)); + return array(new Wizard($conf, $lw), $conf, $lw); + } + + private function prepareLdapWrapperForConnections(&$ldap) { + $ldap->expects($this->once()) + ->method('connect') + //dummy value, usually invalid + ->will($this->returnValue(true)); + + $ldap->expects($this->exactly(3)) + ->method('setOption') + ->will($this->returnValue(true)); + + $ldap->expects($this->once()) + ->method('bind') + ->will($this->returnValue(true)); + + } + + public function testCumulativeSearchOnAttributeLimited() { + list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); + + $configuration->expects($this->any()) + ->method('__get') + ->will($this->returnCallback(function($name) { + if($name === 'ldapBase') { + return array('base'); + } + return null; + })); + + $this->prepareLdapWrapperForConnections($ldap); + + $ldap->expects($this->any()) + ->method('isResource') + ->will($this->returnValue(true)); + + $ldap->expects($this->exactly(2)) + ->method('search') + //dummy value, usually invalid + ->will($this->returnValue(true)); + + $ldap->expects($this->exactly(2)) + ->method('countEntries') + //an is_resource check will follow, so we need to return a dummy resource + ->will($this->returnValue(23)); + + //5 DNs per filter means 2x firstEntry and 8x nextEntry + $ldap->expects($this->exactly(2)) + ->method('firstEntry') + //dummy value, usually invalid + ->will($this->returnValue(true)); + + $ldap->expects($this->exactly(8)) + ->method('nextEntry') + //dummy value, usually invalid + ->will($this->returnValue(true)); + + $ldap->expects($this->exactly(10)) + ->method('getAttributes') + //dummy value, usually invalid + ->will($this->returnValue(array('cn' => array('foo'), 'count' => 1))); + + global $uidnumber; + $uidnumber = 1; + $ldap->expects($this->exactly(10)) + ->method('getDN') + //dummy value, usually invalid + ->will($this->returnCallback(function($a, $b) { + global $uidnumber; + return $uidnumber++; + })); + + # The following expectations are the real test # + $filters = array('f1', 'f2', '*'); + $wizard->cumulativeSearchOnAttribute($filters, 'cn', true, 5); + unset($uidnumber); + } + + public function testCumulativeSearchOnAttributeUnlimited() { + list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); + + $configuration->expects($this->any()) + ->method('__get') + ->will($this->returnCallback(function($name) { + if($name === 'ldapBase') { + return array('base'); + } + return null; + })); + + $this->prepareLdapWrapperForConnections($ldap); + + $ldap->expects($this->any()) + ->method('isResource') + ->will($this->returnCallback(function($r) { + if($r === true) { + return true; + } + if($r % 24 === 0) { + global $uidnumber; + $uidnumber++; + return false; + } + return true; + })); + + $ldap->expects($this->exactly(2)) + ->method('search') + //dummy value, usually invalid + ->will($this->returnValue(true)); + + $ldap->expects($this->exactly(2)) + ->method('countEntries') + //an is_resource check will follow, so we need to return a dummy resource + ->will($this->returnValue(23)); + + //5 DNs per filter means 2x firstEntry and 8x nextEntry + $ldap->expects($this->exactly(2)) + ->method('firstEntry') + //dummy value, usually invalid + ->will($this->returnCallback(function($r) { + global $uidnumber; + return $uidnumber; + })); + + $ldap->expects($this->exactly(46)) + ->method('nextEntry') + //dummy value, usually invalid + ->will($this->returnCallback(function($r) { + global $uidnumber; + return $uidnumber; + })); + + $ldap->expects($this->exactly(46)) + ->method('getAttributes') + //dummy value, usually invalid + ->will($this->returnValue(array('cn' => array('foo'), 'count' => 1))); + + global $uidnumber; + $uidnumber = 1; + $ldap->expects($this->exactly(46)) + ->method('getDN') + //dummy value, usually invalid + ->will($this->returnCallback(function($a, $b) { + global $uidnumber; + return $uidnumber++; + })); + + # The following expectations are the real test # + $filters = array('f1', 'f2', '*'); + $wizard->cumulativeSearchOnAttribute($filters, 'cn', true, 0); + unset($uidnumber); + } + +} \ No newline at end of file diff --git a/apps/user_webdavauth/appinfo/info.xml b/apps/user_webdavauth/appinfo/info.xml index 76b314e48aa..20c5909cc12 100755 --- a/apps/user_webdavauth/appinfo/info.xml +++ b/apps/user_webdavauth/appinfo/info.xml @@ -4,7 +4,7 @@ WebDAV user backend Authenticate users by a WebDAV call. You can use any WebDAV server, ownCloud server or other webserver to authenticate. It should return http 200 for right credentials and http 401 for wrong ones. - This app is not compatible to the LDAP user and group backend. + This app is not compatible with the LDAP user and group backend. AGPL Frank Karlitschek 4.93 diff --git a/apps/user_webdavauth/l10n/ast.php b/apps/user_webdavauth/l10n/ast.php new file mode 100644 index 00000000000..118fa2ce30f --- /dev/null +++ b/apps/user_webdavauth/l10n/ast.php @@ -0,0 +1,7 @@ + "Autenticación per aciu de WevDAV", +"Address: " => "Direición:", +"The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "Les credenciales d'usuariu van unviase a esta direición. Esti complementu verifica la rempuesta y va interpretar los códigos de rempuesta HTTP 401 y 403 como credenciales inválides y toles otres rempuestes como credenciales válides." +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/user_webdavauth/templates/settings.php b/apps/user_webdavauth/templates/settings.php index ad1701add8c..4596fdf3c78 100755 --- a/apps/user_webdavauth/templates/settings.php +++ b/apps/user_webdavauth/templates/settings.php @@ -1,9 +1,7 @@ - -
-

t('WebDAV Authentication'));?>

-

- - -
t('The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials.')); ?> -

+ +

t('WebDAV Authentication'));?>

+

+ + +
t('The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials.')); ?>

diff --git a/autotest.sh b/autotest.sh index b88e9cf68b4..4030fc0250e 100755 --- a/autotest.sh +++ b/autotest.sh @@ -139,7 +139,7 @@ function execute_tests { cd $BASEDIR # revert changes to tests/data - git checkout tests/data/* + git checkout tests/data # reset data directory rm -rf $DATADIR diff --git a/build/package.json b/build/package.json index c9ed7b96c6c..0c395839cf9 100644 --- a/build/package.json +++ b/build/package.json @@ -14,7 +14,9 @@ "karma": "*", "karma-jasmine": "*", "karma-junit-reporter": "*", - "karma-coverage": "*" + "karma-coverage": "*", + "karma-phantomjs-launcher": "*", + "phantomjs": "*" }, "engine": "node >= 0.8" } diff --git a/config/config.sample.php b/config/config.sample.php index 891c2eb5fa1..adcc175e2fa 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -41,7 +41,7 @@ $CONFIG = array( /* The automatic protocol detection of ownCloud can fail in certain reverse proxy situations. This option allows to manually override the protocol detection. For example "https" */ "overwriteprotocol" => "", -/* The automatic webroot detection of ownCloud can fail in certain reverse proxy situations. This option allows to manually override the automatic detection. For example "/domain.tld/ownCloud" */ +/* The automatic webroot detection of ownCloud can fail in certain reverse proxy situations. This option allows to manually override the automatic detection. For example "/domain.tld/ownCloud". The value "/" can be used to remove the root. */ "overwritewebroot" => "", /* The automatic detection of ownCloud can fail in certain reverse proxy situations. This option allows to define a manually override condition as regular expression for the remote ip address. For example "^10\.0\.0\.[1-3]$" */ @@ -276,6 +276,15 @@ $CONFIG = array( /* all css and js files will be served by the web server statically in one js file and ons css file*/ 'asset-pipeline.enabled' => false, - /* where mount.json file should be stored, defaults to data/mount.json */ - 'mount_file' => '', +/* where mount.json file should be stored, defaults to data/mount.json */ +'mount_file' => '', + +/* + * Location of the cache folder, defaults to "data/$user/cache" where "$user" is the current user. + * + * When specified, the format will change to "$cache_path/$user" where "$cache_path" is the configured + * cache directory and "$user" is the user. + * + */ +'cache_path' => '' ); diff --git a/console.php b/console.php index 25b8b312539..dd2c1026e47 100644 --- a/console.php +++ b/console.php @@ -8,7 +8,6 @@ use Symfony\Component\Console\Application; -$RUNTIME_NOAPPS = true; require_once 'lib/base.php'; // Don't do anything if ownCloud has not been installed yet @@ -22,6 +21,9 @@ if (!OC::$CLI) { exit(0); } +// load all apps to get all api routes properly setup +OC_App::loadApps(); + $defaults = new OC_Defaults; $application = new Application($defaults->getName(), \OC_Util::getVersionString()); require_once 'core/register_command.php'; diff --git a/core/ajax/share.php b/core/ajax/share.php index 3f04e1e4ad1..2b41bd8a5da 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -21,7 +21,6 @@ OC_JSON::checkLoggedIn(); OCP\JSON::callCheck(); -OC_App::loadApps(); $defaults = new \OCP\Defaults(); @@ -206,6 +205,34 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo OC_JSON::success(array('data' => array('reshare' => $reshare, 'shares' => $shares))); } break; + case 'getShareWithEmail': + $result = array(); + if (isset($_GET['search'])) { + $cm = OC::$server->getContactsManager(); + if (!is_null($cm) && $cm->isEnabled()) { + $contacts = $cm->search($_GET['search'], array('FN', 'EMAIL')); + foreach ($contacts as $contact) { + if (!isset($contact['EMAIL'])) { + continue; + } + + $emails = $contact['EMAIL']; + if (!is_array($emails)) { + $emails = array($emails); + } + + foreach($emails as $email) { + $result[] = array( + 'id' => $contact['id'], + 'email' => $email, + 'displayname' => $contact['FN'], + ); + } + } + } + } + OC_JSON::success(array('data' => $result)); + break; case 'getShareWith': if (isset($_GET['search'])) { $sharePolicy = OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); diff --git a/core/ajax/update.php b/core/ajax/update.php index 2a0cbb2036d..55e8ab15ec2 100644 --- a/core/ajax/update.php +++ b/core/ajax/update.php @@ -1,6 +1,5 @@ getUserManager(); return $userManager->countUsers(); } @@ -56,4 +55,4 @@ class Report extends Command { $userDirectories = $dataview->getDirectoryContent('/', 'httpd/unix-directory'); return count($userDirectories); } -} \ No newline at end of file +} diff --git a/core/css/apps.css b/core/css/apps.css index 0e6a080c9cd..a8dfc5b7ed1 100644 --- a/core/css/apps.css +++ b/core/css/apps.css @@ -29,10 +29,14 @@ -moz-box-sizing: border-box; box-sizing: border-box; } #app-navigation .active, -#app-navigation .active a, -#app-navigation li:hover > a { +#app-navigation .active a { background-color: #ddd; } +#app-navigation li:hover > a, +#app-navigation .selected, +#app-navigation .selected a { + background-color: #ccc; +} /* special rules for first-level entries and folders */ #app-navigation > ul > li { @@ -151,9 +155,6 @@ transition: padding-bottom 500ms ease 0s; padding-bottom: 40px; } -#app-navigation .personalblock > legend { /* TODO @Raydiation: still needed? */ - padding: 10px 0; margin: 0; -} #app-navigation .error { color: #dd1144; } @@ -242,3 +243,24 @@ button.loading { padding-right: 30px; } + +/* general styles for the content area */ +.section { + display: block; + padding: 30px; + color: #555; + border-top: 1px solid #ddd; +} +.section h2 { + font-size: 20px; + margin-bottom: 7px; +} +.section h3 { + font-size: 16px; +} +/* slight position correction of checkboxes and radio buttons */ +.section input[type="checkbox"], +.section input[type="radio"] { + vertical-align: -2px; + margin-right: 4px; +} diff --git a/core/css/auth.css b/core/css/auth.css deleted file mode 100644 index 70df9f0ae0f..00000000000 --- a/core/css/auth.css +++ /dev/null @@ -1,39 +0,0 @@ -h2 { - font-size:32px; - font-weight:700; - margin-bottom:16px; - white-space:nowrap; -} - -ul.scopes { - list-style:disc; -} - -ul.scopes li { - white-space:nowrap; -} - -h2 img { - width:50%; -} - -#oauth { - width:320px; - margin:64px auto 32px; -} - -#allow-auth { - background-color:#5c3; - box-shadow:0 1px 1px #fff, 0 1px 1px #5f3 inset; - color:#fff; - text-shadow:#5e3 0 1px 0; -} - -#deny-auth { - background:none; - border:0; - box-shadow:0 0 0 #fff, 0 0 0 #fff inset; - font-size:19px; - margin:11px; - padding:0; -} diff --git a/core/css/jquery.ocdialog.css b/core/css/jquery.ocdialog.css index 236968e3245..a1221137bc4 100644 --- a/core/css/jquery.ocdialog.css +++ b/core/css/jquery.ocdialog.css @@ -43,7 +43,7 @@ background-color: #000; opacity: .20;filter:Alpha(Opacity=20); z-index: 999; - position: absolute; + position: fixed; top: 0; left: 0; width: 100%; height: 100%; } diff --git a/core/css/mobile.css b/core/css/mobile.css index a63aa902d34..c67ac3e5ecf 100644 --- a/core/css/mobile.css +++ b/core/css/mobile.css @@ -1,4 +1,12 @@ -@media only screen and (max-width: 600px) { +@media only screen and (max-width: 768px) { + +/* show caret indicator next to logo to make clear it is tappable */ +#owncloud.menutoggle { + background-image: url('../img/actions/caret.svg'); + background-repeat: no-repeat; + background-position: right 26px; + padding-right: 16px !important; +} /* compress search box on mobile, expand when focused */ .searchbox input[type="search"] { @@ -18,5 +26,80 @@ display: none; } +/* toggle navigation */ +#content-wrapper { + padding-left: 0; +} + +#navigation { + top: 45px; + bottom: initial; + width: 255px; + max-height: 90%; + margin-top: 0; + top: 45px; + background-color: rgba(36, 40, 47, .97); + overflow-x: initial; + border-bottom-right-radius: 7px; + border-bottom: 1px #333 solid; + border-right: 1px #333 solid; + box-shadow: 0 0 7px rgba(29,45,68,.97); + display: none; +} +#navigation, #navigation * { + box-sizing:border-box; -moz-box-sizing:border-box; +} +#navigation li { + display: inline-block; +} +#navigation a { + width: 80px; + height: 80px; + display: inline-block; + text-align: center; + padding: 20px 0; +} +#navigation a span { + display: inline-block; + font-size: 13px; + padding-bottom: 0; + padding-left: 0; + width: 80px; +} +#navigation .icon { + margin: 0 auto; + padding: 0; +} +#navigation li:first-child .icon { + padding-top: 0; +} +/* Apps management as sticky footer */ +#navigation .wrapper { + min-height: initial; + margin: 0; +} +#apps-management, #navigation .push { + height: initial; +} + + + +/* shift to account for missing navigation */ +#body-user #controls, +#body-settings #controls { + padding-left: 0; +} + +/* don’t require a minimum width for controls bar */ +#controls { + min-width: initial !important; +} + +/* position share dropdown */ +#dropdown { + margin-right: 10% !important; + width: 80% !important; +} + } diff --git a/core/css/styles.css b/core/css/styles.css index bd8111ebc72..57e2c4479a1 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -77,6 +77,7 @@ body { background:#fefefe; font:normal .8em/1.6em "Helvetica Neue",Helvetica,Ari #header .logo { background-image: url(../img/logo.svg); + background-repeat: no-repeat; width: 250px; height: 118px; margin: 0 auto; @@ -84,6 +85,7 @@ body { background:#fefefe; font:normal .8em/1.6em "Helvetica Neue",Helvetica,Ari #header .logo-wide { background-image: url(../img/logo-wide.svg); + background-repeat: no-repeat; width: 147px; height: 32px; } @@ -99,11 +101,18 @@ input[type="time"], textarea, select, button, .button, +input[type="submit"], +input[type="button"], #quota, .pager li a { - width:10em; margin:.3em; padding:.6em .5em .4em; - font-size:1em; - background:#fff; color:#333; border:1px solid #ddd; outline:none; + width: 130px; + margin: 3px 3px 3px 0; + padding: 7px 6px 5px; + font-size: 13px; + background-color: #fff; + color: #333; + border: 1px solid #ddd; + outline: none; border-radius: 3px; } input[type="hidden"] { @@ -168,14 +177,12 @@ input[type="submit"], input[type="button"], button, .button, #quota, select, .pager li a { width: auto; - padding: .4em; + padding: 5px; background-color: rgba(240,240,240,.9); font-weight: bold; color: #555; border: 1px solid rgba(190,190,190,.9); cursor: pointer; - border-radius: 3px; - outline: none; } input[type="submit"]:hover, input[type="submit"]:focus, input[type="button"]:hover, input[type="button"]:focus, @@ -246,6 +253,7 @@ input[type="submit"].enabled { -webkit-box-sizing: border-box; box-sizing: border-box; position: fixed; + top:45px; right: 0; left: 0; height: 44px; @@ -275,6 +283,10 @@ input[type="submit"].enabled { padding: 7px 10px } +#controls .button.hidden { + display: none; +} + #content { position:relative; height:100%; width:100%; } #content .hascontrols { position: relative; @@ -790,20 +802,12 @@ tr .action { width:16px; height:16px; } tr:hover .action:hover, .selectedActions a:hover, .header-action:hover { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; } tbody tr:hover, tr:active { background-color:#f8f8f8; } -#body-settings h2 { - font-size: 20px; - font-weight: normal; - margin-bottom: 7px; -} -#body-settings .personalblock, #body-settings .helpblock { - padding: 30px; - color: #555; - border-top: 1px solid #ddd; -} -#body-settings .personalblock#quota { position:relative; padding:0; } -#body-settings #controls+.helpblock { position:relative; margin-top:3em; } code { font-family:"Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", monospace; } +#quota { + position: relative; + padding: 0; +} #quota div { padding: 0; background-color: rgb(220,220,220); @@ -922,6 +926,9 @@ div.crumb { background: url('../img/breadcrumb.svg') no-repeat right center; height: 44px; } +div.crumb.hidden { + display: none; +} div.crumb a, div.crumb span { position: relative; diff --git a/core/js/compatibility.js b/core/js/compatibility.js index 6548f95d42b..c07288857f2 100644 --- a/core/js/compatibility.js +++ b/core/js/compatibility.js @@ -148,3 +148,7 @@ function outerHTML(node){ return h; })(node); } + +// devicePixelRatio for IE10 +window.devicePixelRatio = window.devicePixelRatio || + window.screen.deviceXDPI / window.screen.logicalXDPI || 1; diff --git a/core/js/core.json b/core/js/core.json index 665e2485a90..05c2a17a679 100644 --- a/core/js/core.json +++ b/core/js/core.json @@ -6,7 +6,8 @@ "jquery-showpassword.js", "jquery.infieldlabel.js", "jquery.placeholder.js", - "jquery-tipsy.js" + "jquery-tipsy.js", + "underscore.js" ], "modules": [ "compatibility.js", diff --git a/core/js/jquery.avatar.js b/core/js/jquery.avatar.js index 381c42d9dbb..7c19cb321fe 100644 --- a/core/js/jquery.avatar.js +++ b/core/js/jquery.avatar.js @@ -77,7 +77,7 @@ var url = OC.generateUrl( '/avatar/{user}/{size}?requesttoken={requesttoken}', - {user: user, size: size, requesttoken: oc_requesttoken}); + {user: user, size: size * window.devicePixelRatio, requesttoken: oc_requesttoken}); $.get(url, function(result) { if (typeof(result) === 'object') { @@ -93,9 +93,9 @@ } else { $div.show(); if (ie8fix === true) { - $div.html(''); + $div.html(''); } else { - $div.html(''); + $div.html(''); } } if(typeof callback === 'function') { diff --git a/core/js/js.js b/core/js/js.js index 3d3185f12c1..f10c7163092 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -159,6 +159,7 @@ function escapeHTML(s) { * @param file The filename * @param dir The directory the file is in - e.g. $('#dir').val() * @return string +* @deprecated use Files.getDownloadURL() instead */ function fileDownloadPath(dir, file) { return OC.filePath('files', 'ajax', 'download.php')+'?files='+encodeURIComponent(file)+'&dir='+encodeURIComponent(dir); @@ -294,7 +295,7 @@ var OC={ */ imagePath:function(app,file){ if(file.indexOf('.')==-1){//if no extension is given, use png or svg depending on browser support - file+=(SVGSupport())?'.svg':'.png'; + file+=(OC.Util.hasSVGSupport())?'.svg':'.png'; } return OC.filePath(app,'img',file); }, @@ -371,6 +372,7 @@ var OC={ */ parseQueryString:function(queryString){ var parts, + pos, components, result = {}, key, @@ -378,12 +380,25 @@ var OC={ if (!queryString){ return null; } - if (queryString[0] === '?'){ - queryString = queryString.substr(1); + pos = queryString.indexOf('?'); + if (pos >= 0){ + queryString = queryString.substr(pos + 1); } - parts = queryString.split('&'); + parts = queryString.replace(/\+/g, '%20').split('&'); for (var i = 0; i < parts.length; i++){ - components = parts[i].split('='); + // split on first equal sign + var part = parts[i] + pos = part.indexOf('='); + if (pos >= 0) { + components = [ + part.substr(0, pos), + part.substr(pos + 1) + ] + } + else { + // key only + components = [part]; + } if (!components.length){ continue; } @@ -391,8 +406,14 @@ var OC={ if (!key){ continue; } - value = components[1]; - result[key] = value && decodeURIComponent(value); + // if equal sign was there, return string + if (components.length > 1) { + result[key] = decodeURIComponent(components[1]); + } + // no equal sign => null value + else { + result[key] = null; + } } return result; }, @@ -476,12 +497,59 @@ var OC={ throw e; }); } - if(!SVGSupport()) { - replaceSVG(); + if(!OC.Util.hasSVGSupport()) { + OC.Util.replaceSVG(); } }).show(); }, 'html'); } + }, + + // for menu toggling + registerMenu: function($toggle, $menuEl) { + $menuEl.addClass('menu'); + $toggle.addClass('menutoggle'); + $toggle.on('click.menu', function(event) { + if ($menuEl.is(OC._currentMenu)) { + $menuEl.hide(); + OC._currentMenu = null; + OC._currentMenuToggle = null; + return false; + } + // another menu was open? + else if (OC._currentMenu) { + // close it + OC._currentMenu.hide(); + } + $menuEl.show(); + OC._currentMenu = $menuEl; + OC._currentMenuToggle = $toggle; + return false + }); + }, + + unregisterMenu: function($toggle, $menuEl) { + // close menu if opened + if ($menuEl.is(OC._currentMenu)) { + $menuEl.hide(); + OC._currentMenu = null; + OC._currentMenuToggle = null; + } + $toggle.off('click.menu').removeClass('menutoggle'); + $menuEl.removeClass('menu'); + }, + + /** + * Wrapper for matchMedia + * + * This is makes it possible for unit tests to + * stub matchMedia (which doesn't work in PhantomJS) + */ + _matchMedia: function(media) { + if (window.matchMedia) { + return window.matchMedia(media); + } + return false; } }; OC.search.customResults={}; @@ -712,12 +780,12 @@ SVGSupport.checkMimeType=function(){ if(value[0]==='"'){ value=value.substr(1,value.length-2); } - headers[parts[0]]=value; + headers[parts[0].toLowerCase()]=value; } } }); - if(headers["Content-Type"]!=='image/svg+xml'){ - replaceSVG(); + if(headers["content-type"]!=='image/svg+xml'){ + OC.Util.replaceSVG(); SVGSupport.checkMimeType.correct=false; } } @@ -725,35 +793,10 @@ SVGSupport.checkMimeType=function(){ }; SVGSupport.checkMimeType.correct=true; -//replace all svg images with png for browser compatibility -function replaceSVG(){ - $('img.svg').each(function(index,element){ - element=$(element); - var src=element.attr('src'); - element.attr('src',src.substr(0,src.length-3)+'png'); - }); - $('.svg').each(function(index,element){ - element=$(element); - var background=element.css('background-image'); - if(background){ - var i=background.lastIndexOf('.svg'); - if(i>=0){ - background=background.substr(0,i)+'.png'+background.substr(i+4); - element.css('background-image',background); - } - } - element.find('*').each(function(index,element) { - element=$(element); - var background=element.css('background-image'); - if(background){ - var i=background.lastIndexOf('.svg'); - if(i>=0){ - background=background.substr(0,i)+'.png'+background.substr(i+4); - element.css('background-image',background); - } - } - }); - }); +// replace all svg images with png for browser compatibility +// @deprecated use OC.Util.replaceSVG instead +function replaceSVG($el){ + return OC.Util.replaceSVG($el); } /** @@ -831,8 +874,8 @@ function initCore() { initSessionHeartBeat(); } - if(!SVGSupport()){ //replace all svg images with png images for browser that dont support svg - replaceSVG(); + if(!OC.Util.hasSVGSupport()){ //replace all svg images with png images for browser that dont support svg + OC.Util.replaceSVG(); }else{ SVGSupport.checkMimeType(); } @@ -940,6 +983,67 @@ function initCore() { $('a.action').tipsy({gravity:'s', fade:true, live:true}); $('td .modified').tipsy({gravity:'s', fade:true, live:true}); $('input').tipsy({gravity:'w', fade:true}); + + // toggle for menus + $(document).on('mouseup.closemenus', function(event) { + var $el = $(event.target); + if ($el.closest('.menu').length || $el.closest('.menutoggle').length) { + // don't close when clicking on the menu directly or a menu toggle + return false; + } + if (OC._currentMenu) { + OC._currentMenu.hide(); + } + OC._currentMenu = null; + OC._currentMenuToggle = null; + }); + + + /** + * Set up the main menu toggle to react to media query changes. + * If the screen is small enough, the main menu becomes a toggle. + * If the screen is bigger, the main menu is not a toggle any more. + */ + function setupMainMenu() { + // toggle the navigation on mobile + if (!OC._matchMedia) { + return; + } + var mq = OC._matchMedia('(max-width: 768px)'); + var lastMatch = mq.matches; + var $toggle = $('#header #owncloud'); + var $navigation = $('#navigation'); + + function updateMainMenu() { + // mobile mode ? + if (lastMatch && !$toggle.hasClass('menutoggle')) { + // init the menu + OC.registerMenu($toggle, $navigation); + $toggle.data('oldhref', $toggle.attr('href')); + $toggle.attr('href', '#'); + $navigation.hide(); + } + else { + OC.unregisterMenu($toggle, $navigation); + $toggle.attr('href', $toggle.data('oldhref')); + $navigation.show(); + } + } + + updateMainMenu(); + + // TODO: debounce this + $(window).resize(function() { + if (lastMatch !== mq.matches) { + lastMatch = mq.matches; + updateMainMenu(); + } + }); + } + + if (window.matchMedia) { + setupMainMenu(); + } } $(document).ready(initCore); @@ -1005,6 +1109,72 @@ function relative_modified_date(timestamp) { else { return t('core','years ago'); } } +OC.Util = { + /** + * Returns whether the browser supports SVG + * + * @return true if the browser supports SVG, false otherwise + */ + // TODO: replace with original function + hasSVGSupport: SVGSupport, + /** + * If SVG is not supported, replaces the given icon's extension + * from ".svg" to ".png". + * If SVG is supported, return the image path as is. + * + * @param file image path with svg extension + * @return fixed image path with png extension if SVG is not + * supported + */ + replaceSVGIcon: function(file) { + if (!OC.Util.hasSVGSupport()) { + var i = file.lastIndexOf('.svg'); + if (i >= 0) { + file = file.substr(0, i) + '.png' + file.substr(i+4); + } + } + return file; + }, + /** + * Replace SVG images in all elements that have the "svg" class set + * with PNG images. + * + * @param $el root element from which to search, defaults to $('body') + */ + replaceSVG: function($el) { + if (!$el) { + $el = $('body'); + } + $el.find('img.svg').each(function(index,element){ + element=$(element); + var src=element.attr('src'); + element.attr('src',src.substr(0, src.length-3) + 'png'); + }); + $el.find('.svg').each(function(index,element){ + element = $(element); + var background = element.css('background-image'); + if (background){ + var i = background.lastIndexOf('.svg'); + if (i >= 0){ + background = background.substr(0,i) + '.png' + background.substr(i + 4); + element.css('background-image', background); + } + } + element.find('*').each(function(index, element) { + element = $(element); + var background = element.css('background-image'); + if (background) { + var i = background.lastIndexOf('.svg'); + if(i >= 0){ + background = background.substr(0,i) + '.png' + background.substr(i + 4); + element.css('background-image', background); + } + } + }); + }); + } +}; + /** * get a variable by name * @param string name diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js index d1bcb4659b8..11833f12e2d 100644 --- a/core/js/oc-dialogs.js +++ b/core/js/oc-dialogs.js @@ -19,6 +19,8 @@ * */ +/* global OC, t, alert */ + /** * this class to ease the usage of jquery dialogs */ @@ -27,7 +29,7 @@ var OCdialogs = { YES_NO_BUTTONS: 70, OK_BUTTONS: 71, // used to name each dialog - dialogs_counter: 0, + dialogsCounter: 0, /** * displays alert dialog * @param text content of dialog @@ -52,7 +54,8 @@ var OCdialogs = { * displays confirmation dialog * @param text content of dialog * @param title dialog title - * @param callback which will be triggered when user presses YES or NO (true or false would be passed to callback respectively) + * @param callback which will be triggered when user presses YES or NO + * (true or false would be passed to callback respectively) * @param modal make the dialog modal */ confirm:function(text, title, callback, modal) { @@ -63,21 +66,20 @@ var OCdialogs = { * @param title dialog title * @param callback which will be triggered when user presses Choose * @param multiselect whether it should be possible to select multiple files - * @param mimetype_filter mimetype to filter by + * @param mimetypeFilter mimetype to filter by * @param modal make the dialog modal */ - filepicker:function(title, callback, multiselect, mimetype_filter, modal) { + filepicker:function(title, callback, multiselect, mimetypeFilter, modal) { var self = this; $.when(this._getFilePickerTemplate()).then(function($tmpl) { - var dialog_name = 'oc-dialog-filepicker-content'; - var dialog_id = '#' + dialog_name; + var dialogName = 'oc-dialog-filepicker-content'; if(self.$filePicker) { self.$filePicker.ocdialog('close'); } self.$filePicker = $tmpl.octemplate({ - dialog_name: dialog_name, + dialog_name: dialogName, title: title - }).data('path', '').data('multiselect', multiselect).data('mimetype', mimetype_filter); + }).data('path', '').data('multiselect', multiselect).data('mimetype', mimetypeFilter); if (modal === undefined) { modal = false; @@ -85,8 +87,8 @@ var OCdialogs = { if (multiselect === undefined) { multiselect = false; } - if (mimetype_filter === undefined) { - mimetype_filter = ''; + if (mimetypeFilter === undefined) { + mimetypeFilter = ''; } $('body').append(self.$filePicker); @@ -131,13 +133,16 @@ var OCdialogs = { height: 420, modal: modal, buttons: buttonlist, - close: function(event, ui) { + close: function() { try { $(this).ocdialog('destroy').remove(); } catch(e) {} self.$filePicker = null; } }); + if (!OC.Util.hasSVGSupport()) { + OC.Util.replaceSVG(self.$filePicker.parent()); + } }) .fail(function(status, error) { // If the method is called while navigating away @@ -151,15 +156,15 @@ var OCdialogs = { * Displays raw dialog * You better use a wrapper instead ... */ - message:function(content, title, dialog_type, buttons, callback, modal) { + message:function(content, title, dialogType, buttons, callback, modal) { $.when(this._getMessageTemplate()).then(function($tmpl) { - var dialog_name = 'oc-dialog-' + OCdialogs.dialogs_counter + '-content'; - var dialog_id = '#' + dialog_name; + var dialogName = 'oc-dialog-' + OCdialogs.dialogsCounter + '-content'; + var dialogId = '#' + dialogName; var $dlg = $tmpl.octemplate({ - dialog_name: dialog_name, + dialog_name: dialogName, title: title, message: content, - type: dialog_type + type: dialogType }); if (modal === undefined) { modal = false; @@ -167,48 +172,48 @@ var OCdialogs = { $('body').append($dlg); var buttonlist = []; switch (buttons) { - case OCdialogs.YES_NO_BUTTONS: - buttonlist = [{ - text: t('core', 'Yes'), - click: function(){ - if (callback !== undefined) { - callback(true); - } - $(dialog_id).ocdialog('close'); - }, - defaultButton: true + case OCdialogs.YES_NO_BUTTONS: + buttonlist = [{ + text: t('core', 'Yes'), + click: function(){ + if (callback !== undefined) { + callback(true); + } + $(dialogId).ocdialog('close'); }, - { - text: t('core', 'No'), - click: function(){ - if (callback !== undefined) { - callback(false); - } - $(dialog_id).ocdialog('close'); + defaultButton: true + }, + { + text: t('core', 'No'), + click: function(){ + if (callback !== undefined) { + callback(false); } - }]; + $(dialogId).ocdialog('close'); + } + }]; break; - case OCdialogs.OK_BUTTON: - var functionToCall = function() { - $(dialog_id).ocdialog('close'); - if(callback !== undefined) { - callback(); - } - }; - buttonlist[0] = { - text: t('core', 'Ok'), - click: functionToCall, - defaultButton: true - }; + case OCdialogs.OK_BUTTON: + var functionToCall = function() { + $(dialogId).ocdialog('close'); + if(callback !== undefined) { + callback(); + } + }; + buttonlist[0] = { + text: t('core', 'Ok'), + click: functionToCall, + defaultButton: true + }; break; } - $(dialog_id).ocdialog({ + $(dialogId).ocdialog({ closeOnEscape: true, modal: modal, buttons: buttonlist }); - OCdialogs.dialogs_counter++; + OCdialogs.dialogsCounter++; }) .fail(function(status, error) { // If the method is called while navigating away from @@ -246,7 +251,7 @@ var OCdialogs = { image.onload = function () { var url = crop(image); deferred.resolve(url); - } + }; }; reader.readAsArrayBuffer(file); } else { @@ -294,7 +299,7 @@ var OCdialogs = { conflict.find('.replacement .mtime').text(formatDate(replacement.lastModifiedDate)); } var path = original.directory + '/' +original.name; - Files.lazyLoadPreview(path, original.mime, function(previewpath){ + Files.lazyLoadPreview(path, original.mimetype, function(previewpath){ conflict.find('.original .icon').css('background-image','url('+previewpath+')'); }, 96, 96, original.etag); getCroppedPreview(replacement).then( @@ -334,129 +339,133 @@ var OCdialogs = { //if (selection.defaultAction) { // controller[selection.defaultAction](data); //} else { - var dialog_name = 'oc-dialog-fileexists-content'; - var dialog_id = '#' + dialog_name; - if (this._fileexistsshown) { - // add conflict - - var conflicts = $(dialog_id+ ' .conflicts'); - addConflict(conflicts, original, replacement); + var dialogName = 'oc-dialog-fileexists-content'; + var dialogId = '#' + dialogName; + if (this._fileexistsshown) { + // add conflict + + var conflicts = $(dialogId+ ' .conflicts'); + addConflict(conflicts, original, replacement); + + var count = $(dialogId+ ' .conflict').length; + var title = n('core', + '{count} file conflict', + '{count} file conflicts', + count, + {count:count} + ); + $(dialogId).parent().children('.oc-dialog-title').text(title); + + //recalculate dimensions + $(window).trigger('resize'); - var count = $(dialog_id+ ' .conflict').length; - var title = n('files', - '{count} file conflict', - '{count} file conflicts', - count, - {count:count} - ); - $(dialog_id).parent().children('.oc-dialog-title').text(title); + } else { + //create dialog + this._fileexistsshown = true; + $.when(this._getFileExistsTemplate()).then(function($tmpl) { + var title = t('core','One file conflict'); + var $dlg = $tmpl.octemplate({ + dialog_name: dialogName, + title: title, + type: 'fileexists', + + allnewfiles: t('core','New Files'), + allexistingfiles: t('core','Already existing files'), + + why: t('core','Which files do you want to keep?'), + what: t('core','If you select both versions, the copied file will have a number added to its name.') + }); + $('body').append($dlg); - //recalculate dimensions - $(window).trigger('resize'); + var conflicts = $($dlg).find('.conflicts'); + addConflict(conflicts, original, replacement); - } else { - //create dialog - this._fileexistsshown = true; - $.when(this._getFileExistsTemplate()).then(function($tmpl) { - var title = t('files','One file conflict'); - var $dlg = $tmpl.octemplate({ - dialog_name: dialog_name, - title: title, - type: 'fileexists', - - why: t('files','Which files do you want to keep?'), - what: t('files','If you select both versions, the copied file will have a number added to its name.') - }); - $('body').append($dlg); - - var conflicts = $($dlg).find('.conflicts'); - addConflict(conflicts, original, replacement); - - buttonlist = [{ - text: t('core', 'Cancel'), - classes: 'cancel', - click: function(){ - if ( typeof controller.onCancel !== 'undefined') { - controller.onCancel(data); - } - $(dialog_id).ocdialog('close'); + var buttonlist = [{ + text: t('core', 'Cancel'), + classes: 'cancel', + click: function(){ + if ( typeof controller.onCancel !== 'undefined') { + controller.onCancel(data); } - }, - { - text: t('core', 'Continue'), - classes: 'continue', - click: function(){ - if ( typeof controller.onContinue !== 'undefined') { - controller.onContinue($(dialog_id + ' .conflict')); - } - $(dialog_id).ocdialog('close'); + $(dialogId).ocdialog('close'); + } + }, + { + text: t('core', 'Continue'), + classes: 'continue', + click: function(){ + if ( typeof controller.onContinue !== 'undefined') { + controller.onContinue($(dialogId + ' .conflict')); } - }]; - - $(dialog_id).ocdialog({ - width: 500, - closeOnEscape: true, - modal: true, - buttons: buttonlist, - closeButton: null, - close: function(event, ui) { - self._fileexistsshown = false; + $(dialogId).ocdialog('close'); + } + }]; + + $(dialogId).ocdialog({ + width: 500, + closeOnEscape: true, + modal: true, + buttons: buttonlist, + closeButton: null, + close: function() { + self._fileexistsshown = false; $(this).ocdialog('destroy').remove(); } - }); + }); - $(dialog_id).css('height','auto'); + $(dialogId).css('height','auto'); - //add checkbox toggling actions - $(dialog_id).find('.allnewfiles').on('click', function() { - var checkboxes = $(dialog_id).find('.conflict .replacement input[type="checkbox"]'); - checkboxes.prop('checked', $(this).prop('checked')); - }); - $(dialog_id).find('.allexistingfiles').on('click', function() { - var checkboxes = $(dialog_id).find('.conflict .original input[type="checkbox"]'); - checkboxes.prop('checked', $(this).prop('checked')); - }); - $(dialog_id).find('.conflicts').on('click', '.replacement,.original', function() { - var checkbox = $(this).find('input[type="checkbox"]'); - checkbox.prop('checked', !checkbox.prop('checked')); - }); - $(dialog_id).find('.conflicts').on('click', 'input[type="checkbox"]', function() { - var checkbox = $(this); - checkbox.prop('checked', !checkbox.prop('checked')); - }); + //add checkbox toggling actions + $(dialogId).find('.allnewfiles').on('click', function() { + var checkboxes = $(dialogId).find('.conflict .replacement input[type="checkbox"]'); + checkboxes.prop('checked', $(this).prop('checked')); + }); + $(dialogId).find('.allexistingfiles').on('click', function() { + var checkboxes = $(dialogId).find('.conflict .original input[type="checkbox"]'); + checkboxes.prop('checked', $(this).prop('checked')); + }); + $(dialogId).find('.conflicts').on('click', '.replacement,.original', function() { + var checkbox = $(this).find('input[type="checkbox"]'); + checkbox.prop('checked', !checkbox.prop('checked')); + }); + $(dialogId).find('.conflicts').on('click', 'input[type="checkbox"]', function() { + var checkbox = $(this); + checkbox.prop('checked', !checkbox.prop('checked')); + }); - //update counters - $(dialog_id).on('click', '.replacement,.allnewfiles', function() { - var count = $(dialog_id).find('.conflict .replacement input[type="checkbox"]:checked').length; - if (count === $(dialog_id+ ' .conflict').length) { - $(dialog_id).find('.allnewfiles').prop('checked', true); - $(dialog_id).find('.allnewfiles + .count').text(t('files','(all selected)')); - } else if (count > 0) { - $(dialog_id).find('.allnewfiles').prop('checked', false); - $(dialog_id).find('.allnewfiles + .count').text(t('files','({count} selected)',{count:count})); - } else { - $(dialog_id).find('.allnewfiles').prop('checked', false); - $(dialog_id).find('.allnewfiles + .count').text(''); - } - }); - $(dialog_id).on('click', '.original,.allexistingfiles', function(){ - var count = $(dialog_id).find('.conflict .original input[type="checkbox"]:checked').length; - if (count === $(dialog_id+ ' .conflict').length) { - $(dialog_id).find('.allexistingfiles').prop('checked', true); - $(dialog_id).find('.allexistingfiles + .count').text(t('files','(all selected)')); - } else if (count > 0) { - $(dialog_id).find('.allexistingfiles').prop('checked', false); - $(dialog_id).find('.allexistingfiles + .count').text(t('files','({count} selected)',{count:count})); - } else { - $(dialog_id).find('.allexistingfiles').prop('checked', false); - $(dialog_id).find('.allexistingfiles + .count').text(''); - } - }); - }) - .fail(function() { - alert(t('core', 'Error loading file exists template')); + //update counters + $(dialogId).on('click', '.replacement,.allnewfiles', function() { + var count = $(dialogId).find('.conflict .replacement input[type="checkbox"]:checked').length; + if (count === $(dialogId+ ' .conflict').length) { + $(dialogId).find('.allnewfiles').prop('checked', true); + $(dialogId).find('.allnewfiles + .count').text(t('core','(all selected)')); + } else if (count > 0) { + $(dialogId).find('.allnewfiles').prop('checked', false); + $(dialogId).find('.allnewfiles + .count').text(t('core','({count} selected)',{count:count})); + } else { + $(dialogId).find('.allnewfiles').prop('checked', false); + $(dialogId).find('.allnewfiles + .count').text(''); + } }); - } + $(dialogId).on('click', '.original,.allexistingfiles', function(){ + var count = $(dialogId).find('.conflict .original input[type="checkbox"]:checked').length; + if (count === $(dialogId+ ' .conflict').length) { + $(dialogId).find('.allexistingfiles').prop('checked', true); + $(dialogId).find('.allexistingfiles + .count').text(t('core','(all selected)')); + } else if (count > 0) { + $(dialogId).find('.allexistingfiles').prop('checked', false); + $(dialogId).find('.allexistingfiles + .count') + .text(t('core','({count} selected)',{count:count})); + } else { + $(dialogId).find('.allexistingfiles').prop('checked', false); + $(dialogId).find('.allexistingfiles + .count').text(''); + } + }); + }) + .fail(function() { + alert(t('core', 'Error loading file exists template')); + }); + } //} }, _getFilePickerTemplate: function() { @@ -514,20 +523,13 @@ var OCdialogs = { } return $.getJSON( - OC.filePath('files', 'ajax', 'rawlist.php'), + OC.filePath('files', 'ajax', 'list.php'), { dir: dir, mimetypes: JSON.stringify(mimeType) } ); }, - _determineValue: function(element) { - if ( $(element).attr('type') === 'checkbox' ) { - return element.checked; - } else { - return $(element).val(); - } - }, /** * fills the filepicker with files @@ -539,7 +541,7 @@ var OCdialogs = { this.$filelist.empty().addClass('loading'); this.$filePicker.data('path', dir); $.when(this._getFileList(dir, this.$filePicker.data('mimetype'))).then(function(response) { - $.each(response.data, function(index, file) { + $.each(response.data.files, function(index, file) { if (file.type === 'dir') { dirs.push(file); } else { @@ -555,13 +557,25 @@ var OCdialogs = { type: entry.type, dir: dir, filename: entry.name, - date: OC.mtime2date(entry.mtime) + date: OC.mtime2date(Math.floor(entry.mtime / 1000)) }); - $li.find('img').attr('src', entry.mimetype_icon); + if (entry.isPreviewAvailable) { + var urlSpec = { + file: dir + '/' + entry.name + }; + var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec); + $li.find('img').attr('src', previewUrl); + } + else { + $li.find('img').attr('src', OC.Util.replaceSVGIcon(entry.icon)); + } self.$filelist.append($li); }); self.$filelist.removeClass('loading'); + if (!OC.Util.hasSVGSupport()) { + OC.Util.replaceSVG(self.$filePicker.find('.dirtree')); + } }); }, /** @@ -607,7 +621,6 @@ var OCdialogs = { this.$filelist.find('.filepicker_element_selected').removeClass('filepicker_element_selected'); } $element.toggleClass('filepicker_element_selected'); - return; } else if ( $element.data('type') === 'dir' ) { this._fillFilePicker(this.$filePicker.data('path') + '/' + $element.data('entryname')); } diff --git a/core/js/share.js b/core/js/share.js index 9ee50ff6963..5cabc614563 100644 --- a/core/js/share.js +++ b/core/js/share.js @@ -48,7 +48,7 @@ OC.Share={ var action = $(file).find('.fileactions .action[data-action="Share"]'); var img = action.find('img').attr('src', image); action.addClass('permanent'); - action.html(' '+t('core', 'Shared')).prepend(img); + action.html(' '+t('core', 'Shared')+'').prepend(img); } else { var dir = $('#dir').val(); if (dir.length > 1) { @@ -63,7 +63,7 @@ OC.Share={ if (img.attr('src') != OC.imagePath('core', 'actions/public')) { img.attr('src', image); $(action).addClass('permanent'); - $(action).html(' '+t('core', 'Shared')).prepend(img); + $(action).html(' '+t('core', 'Shared')+'').prepend(img); } }); } @@ -103,10 +103,10 @@ OC.Share={ var img = action.find('img').attr('src', image); if (shares) { action.addClass('permanent'); - action.html(' '+ escapeHTML(t('core', 'Shared'))).prepend(img); + action.html(' '+ escapeHTML(t('core', 'Shared'))+'').prepend(img); } else { action.removeClass('permanent'); - action.html(' '+ escapeHTML(t('core', 'Share'))).prepend(img); + action.html(' '+ escapeHTML(t('core', 'Share'))+'').prepend(img); } } } @@ -331,6 +331,26 @@ OC.Share={ .append( insert ) .appendTo( ul ); }; + $('#email').autocomplete({ + minLength: 1, + source: function (search, response) { + $.get(OC.filePath('core', 'ajax', 'share.php'), { fetch: 'getShareWithEmail', search: search.term }, function(result) { + if (result.status == 'success' && result.data.length > 0) { + response(result.data); + } + }); + }, + select: function( event, item ) { + $('#email').val(item.item.email); + return false; + } + }) + .data("ui-autocomplete")._renderItem = function( ul, item ) { + return $( "
  • " ) + .append( "" + item.displayname + "
    " + item.email + "
    " ) + .appendTo( ul ); + }; + } else { html += ''; html += '
  • '; @@ -551,7 +571,7 @@ $(document).ready(function() { var itemType = $('#dropdown').data('item-type'); var itemSource = $('#dropdown').data('item-source'); var shareType = $li.data('share-type'); - var shareWith = $li.data('share-with'); + var shareWith = $li.attr('data-share-with'); OC.Share.unshare(itemType, itemSource, shareType, shareWith, function() { $li.remove(); var index = OC.Share.itemShares[shareType].indexOf(shareWith); @@ -597,7 +617,7 @@ $(document).ready(function() { OC.Share.setPermissions($('#dropdown').data('item-type'), $('#dropdown').data('item-source'), li.data('share-type'), - li.data('share-with'), + li.attr('data-share-with'), permissions); }); @@ -782,7 +802,7 @@ $(document).ready(function() { } var shareType = $li.data('share-type'); - var shareWith = $li.data('share-with'); + var shareWith = $li.attr('data-share-with'); $.post(OC.filePath('core', 'ajax', 'share.php'), {action: action, recipient: shareWith, shareType: shareType, itemSource: itemSource, itemType: itemType}, function(result) { if (result.status !== 'success') { diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js index 069546387c7..ccd9f7a1288 100644 --- a/core/js/tests/specs/coreSpec.js +++ b/core/js/tests/specs/coreSpec.js @@ -147,19 +147,19 @@ describe('Core base tests', function() { }); describe('Images', function() { it('Generates image path with given extension', function() { - var svgSupportStub = sinon.stub(window, 'SVGSupport', function() { return true; }); + var svgSupportStub = sinon.stub(OC.Util, 'hasSVGSupport', function() { return true; }); expect(OC.imagePath('core', 'somefile.jpg')).toEqual(OC.webroot + '/core/img/somefile.jpg'); expect(OC.imagePath(TESTAPP, 'somefile.jpg')).toEqual(TESTAPP_ROOT + '/img/somefile.jpg'); svgSupportStub.restore(); }); it('Generates image path with svg extension when svg support exists', function() { - var svgSupportStub = sinon.stub(window, 'SVGSupport', function() { return true; }); + var svgSupportStub = sinon.stub(OC.Util, 'hasSVGSupport', function() { return true; }); expect(OC.imagePath('core', 'somefile')).toEqual(OC.webroot + '/core/img/somefile.svg'); expect(OC.imagePath(TESTAPP, 'somefile')).toEqual(TESTAPP_ROOT + '/img/somefile.svg'); svgSupportStub.restore(); }); it('Generates image path with png ext when svg support is not available', function() { - var svgSupportStub = sinon.stub(window, 'SVGSupport', function() { return false; }); + var svgSupportStub = sinon.stub(OC.Util, 'hasSVGSupport', function() { return false; }); expect(OC.imagePath('core', 'somefile')).toEqual(OC.webroot + '/core/img/somefile.png'); expect(OC.imagePath(TESTAPP, 'somefile')).toEqual(TESTAPP_ROOT + '/img/somefile.png'); svgSupportStub.restore(); @@ -268,7 +268,72 @@ describe('Core base tests', function() { // still nothing expect(counter).toEqual(0); }); - + }); + describe('Parse query string', function() { + it('Parses query string from full URL', function() { + var query = OC.parseQueryString('http://localhost/stuff.php?q=a&b=x'); + expect(query).toEqual({q: 'a', b: 'x'}); + }); + it('Parses query string from query part alone', function() { + var query = OC.parseQueryString('q=a&b=x'); + expect(query).toEqual({q: 'a', b: 'x'}); + }); + it('Returns null hash when empty query', function() { + var query = OC.parseQueryString(''); + expect(query).toEqual(null); + }); + it('Returns empty hash when empty query with question mark', function() { + var query = OC.parseQueryString('?'); + expect(query).toEqual({}); + }); + it('Decodes regular query strings', function() { + var query = OC.parseQueryString('a=abc&b=def'); + expect(query).toEqual({ + a: 'abc', + b: 'def' + }); + }); + it('Ignores empty parts', function() { + var query = OC.parseQueryString('&q=a&&b=x&'); + expect(query).toEqual({q: 'a', b: 'x'}); + }); + it('Ignores lone equal signs', function() { + var query = OC.parseQueryString('&q=a&=&b=x&'); + expect(query).toEqual({q: 'a', b: 'x'}); + }); + it('Includes extra equal signs in value', function() { + var query = OC.parseQueryString('u=a=x&q=a=b'); + expect(query).toEqual({u: 'a=x', q: 'a=b'}); + }); + it('Decodes plus as space', function() { + var query = OC.parseQueryString('space+key=space+value'); + expect(query).toEqual({'space key': 'space value'}); + }); + it('Decodes special characters', function() { + var query = OC.parseQueryString('unicode=%E6%B1%89%E5%AD%97'); + expect(query).toEqual({unicode: '汉字'}); + query = OC.parseQueryString('b=spaace%20value&space%20key=normalvalue&slash%2Fthis=amp%26ersand'); + expect(query).toEqual({ + b: 'spaace value', + 'space key': 'normalvalue', + 'slash/this': 'amp&ersand' + }); + }); + it('Decodes empty values', function() { + var query = OC.parseQueryString('keywithemptystring=&keywithnostring'); + expect(query).toEqual({ + 'keywithemptystring': '', + 'keywithnostring': null + }); + }); + it('Does not interpret data types', function() { + var query = OC.parseQueryString('booleanfalse=false&booleantrue=true&number=123'); + expect(query).toEqual({ + 'booleanfalse': 'false', + 'booleantrue': 'true', + 'number': '123' + }); + }); }); describe('Generate Url', function() { it('returns absolute urls', function() { @@ -279,5 +344,135 @@ describe('Core base tests', function() { expect(OC.generateUrl('apps/files/download{file}', {file: '/Welcome.txt'})).toEqual(OC.webroot + '/index.php/apps/files/download/Welcome.txt'); }); }); + describe('Main menu mobile toggle', function() { + var oldMatchMedia; + var $toggle; + var $navigation; + + beforeEach(function() { + oldMatchMedia = OC._matchMedia; + // a separate method was needed because window.matchMedia + // cannot be stubbed due to a bug in PhantomJS: + // https://github.com/ariya/phantomjs/issues/12069 + OC._matchMedia = sinon.stub(); + $('#testArea').append('' + + ''); + $toggle = $('#owncloud'); + $navigation = $('#navigation'); + }); + + afterEach(function() { + OC._matchMedia = oldMatchMedia; + }); + it('Sets up menu toggle in mobile mode', function() { + OC._matchMedia.returns({matches: true}); + window.initCore(); + expect($toggle.hasClass('menutoggle')).toEqual(true); + expect($navigation.hasClass('menu')).toEqual(true); + }); + it('Does not set up menu toggle in desktop mode', function() { + OC._matchMedia.returns({matches: false}); + window.initCore(); + expect($toggle.hasClass('menutoggle')).toEqual(false); + expect($navigation.hasClass('menu')).toEqual(false); + }); + it('Switches on menu toggle when mobile mode changes', function() { + var mq = {matches: false}; + OC._matchMedia.returns(mq); + window.initCore(); + expect($toggle.hasClass('menutoggle')).toEqual(false); + mq.matches = true; + $(window).trigger('resize'); + expect($toggle.hasClass('menutoggle')).toEqual(true); + }); + it('Switches off menu toggle when mobile mode changes', function() { + var mq = {matches: true}; + OC._matchMedia.returns(mq); + window.initCore(); + expect($toggle.hasClass('menutoggle')).toEqual(true); + mq.matches = false; + $(window).trigger('resize'); + expect($toggle.hasClass('menutoggle')).toEqual(false); + }); + it('Clicking menu toggle toggles navigation in mobile mode', function() { + OC._matchMedia.returns({matches: true}); + window.initCore(); + $navigation.hide(); // normally done through media query triggered CSS + expect($navigation.is(':visible')).toEqual(false); + $toggle.click(); + expect($navigation.is(':visible')).toEqual(true); + $toggle.click(); + expect($navigation.is(':visible')).toEqual(false); + }); + it('Clicking menu toggle does not toggle navigation in desktop mode', function() { + OC._matchMedia.returns({matches: false}); + window.initCore(); + expect($navigation.is(':visible')).toEqual(true); + $toggle.click(); + expect($navigation.is(':visible')).toEqual(true); + }); + it('Switching to mobile mode hides navigation', function() { + var mq = {matches: false}; + OC._matchMedia.returns(mq); + window.initCore(); + expect($navigation.is(':visible')).toEqual(true); + mq.matches = true; + $(window).trigger('resize'); + expect($navigation.is(':visible')).toEqual(false); + }); + it('Switching to desktop mode shows navigation', function() { + var mq = {matches: true}; + OC._matchMedia.returns(mq); + window.initCore(); + expect($navigation.is(':visible')).toEqual(false); + mq.matches = false; + $(window).trigger('resize'); + expect($navigation.is(':visible')).toEqual(true); + }); + it('Switch to desktop with opened menu then back to mobile resets toggle', function() { + var mq = {matches: true}; + OC._matchMedia.returns(mq); + window.initCore(); + expect($navigation.is(':visible')).toEqual(false); + $toggle.click(); + expect($navigation.is(':visible')).toEqual(true); + mq.matches = false; + $(window).trigger('resize'); + expect($navigation.is(':visible')).toEqual(true); + mq.matches = true; + $(window).trigger('resize'); + expect($navigation.is(':visible')).toEqual(false); + $toggle.click(); + expect($navigation.is(':visible')).toEqual(true); + }); + }); + describe('SVG extension replacement', function() { + var svgSupportStub; + + beforeEach(function() { + svgSupportStub = sinon.stub(OC.Util, 'hasSVGSupport'); + }); + afterEach(function() { + svgSupportStub.restore(); + }); + it('does not replace svg extension with png when SVG is supported', function() { + svgSupportStub.returns(true); + expect( + OC.Util.replaceSVGIcon('/path/to/myicon.svg?someargs=1') + ).toEqual( + '/path/to/myicon.svg?someargs=1' + ); + }); + it('replaces svg extension with png when SVG not supported', function() { + svgSupportStub.returns(false); + expect( + OC.Util.replaceSVGIcon('/path/to/myicon.svg?someargs=1') + ).toEqual( + '/path/to/myicon.png?someargs=1' + ); + }); + }); }); diff --git a/core/js/underscore.js b/core/js/underscore.js new file mode 100644 index 00000000000..ca61fdc3a4b --- /dev/null +++ b/core/js/underscore.js @@ -0,0 +1,1344 @@ +// Underscore.js 1.6.0 +// http://underscorejs.org +// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `exports` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + concat = ArrayProto.concat, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object via a string identifier, + // for Closure Compiler "advanced" mode. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root._ = _; + } + + // Current version. + _.VERSION = '1.6.0'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return obj; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, length = obj.length; i < length; i++) { + if (iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; + } + } + return obj; + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results.push(iterator.call(context, value, index, list)); + }); + return results; + }; + + var reduceError = 'Reduce of empty array with no initial value'; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError(reduceError); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var length = obj.length; + if (length !== +length) { + var keys = _.keys(obj); + length = keys.length; + } + each(obj, function(value, index, list) { + index = keys ? keys[--length] : --length; + if (!initial) { + memo = obj[index]; + initial = true; + } else { + memo = iterator.call(context, memo, obj[index], index, list); + } + }); + if (!initial) throw new TypeError(reduceError); + return memo; + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, predicate, context) { + var result; + any(obj, function(value, index, list) { + if (predicate.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, predicate, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context); + each(obj, function(value, index, list) { + if (predicate.call(context, value, index, list)) results.push(value); + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, predicate, context) { + return _.filter(obj, function(value, index, list) { + return !predicate.call(context, value, index, list); + }, context); + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, predicate, context) { + predicate || (predicate = _.identity); + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context); + each(obj, function(value, index, list) { + if (!(result = result && predicate.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, predicate, context) { + predicate || (predicate = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context); + each(obj, function(value, index, list) { + if (result || (result = predicate.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if the array or object contains a given value (using `===`). + // Aliased as `include`. + _.contains = _.include = function(obj, target) { + if (obj == null) return false; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + return any(obj, function(value) { + return value === target; + }); + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + return (isFunc ? method : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, _.property(key)); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + _.where = function(obj, attrs) { + return _.filter(obj, _.matches(attrs)); + }; + + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + _.findWhere = function(obj, attrs) { + return _.find(obj, _.matches(attrs)); + }; + + // Return the maximum element or (element-based computation). + // Can't optimize arrays of integers longer than 65,535 elements. + // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797) + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { + return Math.max.apply(Math, obj); + } + var result = -Infinity, lastComputed = -Infinity; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + if (computed > lastComputed) { + result = value; + lastComputed = computed; + } + }); + return result; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { + return Math.min.apply(Math, obj); + } + var result = Infinity, lastComputed = Infinity; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + if (computed < lastComputed) { + result = value; + lastComputed = computed; + } + }); + return result; + }; + + // Shuffle an array, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + _.shuffle = function(obj) { + var rand; + var index = 0; + var shuffled = []; + each(obj, function(value) { + rand = _.random(index++); + shuffled[index - 1] = shuffled[rand]; + shuffled[rand] = value; + }); + return shuffled; + }; + + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (obj.length !== +obj.length) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + + // An internal function to generate lookup iterators. + var lookupIterator = function(value) { + if (value == null) return _.identity; + if (_.isFunction(value)) return value; + return _.property(value); + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + iterator = lookupIterator(iterator); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value: value, + index: index, + criteria: iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(behavior) { + return function(obj, iterator, context) { + var result = {}; + iterator = lookupIterator(iterator); + each(obj, function(value, index) { + var key = iterator.call(context, value, index, obj); + behavior(result, key, value); + }); + return result; + }; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = group(function(result, key, value) { + _.has(result, key) ? result[key].push(value) : result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, key, value) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = group(function(result, key) { + _.has(result, key) ? result[key]++ : result[key] = 1; + }); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator, context) { + iterator = lookupIterator(iterator); + var value = iterator.call(context, obj); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >>> 1; + iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely create a real, live array from anything iterable. + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (obj.length === +obj.length) return _.map(obj, _.identity); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + if (obj == null) return 0; + return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + if ((n == null) || guard) return array[0]; + if (n < 0) return []; + return slice.call(array, 0, n); + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. The **guard** check allows it to work with `_.map`. + _.last = function(array, n, guard) { + if (array == null) return void 0; + if ((n == null) || guard) return array[array.length - 1]; + return slice.call(array, Math.max(array.length - n, 0)); + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, (n == null) || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, _.identity); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, output) { + if (shallow && _.every(input, _.isArray)) { + return concat.apply(output, input); + } + each(input, function(value) { + if (_.isArray(value) || _.isArguments(value)) { + shallow ? push.apply(output, value) : flatten(value, shallow, output); + } else { + output.push(value); + } + }); + return output; + }; + + // Flatten out an array, either recursively (by default), or just one level. + _.flatten = function(array, shallow) { + return flatten(array, shallow, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Split an array into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(array, predicate, context) { + predicate = lookupIterator(predicate); + var pass = [], fail = []; + each(array, function(elem) { + (predicate.call(context, elem) ? pass : fail).push(elem); + }); + return [pass, fail]; + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator, context) { + if (_.isFunction(isSorted)) { + context = iterator; + iterator = isSorted; + isSorted = false; + } + var initial = iterator ? _.map(array, iterator, context) : array; + var results = []; + var seen = []; + each(initial, function(value, index) { + if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { + seen.push(value); + results.push(array[index]); + } + }); + return results; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(_.flatten(arguments, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.contains(other, item); + }); + }); + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.contains(rest, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var length = _.max(_.pluck(arguments, 'length').concat(0)); + var results = new Array(length); + for (var i = 0; i < length; i++) { + results[i] = _.pluck(arguments, '' + i); + } + return results; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + if (list == null) return {}; + var result = {}; + for (var i = 0, length = list.length; i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i = 0, length = array.length; + if (isSorted) { + if (typeof isSorted == 'number') { + i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted); + } else { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); + for (; i < length; i++) if (array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item, from) { + if (array == null) return -1; + var hasIndex = from != null; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { + return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); + } + var i = (hasIndex ? from : array.length); + while (i--) if (array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(length); + + while(idx < length) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + _.bind = function(func, context) { + var args, bound; + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + ctor.prototype = null; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; + }; + }; + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. + _.partial = function(func) { + var boundArgs = slice.call(arguments, 1); + return function() { + var position = 0; + var args = boundArgs.slice(); + for (var i = 0, length = args.length; i < length; i++) { + if (args[i] === _) args[i] = arguments[position++]; + } + while (position < arguments.length) args.push(arguments[position++]); + return func.apply(this, args); + }; + }; + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length === 0) throw new Error('bindAll must be passed function names'); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(null, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + options || (options = {}); + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + if (last < wait) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); + var callNow = immediate && !timeout; + if (!timeout) { + timeout = setTimeout(later, wait); + } + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + memo = func.apply(this, arguments); + func = null; + return memo; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return _.partial(wrapper, func); + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var values = new Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } + return values; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var pairs = new Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + if (source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + } + }); + return obj; + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(obj) { + var copy = {}; + var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); + each(keys, function(key) { + if (key in obj) copy[key] = obj[key]; + }); + return copy; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj) { + var copy = {}; + var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); + for (var key in obj) { + if (!_.contains(keys, key)) copy[key] = obj[key]; + } + return copy; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + if (source) { + for (var prop in source) { + if (obj[prop] === void 0) obj[prop] = source[prop]; + } + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] == a) return bStack[length] == b; + } + // Objects with different constructors are not equivalent, but `Object`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && + _.isFunction(bCtor) && (bCtor instanceof bCtor)) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + if (!(result = eq(a[size], b[size], aStack, bStack))) break; + } + } + } else { + // Deep compare objects. + for (var key in a) { + if (_.has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return result; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, [], []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. + each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) == '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + + // Optimize `isFunction` if appropriate. + if (typeof (/./) !== 'function') { + _.isFunction = function(obj) { + return typeof obj === 'function'; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj != +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + _.constant = function(value) { + return function () { + return value; + }; + }; + + _.property = function(key) { + return function(obj) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of `key:value` pairs. + _.matches = function(attrs) { + return function(obj) { + if (obj === attrs) return true; //avoid comparing an object to itself. + for (var key in attrs) { + if (attrs[key] !== obj[key]) + return false; + } + return true; + } + }; + + // Run a function **n** times. + _.times = function(n, iterator, context) { + var accum = Array(Math.max(0, n)); + for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); + return accum; + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { return new Date().getTime(); }; + + // List of HTML entities for escaping. + var entityMap = { + escape: { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + } + }; + entityMap.unescape = _.invert(entityMap.escape); + + // Regexes containing the keys and values listed immediately above. + var entityRegexes = { + escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), + unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') + }; + + // Functions for escaping and unescaping strings to/from HTML interpolation. + _.each(['escape', 'unescape'], function(method) { + _[method] = function(string) { + if (string == null) return ''; + return ('' + string).replace(entityRegexes[method], function(match) { + return entityMap[method][match]; + }); + }; + }); + + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. + _.result = function(object, property) { + if (object == null) return void 0; + var value = object[property]; + return _.isFunction(value) ? value.call(object) : value; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + each(_.functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result.call(this, func.apply(_, args)); + }; + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function, which will delegate to the wrapper. + _.chain = function(obj) { + return _(obj).chain(); + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(obj) { + return this._chain ? _(obj).chain() : obj; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; + return result.call(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result.call(this, method.apply(this._wrapped, arguments)); + }; + }); + + _.extend(_.prototype, { + + // Start chaining a wrapped Underscore object. + chain: function() { + this._chain = true; + return this; + }, + + // Extracts the result from a wrapped and chained object. + value: function() { + return this._wrapped; + } + + }); + + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } +}).call(this); diff --git a/core/l10n/ast.php b/core/l10n/ast.php new file mode 100644 index 00000000000..0fcda328dc0 --- /dev/null +++ b/core/l10n/ast.php @@ -0,0 +1,77 @@ + "Base de datos anovada", +"Invalid image" => "Imaxe inválida", +"Sunday" => "Domingu", +"Monday" => "Llunes", +"Tuesday" => "Martes", +"Wednesday" => "Miércoles", +"Thursday" => "Xueves", +"Friday" => "Vienres", +"Saturday" => "Sábadu", +"January" => "Xineru", +"February" => "Febreru", +"March" => "Marzu", +"April" => "Abril", +"May" => "Mayu", +"June" => "Xunu", +"July" => "Xunetu", +"August" => "Agostu", +"September" => "Setiembre", +"October" => "Ochobre", +"November" => "Payares", +"December" => "Avientu", +"Settings" => "Axustes", +"seconds ago" => "fai segundos", +"_%n minute ago_::_%n minutes ago_" => array("fai %n minutu","fai %n minutos"), +"_%n hour ago_::_%n hours ago_" => array("fai %n hora","fai %n hores"), +"today" => "güei", +"yesterday" => "ayeri", +"_%n day ago_::_%n days ago_" => array("fai %n día","fai %n díes"), +"last month" => "mes caberu", +"_%n month ago_::_%n months ago_" => array("fai %n mes","fai %n meses"), +"months ago" => "fai meses", +"last year" => "añu caberu", +"years ago" => "fai años", +"Choose" => "Esbillar", +"Yes" => "Sí", +"No" => "Non", +"_{count} file conflict_::_{count} file conflicts_" => array("",""), +"Which files do you want to keep?" => "¿Qué ficheros quies caltener?", +"Cancel" => "Encaboxar", +"Continue" => "Continuar", +"Shared" => "Compartíu", +"Share" => "Compartir", +"Error" => "Fallu", +"Share link" => "Compartir enllaz", +"Password" => "Contraseña", +"Send" => "Unviar", +"group" => "grupu", +"Unshare" => "Dexar de compartir", +"notify by email" => "notificar per corréu", +"can edit" => "pue editar", +"access control" => "control d'accesu", +"create" => "crear", +"update" => "xubir", +"delete" => "desaniciar", +"share" => "compartir", +"Password protected" => "Contraseña protexida", +"Email sent" => "Corréu unviáu", +"Delete" => "Desaniciar", +"Add" => "Amestar", +"Edit tags" => "Editar etiquetes", +"Username" => "Nome d'usuariu", +"Reset" => "Reaniciar", +"For the best results, please consider using a GNU/Linux server instead." => "Pa los meyores resultaos, por favor considera l'usu d'un sirvidor GNU/Linux nel so llugar.", +"Personal" => "Personal", +"Users" => "Usuarios", +"Cheers!" => "¡Salú!", +"will be used" => "usaráse", +"Finishing …" => "Finando ...", +"Log out" => "Zarrar sesión", +"Lost your password?" => "¿Escaeciesti la to contraseña?", +"Log in" => "Aniciar sesión", +"Alternative Logins" => "Anicios de sesión alternativos", +"Thank you for your patience." => "Gracies pola to paciencia." +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/core/l10n/ca.php b/core/l10n/ca.php index 0a658d515d9..214b2eac0e9 100644 --- a/core/l10n/ca.php +++ b/core/l10n/ca.php @@ -50,6 +50,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Error en carregar la plantilla de missatge: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} conflicte de fitxer","{count} conflictes de fitxer"), "One file conflict" => "Un fitxer en conflicte", +"New Files" => "Fitxers nous", "Which files do you want to keep?" => "Quin fitxer voleu conservar?", "If you select both versions, the copied file will have a number added to its name." => "Si seleccioneu les dues versions, el fitxer copiat tindrà un número afegit al seu nom.", "Cancel" => "Cancel·la", diff --git a/core/l10n/cs_CZ.php b/core/l10n/cs_CZ.php index ffe34f78280..c21d904b233 100644 --- a/core/l10n/cs_CZ.php +++ b/core/l10n/cs_CZ.php @@ -50,6 +50,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Chyba při nahrávání šablony zprávy: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} souborový konflikt","{count} souborové konflikty","{count} souborových konfliktů"), "One file conflict" => "Jeden konflikt souboru", +"New Files" => "Nové soubory", "Which files do you want to keep?" => "Které soubory chcete ponechat?", "If you select both versions, the copied file will have a number added to its name." => "Pokud zvolíte obě verze, zkopírovaný soubor bude mít název doplněný o číslo.", "Cancel" => "Zrušit", diff --git a/core/l10n/da.php b/core/l10n/da.php index d3384dac432..c7bda6fd365 100644 --- a/core/l10n/da.php +++ b/core/l10n/da.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Fejl ved indlæsning af besked skabelon: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} filkonflikt","{count} filkonflikter"), "One file conflict" => "En filkonflikt", +"New Files" => "Nye filer", "Which files do you want to keep?" => "Hvilke filer ønsker du at beholde?", "If you select both versions, the copied file will have a number added to its name." => "Hvis du vælger begge versioner, vil den kopierede fil få tilføjet et nummer til sit navn.", "Cancel" => "Annuller", diff --git a/core/l10n/de.php b/core/l10n/de.php index 79edfb725d7..fabf35440cb 100644 --- a/core/l10n/de.php +++ b/core/l10n/de.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Fehler beim Laden der Nachrichtenvorlage: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} Dateikonflikt","{count} Dateikonflikte"), "One file conflict" => "Ein Dateikonflikt", +"New Files" => "Neue Dateien", +"Already existing files" => "Die Dateien existieren bereits", "Which files do you want to keep?" => "Welche Dateien möchtest Du behalten?", "If you select both versions, the copied file will have a number added to its name." => "Wenn Du beide Versionen auswählst, erhält die kopierte Datei eine Zahl am Ende des Dateinamens.", "Cancel" => "Abbrechen", diff --git a/core/l10n/de_CH.php b/core/l10n/de_CH.php index 42b8eb3bcea..eb2cfd233d3 100644 --- a/core/l10n/de_CH.php +++ b/core/l10n/de_CH.php @@ -40,6 +40,7 @@ $TRANSLATIONS = array( "No" => "Nein", "Ok" => "OK", "_{count} file conflict_::_{count} file conflicts_" => array("",""), +"New Files" => "Neue Dateien", "Cancel" => "Abbrechen", "Shared" => "Geteilt", "Share" => "Teilen", diff --git a/core/l10n/de_DE.php b/core/l10n/de_DE.php index a0877e792e2..a65714f26f6 100644 --- a/core/l10n/de_DE.php +++ b/core/l10n/de_DE.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Fehler beim Laden der Nachrichtenvorlage: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} Dateikonflikt","{count} Dateikonflikte"), "One file conflict" => "Ein Dateikonflikt", +"New Files" => "Neue Dateien", +"Already existing files" => "Die Dateien existieren bereits", "Which files do you want to keep?" => "Welche Dateien möchten Sie behalten?", "If you select both versions, the copied file will have a number added to its name." => "Wenn Sie beide Versionen auswählen, erhält die kopierte Datei eine Zahl am Ende des Dateinamens.", "Cancel" => "Abbrechen", diff --git a/core/l10n/el.php b/core/l10n/el.php index ed7792b7261..c899427ae30 100644 --- a/core/l10n/el.php +++ b/core/l10n/el.php @@ -1,5 +1,6 @@ "Η ημερομηνία λήξης είναι στο παρελθόν.", "Couldn't send mail to following users: %s " => "Αδυναμία αποστολής μηνύματος στους ακόλουθους χρήστες: %s", "Turned on maintenance mode" => "Η κατάσταση συντήρησης ενεργοποιήθηκε", "Turned off maintenance mode" => "Η κατάσταση συντήρησης απενεργοποιήθηκε", @@ -49,14 +50,17 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Σφάλμα φόρτωσης προτύπου μηνυμάτων: {σφάλμα}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} αρχείο διαφέρει","{count} αρχεία διαφέρουν"), "One file conflict" => "Ένα αρχείο διαφέρει", +"New Files" => "Νέα Αρχεία", "Which files do you want to keep?" => "Ποια αρχεία θέλετε να κρατήσετε;", "If you select both versions, the copied file will have a number added to its name." => "Εάν επιλέξετε και τις δυο εκδοχές, ένας αριθμός θα προστεθεί στο αντιγραφόμενο αρχείο.", "Cancel" => "Άκυρο", "Continue" => "Συνέχεια", "(all selected)" => "(όλα τα επιλεγμένα)", "({count} selected)" => "({count} επιλέχθησαν)", +"Error loading file exists template" => "Σφάλμα κατά την φόρτωση του προτύπου ύπαρξης αρχείου", "Very weak password" => "Πολύ αδύναμο συνθηματικό", "Weak password" => "Αδύναμο συνθηματικό", +"So-so password" => "Μέτριο συνθηματικό", "Good password" => "Καλό συνθηματικό", "Strong password" => "Δυνατό συνθηματικό", "Shared" => "Κοινόχρηστα", @@ -119,6 +123,8 @@ $TRANSLATIONS = array( "To login page" => "Σελίδα εισόδου", "New password" => "Νέο συνθηματικό", "Reset password" => "Επαναφορά συνθηματικού", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Το Mac OS X δεν υποστηρίζεται και το %s δεν θα λειτουργήσει σωστά σε αυτή την πλατφόρμα. Χρησιμοποιείτε με δική σας ευθύνη!", +"For the best results, please consider using a GNU/Linux server instead." => "Για καλύτερα αποτελέσματα, παρακαλούμε εξετάστε την μετατροπή σε έναν διακομιστή GNU/Linux.", "Personal" => "Προσωπικά", "Users" => "Χρήστες", "Apps" => "Εφαρμογές", @@ -144,6 +150,7 @@ $TRANSLATIONS = array( "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." => "Ο κατάλογος δεδομένων και τα αρχεία σας είναι πιθανό προσβάσιμα από το internet γιατί δεν δουλεύει το αρχείο .htaccess.", "For information how to properly configure your server, please see the documentation." => "Για πληροφορίες πως να ρυθμίσετε ορθά τον διακομιστή σας, παρακαλώ δείτε την τεκμηρίωση.", "Create an admin account" => "Δημιουργήστε έναν λογαριασμό διαχειριστή", +"Storage & database" => "Αποθήκευση & βάση δεδομένων", "Data folder" => "Φάκελος δεδομένων", "Configure the database" => "Ρύθμιση της βάσης δεδομένων", "will be used" => "θα χρησιμοποιηθούν", @@ -166,6 +173,7 @@ $TRANSLATIONS = array( "remember" => "απομνημόνευση", "Log in" => "Είσοδος", "Alternative Logins" => "Εναλλακτικές Συνδέσεις", +"Hey there,

    just letting you know that %s shared %s with you.
    View it!

    " => "Γειά χαρά,

    απλά σας ενημερώνω πως ο %s μοιράστηκε το%s με εσάς.
    Δείτε το!

    ", "This ownCloud instance is currently in single user mode." => "Αυτή η εγκατάσταση ownCloud είναι τώρα σε κατάσταση ενός χρήστη.", "This means only administrators can use the instance." => "Αυτό σημαίνει ότι μόνο διαχειριστές μπορούν να χρησιμοποιήσουν την εγκατάσταση.", "Contact your system administrator if this message persists or appeared unexpectedly." => "Επικοινωνήστε με το διαχειριστή του συστήματος αν αυτό το μήνυμα συνεχίζει να εμφανίζεται ή εμφανίστηκε απρόσμενα.", diff --git a/core/l10n/en_GB.php b/core/l10n/en_GB.php index bc36f5a4446..215bae92d1c 100644 --- a/core/l10n/en_GB.php +++ b/core/l10n/en_GB.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Error loading message template: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} file conflict","{count} file conflicts"), "One file conflict" => "One file conflict", +"New Files" => "New Files", +"Already existing files" => "Already existing files", "Which files do you want to keep?" => "Which files do you wish to keep?", "If you select both versions, the copied file will have a number added to its name." => "If you select both versions, the copied file will have a number added to its name.", "Cancel" => "Cancel", diff --git a/core/l10n/eo.php b/core/l10n/eo.php index f264b7ed7a7..05d28efb66b 100644 --- a/core/l10n/eo.php +++ b/core/l10n/eo.php @@ -41,6 +41,7 @@ $TRANSLATIONS = array( "Ok" => "Akcepti", "_{count} file conflict_::_{count} file conflicts_" => array("{count} dosierkonflikto","{count} dosierkonfliktoj"), "One file conflict" => "Unu dosierkonflikto", +"New Files" => "Novaj dosieroj", "Which files do you want to keep?" => "Kiujn dosierojn vi volas konservi?", "If you select both versions, the copied file will have a number added to its name." => "Se vi elektos ambaŭ eldonojn, la kopiota dosiero havos numeron aldonitan al sia nomo.", "Cancel" => "Nuligi", diff --git a/core/l10n/es.php b/core/l10n/es.php index 7f4d46aa1f1..cb2d09d60fe 100644 --- a/core/l10n/es.php +++ b/core/l10n/es.php @@ -1,6 +1,6 @@ "La fecha de caducidad está en el pasado.", +"Expiration date is in the past." => "Ha pasado la fecha de caducidad", "Couldn't send mail to following users: %s " => "No se pudo enviar el mensaje a los siguientes usuarios: %s", "Turned on maintenance mode" => "Modo mantenimiento activado", "Turned off maintenance mode" => "Modo mantenimiento desactivado", @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Error cargando plantilla del mensaje: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} conflicto de archivo","{count} conflictos de archivo"), "One file conflict" => "On conflicto de archivo", +"New Files" => "Nuevos Archivos", +"Already existing files" => "Archivos ya existentes", "Which files do you want to keep?" => "¿Que archivos deseas mantener?", "If you select both versions, the copied file will have a number added to its name." => "Si seleccionas ambas versiones, el archivo copiado tendrá añadido un número en su nombre.", "Cancel" => "Cancelar", @@ -105,7 +107,7 @@ $TRANSLATIONS = array( "Edit tags" => "Editar etiquetas", "Error loading dialog template: {error}" => "Error cargando plantilla de diálogo: {error}", "No tags selected for deletion." => "No hay etiquetas seleccionadas para borrar.", -"Please reload the page." => "Vuelva a cargar la página.", +"Please reload the page." => "Recargue/Actualice la página", "The update was unsuccessful. Please report this issue to the ownCloud community." => "La actualización ha fracasado. Por favor, informe de este problema a la Comunidad de ownCloud.", "The update was successful. Redirecting you to ownCloud now." => "La actualización se ha realizado con éxito. Redireccionando a ownCloud ahora.", "%s password reset" => "%s restablecer contraseña", @@ -179,6 +181,6 @@ $TRANSLATIONS = array( "Thank you for your patience." => "Gracias por su paciencia.", "Updating ownCloud to version %s, this may take a while." => "Actualizando ownCloud a la versión %s, esto puede demorar un tiempo.", "This ownCloud instance is currently being updated, which may take a while." => "Esta versión de owncloud se está actualizando, esto puede demorar un tiempo.", -"Please reload this page after a short time to continue using ownCloud." => "Por favor , recargue esta instancia de onwcloud tras un corto periodo de tiempo y continue usándolo." +"Please reload this page after a short time to continue using ownCloud." => "Por favor, recargue la página tras un corto periodo de tiempo para continuar usando ownCloud" ); $PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/core/l10n/es_AR.php b/core/l10n/es_AR.php index b5b37d4825b..c9d270edefa 100644 --- a/core/l10n/es_AR.php +++ b/core/l10n/es_AR.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Error cargando la plantilla del mensaje: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("un archivo en conflicto","{count} archivos en conflicto"), "One file conflict" => "Un archivo en conflicto", +"New Files" => "Nuevos archivos", "Which files do you want to keep?" => "¿Qué archivos deseas retener?", "If you select both versions, the copied file will have a number added to its name." => "Si tu seleccionas ambas versiones, el archivo copiado tendrá un número agregado a su nombre.", "Cancel" => "Cancelar", diff --git a/core/l10n/et_EE.php b/core/l10n/et_EE.php index 5a2e34ff3a0..422caac9c15 100644 --- a/core/l10n/et_EE.php +++ b/core/l10n/et_EE.php @@ -1,5 +1,6 @@ "Aegumise kuupäev on minevikus.", "Couldn't send mail to following users: %s " => "Kirja saatmine järgnevatele kasutajatele ebaõnnestus: %s ", "Turned on maintenance mode" => "Haldusrežiimis sisse lülitatud", "Turned off maintenance mode" => "Haldusrežiimis välja lülitatud", @@ -49,6 +50,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Viga sõnumi malli laadimisel: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} failikonflikt","{count} failikonflikti"), "One file conflict" => "Üks failikonflikt", +"New Files" => "Uued failid", "Which files do you want to keep?" => "Milliseid faile sa soovid alles hoida?", "If you select both versions, the copied file will have a number added to its name." => "Kui valid mõlemad versioonid, siis lisatakse kopeeritud faili nimele number.", "Cancel" => "Loobu", @@ -56,6 +58,11 @@ $TRANSLATIONS = array( "(all selected)" => "(kõik valitud)", "({count} selected)" => "({count} valitud)", "Error loading file exists template" => "Viga faili olemasolu malli laadimisel", +"Very weak password" => "Väga nõrk parool", +"Weak password" => "Nõrk parool", +"So-so password" => "Enam-vähem sobiv parool", +"Good password" => "Hea parool", +"Strong password" => "Väga hea parool", "Shared" => "Jagatud", "Share" => "Jaga", "Error" => "Viga", @@ -103,6 +110,7 @@ $TRANSLATIONS = array( "The update was unsuccessful. Please report this issue to the ownCloud community." => "Uuendus ebaõnnestus. Palun teavita probleemidest ownCloud kogukonda.", "The update was successful. Redirecting you to ownCloud now." => "Uuendus oli edukas. Kohe suunatakse Sind ownCloudi.", "%s password reset" => "%s parooli lähtestus", +"A problem has occurred whilst sending the email, please contact your administrator." => "Tekkis tõrge e-posti saatmisel, palun kontakteeru administraatoriga.", "Use the following link to reset your password: {link}" => "Kasuta järgnevat linki oma parooli taastamiseks: {link}", "The link to reset your password has been sent to your email.
    If you do not receive it within a reasonable amount of time, check your spam/junk folders.
    If it is not there ask your local administrator ." => "Link parooli vahetuseks on saadetud Sinu e-posti aadressile.
    Kui kiri pole saabunud mõistliku aja jooksul, siis kontrolli oma spam-/rämpskirjade katalooge.
    Kui kirja pole ka seal, siis küsi abi süsteemihaldurilt.", "Request failed!
    Did you make sure your email/username was right?" => "Päring ebaõnnestus!
    Oled sa veendunud, et e-post/kasutajanimi on õiged?", @@ -115,6 +123,8 @@ $TRANSLATIONS = array( "To login page" => "Sisselogimise lehele", "New password" => "Uus parool", "Reset password" => "Nulli parool", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Mac OS X ei ole toetatud ja %s ei pruugi korralikult toimida sellel platvormil. Kasuta seda omal vastutusel!", +"For the best results, please consider using a GNU/Linux server instead." => "Parema tulemuse saavitamiseks palun kaalu serveris GNU/Linux kasutamist.", "Personal" => "Isiklik", "Users" => "Kasutajad", "Apps" => "Rakendused", @@ -140,6 +150,7 @@ $TRANSLATIONS = array( "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." => "Su andmete kataloog ja failid on tõenäoliselt internetist vabalt saadaval kuna .htaccess fail ei toimi.", "For information how to properly configure your server, please see the documentation." => "Serveri korrektseks seadistuseks palun tutvu dokumentatsiooniga.", "Create an admin account" => "Loo admini konto", +"Storage & database" => "Andmehoidla ja andmebaas", "Data folder" => "Andmete kaust", "Configure the database" => "Seadista andmebaasi", "will be used" => "kasutatakse", @@ -162,6 +173,7 @@ $TRANSLATIONS = array( "remember" => "pea meeles", "Log in" => "Logi sisse", "Alternative Logins" => "Alternatiivsed sisselogimisviisid", +"Hey there,

    just letting you know that %s shared %s with you.
    View it!

    " => "Hei,

    annan teada, et %s jagas sinuga %s. Vaata seda!

    ", "This ownCloud instance is currently in single user mode." => "See ownCloud on momendil seadistatud ühe kasutaja jaoks.", "This means only administrators can use the instance." => "See tähendab, et seda saavad kasutada ainult administraatorid.", "Contact your system administrator if this message persists or appeared unexpectedly." => "Kontakteeru oma süsteemihalduriga, kui see teade püsib või on tekkinud ootamatult.", diff --git a/core/l10n/eu.php b/core/l10n/eu.php index 33c98fb9b90..8fd554485db 100644 --- a/core/l10n/eu.php +++ b/core/l10n/eu.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Errorea mezu txantiloia kargatzean: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("fitxategi {count}ek konfliktua sortu du","{count} fitxategik konfliktua sortu dute"), "One file conflict" => "Fitxategi batek konfliktua sortu du", +"New Files" => "Fitxategi Berriak", "Which files do you want to keep?" => "Ze fitxategi mantendu nahi duzu?", "If you select both versions, the copied file will have a number added to its name." => "Bi bertsioak hautatzen badituzu, kopiatutako fitxategiaren izenean zenbaki bat atxikituko zaio.", "Cancel" => "Ezeztatu", diff --git a/core/l10n/fa.php b/core/l10n/fa.php index 3e7e246e827..a349d3b7704 100644 --- a/core/l10n/fa.php +++ b/core/l10n/fa.php @@ -37,6 +37,7 @@ $TRANSLATIONS = array( "No" => "نه", "Ok" => "قبول", "_{count} file conflict_::_{count} file conflicts_" => array(""), +"New Files" => "فایل های جدید", "Cancel" => "منصرف شدن", "Shared" => "اشتراک گذاشته شده", "Share" => "اشتراک‌گذاری", diff --git a/core/l10n/fi_FI.php b/core/l10n/fi_FI.php index 0af7503ee9d..7797d17c872 100644 --- a/core/l10n/fi_FI.php +++ b/core/l10n/fi_FI.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Virhe ladatessa viestipohjaa: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} tiedoston ristiriita","{count} tiedoston ristiriita"), "One file conflict" => "Yhden tiedoston ristiriita", +"New Files" => "Uudet tiedostot", +"Already existing files" => "Jo olemassa olevat tiedostot", "Which files do you want to keep?" => "Mitkä tiedostot haluat säilyttää?", "If you select both versions, the copied file will have a number added to its name." => "Jos valitset kummatkin versiot, kopioidun tiedoston nimeen lisätään numero.", "Cancel" => "Peru", @@ -122,6 +124,8 @@ $TRANSLATIONS = array( "To login page" => "Kirjautumissivulle", "New password" => "Uusi salasana", "Reset password" => "Palauta salasana", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Mac OS X ei ole tuettu, joten %s ei toimi kunnolla tällä alustalla. Käytä omalla vastuulla!", +"For the best results, please consider using a GNU/Linux server instead." => "Käytä parhaan lopputuloksen saamiseksi GNU/Linux-palvelinta.", "Personal" => "Henkilökohtainen", "Users" => "Käyttäjät", "Apps" => "Sovellukset", diff --git a/core/l10n/fr.php b/core/l10n/fr.php index 3754e8c9e07..623f129c860 100644 --- a/core/l10n/fr.php +++ b/core/l10n/fr.php @@ -1,5 +1,6 @@ "La date d'expiration est dans le passé.", "Couldn't send mail to following users: %s " => "Impossible d'envoyer un mail aux utilisateurs suivant : %s", "Turned on maintenance mode" => "Basculé en mode maintenance", "Turned off maintenance mode" => "Basculé en mode production (non maintenance)", @@ -49,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Erreur de chargement du modèle de message : {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} fichier en conflit","{count} fichiers en conflit"), "One file conflict" => "Un conflit de fichier", +"New Files" => "Nouveaux fichiers", +"Already existing files" => "Fichiers déjà existants", "Which files do you want to keep?" => "Quels fichiers désirez-vous garder ?", "If you select both versions, the copied file will have a number added to its name." => "Si vous sélectionnez les deux versions, un nombre sera ajouté au nom du fichier copié.", "Cancel" => "Annuler", @@ -121,6 +124,8 @@ $TRANSLATIONS = array( "To login page" => "Retour à la page d'authentification", "New password" => "Nouveau mot de passe", "Reset password" => "Réinitialiser le mot de passe", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Mac OS X n'est pas supporté et %s ne fonctionnera pas correctement sur cette plateforme. Son utilisation est à vos risques et périls !", +"For the best results, please consider using a GNU/Linux server instead." => "Pour des résultats meilleurs encore, pensez à utiliser un serveur GNU/Linux à la place.", "Personal" => "Personnel", "Users" => "Utilisateurs", "Apps" => "Applications", diff --git a/core/l10n/gl.php b/core/l10n/gl.php index c1c678e7e3f..eb9f1af5657 100644 --- a/core/l10n/gl.php +++ b/core/l10n/gl.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Produciuse un erro ao cargar o modelo da mensaxe: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} conflito de ficheiro","{count} conflitos de ficheiros"), "One file conflict" => "Un conflito de ficheiro", +"New Files" => "Ficheiros novos", +"Already existing files" => "Ficheiros xa existentes", "Which files do you want to keep?" => "Que ficheiros quere conservar?", "If you select both versions, the copied file will have a number added to its name." => "Se selecciona ambas versións, o ficheiro copiado terá un número engadido ao nome.", "Cancel" => "Cancelar", diff --git a/core/l10n/he.php b/core/l10n/he.php index 4579626f12d..8fb7373a143 100644 --- a/core/l10n/he.php +++ b/core/l10n/he.php @@ -37,6 +37,7 @@ $TRANSLATIONS = array( "No" => "לא", "Ok" => "בסדר", "_{count} file conflict_::_{count} file conflicts_" => array("",""), +"New Files" => "קבצים חדשים", "Cancel" => "ביטול", "Shared" => "שותף", "Share" => "שתף", diff --git a/core/l10n/hu_HU.php b/core/l10n/hu_HU.php index e81991ec7ad..096b28e2d9b 100644 --- a/core/l10n/hu_HU.php +++ b/core/l10n/hu_HU.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Nem sikerült betölteni az üzenet sablont: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} fájl ütközik","{count} fájl ütközik"), "One file conflict" => "Egy file ütközik", +"New Files" => "Új fájlok", "Which files do you want to keep?" => "Melyik file-okat akarod megtartani?", "If you select both versions, the copied file will have a number added to its name." => "Ha kiválasztod mindazokaz a verziókat, a másolt fileok neve sorszámozva lesz.", "Cancel" => "Mégsem", diff --git a/core/l10n/it.php b/core/l10n/it.php index 2f0017263fa..98d0d5e3b0e 100644 --- a/core/l10n/it.php +++ b/core/l10n/it.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Errore durante il caricamento del modello di messaggio: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} file in conflitto","{count} file in conflitto"), "One file conflict" => "Un file in conflitto", +"New Files" => "File nuovi", +"Already existing files" => "File già esistenti", "Which files do you want to keep?" => "Quali file vuoi mantenere?", "If you select both versions, the copied file will have a number added to its name." => "Se selezioni entrambe le versioni, sarà aggiunto un numero al nome del file copiato.", "Cancel" => "Annulla", diff --git a/core/l10n/ja.php b/core/l10n/ja.php index eb3e6882578..3a99f0e598b 100644 --- a/core/l10n/ja.php +++ b/core/l10n/ja.php @@ -1,5 +1,6 @@ "有効期限が切れています。", "Couldn't send mail to following users: %s " => "次のユーザーにメールを送信できませんでした: %s", "Turned on maintenance mode" => "メンテナンスモードがオンになりました", "Turned off maintenance mode" => "メンテナンスモードがオフになりました", @@ -49,6 +50,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "メッセージテンプレートの読み込みエラー: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} ファイルが競合"), "One file conflict" => "1ファイルが競合", +"New Files" => "新しいファイル", "Which files do you want to keep?" => "どちらのファイルを保持したいですか?", "If you select both versions, the copied file will have a number added to its name." => "両方のバージョンを選択した場合は、ファイル名の後ろに数字を追加したファイルのコピーを作成します。", "Cancel" => "キャンセル", @@ -121,6 +123,8 @@ $TRANSLATIONS = array( "To login page" => "ログインページへ戻る", "New password" => "新しいパスワードを入力", "Reset password" => "パスワードをリセット", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Mac OS X では、サポートされていません。このOSでは、%sは正常に動作しないかもしれません。ご自身の責任においてご利用ください。", +"For the best results, please consider using a GNU/Linux server instead." => "最も良い方法としては、代わりにGNU/Linuxサーバーを利用することをご検討ください。", "Personal" => "個人", "Users" => "ユーザー", "Apps" => "アプリ", diff --git a/core/l10n/jv.php b/core/l10n/jv.php new file mode 100644 index 00000000000..ffcdde48d47 --- /dev/null +++ b/core/l10n/jv.php @@ -0,0 +1,9 @@ + array("",""), +"_%n hour ago_::_%n hours ago_" => array("",""), +"_%n day ago_::_%n days ago_" => array("",""), +"_%n month ago_::_%n months ago_" => array("",""), +"_{count} file conflict_::_{count} file conflicts_" => array("","") +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/core/l10n/ka_GE.php b/core/l10n/ka_GE.php index 0070fd7994e..a76a8866541 100644 --- a/core/l10n/ka_GE.php +++ b/core/l10n/ka_GE.php @@ -37,6 +37,7 @@ $TRANSLATIONS = array( "No" => "არა", "Ok" => "დიახ", "_{count} file conflict_::_{count} file conflicts_" => array(""), +"New Files" => "ახალი ფაილები", "Cancel" => "უარყოფა", "Shared" => "გაზიარებული", "Share" => "გაზიარება", diff --git a/core/l10n/lv.php b/core/l10n/lv.php index 505bf46b4c9..683ff2c129a 100644 --- a/core/l10n/lv.php +++ b/core/l10n/lv.php @@ -37,6 +37,7 @@ $TRANSLATIONS = array( "No" => "Nē", "Ok" => "Labi", "_{count} file conflict_::_{count} file conflicts_" => array("","",""), +"New Files" => "Jaunās datnes", "Cancel" => "Atcelt", "Shared" => "Kopīgs", "Share" => "Dalīties", diff --git a/core/l10n/nb_NO.php b/core/l10n/nb_NO.php index 43141bc431f..c47599f5a17 100644 --- a/core/l10n/nb_NO.php +++ b/core/l10n/nb_NO.php @@ -56,6 +56,10 @@ $TRANSLATIONS = array( "(all selected)" => "(alle valgt)", "({count} selected)" => "({count} valgt)", "Error loading file exists template" => "Feil ved lasting av \"filen eksisterer\"-mal", +"Very weak password" => "Veldig svakt passord", +"Weak password" => "Svakt passord", +"Good password" => "Bra passord", +"Strong password" => "Sterkt passord", "Shared" => "Delt", "Share" => "Del", "Error" => "Feil", @@ -140,6 +144,7 @@ $TRANSLATIONS = array( "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." => "Datamappen og filene dine er sannsynligvis tilgjengelig fra Internett fordi .htaccess-filen ikke fungerer.", "For information how to properly configure your server, please see the documentation." => "For informasjon om hvordan du setter opp serveren din riktig, se dokumentasjonen.", "Create an admin account" => "opprett en administrator-konto", +"Storage & database" => "Lagring og database", "Data folder" => "Datamappe", "Configure the database" => "Konfigurer databasen", "will be used" => "vil bli brukt", diff --git a/core/l10n/nl.php b/core/l10n/nl.php index 05cef6afd5a..b09509e6290 100644 --- a/core/l10n/nl.php +++ b/core/l10n/nl.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Fout bij laden berichtensjabloon: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} bestandsconflict","{count} bestandsconflicten"), "One file conflict" => "Een bestandsconflict", +"New Files" => "Nieuwe bestanden", +"Already existing files" => "Al aanwezige bestanden", "Which files do you want to keep?" => "Welke bestanden wilt u bewaren?", "If you select both versions, the copied file will have a number added to its name." => "Als u beide versies selecteerde, zal het gekopieerde bestand een nummer aan de naam toegevoegd krijgen.", "Cancel" => "Annuleer", diff --git a/core/l10n/pl.php b/core/l10n/pl.php index 17fde36c7cd..fe0cf145832 100644 --- a/core/l10n/pl.php +++ b/core/l10n/pl.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Błąd podczas ładowania szablonu wiadomości: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} konfliktów plików","{count} konfliktów plików","{count} konfliktów plików"), "One file conflict" => "Konflikt pliku", +"New Files" => "Nowe pliki", +"Already existing files" => "Już istniejące pliki", "Which files do you want to keep?" => "Które pliki chcesz zachować?", "If you select both versions, the copied file will have a number added to its name." => "Jeśli wybierzesz obie wersje, skopiowany plik będzie miał dodany numerek w nazwie", "Cancel" => "Anuluj", diff --git a/core/l10n/pl_PL.php b/core/l10n/pl_PL.php deleted file mode 100644 index 15c376eb954..00000000000 --- a/core/l10n/pl_PL.php +++ /dev/null @@ -1,6 +0,0 @@ - "Ustawienia", -"Username" => "Nazwa użytkownika" -); -$PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"; diff --git a/core/l10n/pt_BR.php b/core/l10n/pt_BR.php index b31925cdf79..3545426b670 100644 --- a/core/l10n/pt_BR.php +++ b/core/l10n/pt_BR.php @@ -50,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Erro no carregamento de modelo de mensagem: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} conflito de arquivo","{count} conflitos de arquivos"), "One file conflict" => "Conflito em um arquivo", +"New Files" => "Novos Arquivos", +"Already existing files" => "Arquivos já existentes", "Which files do you want to keep?" => "Qual arquivo você quer manter?", "If you select both versions, the copied file will have a number added to its name." => "Se você selecionar ambas as versões, o arquivo copiado terá um número adicionado ao seu nome.", "Cancel" => "Cancelar", diff --git a/core/l10n/pt_PT.php b/core/l10n/pt_PT.php index a4d6785cd5e..bb1b6011a6b 100644 --- a/core/l10n/pt_PT.php +++ b/core/l10n/pt_PT.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Erro ao carregar o template: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} conflicto de ficheiro","{count} conflitos de ficheiro"), "One file conflict" => "Um conflito no ficheiro", +"New Files" => "Ficheiros Novos", "Which files do you want to keep?" => "Quais os ficheiros que pretende manter?", "If you select both versions, the copied file will have a number added to its name." => "Se escolher ambas as versões, o ficheiro copiado irá ter um número adicionado ao seu nome.", "Cancel" => "Cancelar", diff --git a/core/l10n/ru.php b/core/l10n/ru.php index 8d84e7d31bc..aa784088f7a 100644 --- a/core/l10n/ru.php +++ b/core/l10n/ru.php @@ -1,5 +1,6 @@ "Дата истечения срока действия в прошлом.", "Couldn't send mail to following users: %s " => "Невозможно отправить письмо следующим пользователям: %s", "Turned on maintenance mode" => "Режим отладки включён", "Turned off maintenance mode" => "Режим отладки отключён", @@ -49,6 +50,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Ошибка загрузки шаблона сообщений: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} конфликт в файлах","{count} конфликта в файлах","{count} конфликтов в файлах"), "One file conflict" => "Один конфликт в файлах", +"New Files" => "Новые файлы", "Which files do you want to keep?" => "Какие файлы вы хотите сохранить?", "If you select both versions, the copied file will have a number added to its name." => "При выборе обоих версий, к названию копируемого файла будет добавлена цифра", "Cancel" => "Отменить", @@ -56,6 +58,11 @@ $TRANSLATIONS = array( "(all selected)" => "(выбраны все)", "({count} selected)" => "({count} выбрано)", "Error loading file exists template" => "Ошибка при загрузке шаблона существующего файла", +"Very weak password" => "Очень слабый пароль", +"Weak password" => "Слабый пароль", +"So-so password" => "Так себе пароль", +"Good password" => "Хороший пароль", +"Strong password" => "Устойчивый к взлому пароль", "Shared" => "Общие", "Share" => "Открыть доступ", "Error" => "Ошибка", @@ -103,6 +110,7 @@ $TRANSLATIONS = array( "The update was unsuccessful. Please report this issue to the ownCloud community." => "При обновлении произошла ошибка. Пожалуйста сообщите об этом в ownCloud сообщество.", "The update was successful. Redirecting you to ownCloud now." => "Обновление прошло успешно. Перенаправляемся в Ваш ownCloud...", "%s password reset" => "%s сброс пароля", +"A problem has occurred whilst sending the email, please contact your administrator." => "Произошла ошибка при отправке сообщения электронной почты, пожалуйста, свяжитесь с Вашим администратором.", "Use the following link to reset your password: {link}" => "Используйте следующую ссылку чтобы сбросить пароль: {link}", "The link to reset your password has been sent to your email.
    If you do not receive it within a reasonable amount of time, check your spam/junk folders.
    If it is not there ask your local administrator ." => "Ссылка для сброса пароля отправлена вам ​​по электронной почте.
    Если вы не получите письмо в пределах одной-двух минут, проверьте папку Спам.
    Если письма там нет, обратитесь к своему администратору.", "Request failed!
    Did you make sure your email/username was right?" => "Запрос не удался. Вы уверены, что email или имя пользователя указаны верно?", @@ -115,6 +123,8 @@ $TRANSLATIONS = array( "To login page" => "На страницу авторизации", "New password" => "Новый пароль", "Reset password" => "Сбросить пароль", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Mac OS X не поддерживается и %s не будет работать правильно на этой платформе. Используйте ее на свой страх и риск!", +"For the best results, please consider using a GNU/Linux server instead." => "Для достижения наилучших результатов, пожалуйста, рассмотрите возможность использовать взамен GNU/Linux сервер.", "Personal" => "Личное", "Users" => "Пользователи", "Apps" => "Приложения", @@ -140,6 +150,7 @@ $TRANSLATIONS = array( "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." => "Ваша папка с данными и файлы возможно доступны из интернета потому что файл .htaccess не работает.", "For information how to properly configure your server, please see the documentation." => "Для информации, как правильно настроить Ваш сервер, пожалуйста загляните в документацию.", "Create an admin account" => "Создать учётную запись администратора", +"Storage & database" => "Система хранения данных & база данных", "Data folder" => "Директория с данными", "Configure the database" => "Настройка базы данных", "will be used" => "будет использовано", @@ -162,6 +173,7 @@ $TRANSLATIONS = array( "remember" => "запомнить", "Log in" => "Войти", "Alternative Logins" => "Альтернативные имена пользователя", +"Hey there,

    just letting you know that %s shared %s with you.
    View it!

    " => "Здравствуйте,

    просто даём вам знать, что %s открыл доступ к %s для вас.
    Посмотреть!

    ", "This ownCloud instance is currently in single user mode." => "Эта установка ownCloud в настоящее время в однопользовательском режиме.", "This means only administrators can use the instance." => "Это значит, что только администраторы могут использовать эту установку.", "Contact your system administrator if this message persists or appeared unexpectedly." => "Обратитесь к вашему системному администратору если это сообщение не исчезает или появляется неожиданно.", diff --git a/core/l10n/sk_SK.php b/core/l10n/sk_SK.php index bb3c9863ce2..1b717bc412e 100644 --- a/core/l10n/sk_SK.php +++ b/core/l10n/sk_SK.php @@ -1,5 +1,6 @@ " \t\nDátum expirácie spadá do minulosti.", "Couldn't send mail to following users: %s " => "Nebolo možné odoslať email týmto používateľom: %s ", "Turned on maintenance mode" => "Mód údržby je zapnutý", "Turned off maintenance mode" => "Mód údržby e vypnutý", @@ -49,6 +50,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Chyba pri nahrávaní šablóny správy: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} konflikt súboru","{count} konflikty súboru","{count} konfliktov súboru"), "One file conflict" => "Jeden konflikt súboru", +"New Files" => "Nové súbory", "Which files do you want to keep?" => "Ktoré súbory chcete ponechať?", "If you select both versions, the copied file will have a number added to its name." => "Ak zvolíte obe verzie, názov nakopírovaného súboru bude doplnený o číslo.", "Cancel" => "Zrušiť", @@ -56,6 +58,11 @@ $TRANSLATIONS = array( "(all selected)" => "(všetko vybrané)", "({count} selected)" => "({count} vybraných)", "Error loading file exists template" => "Chyba pri nahrávaní šablóny existencie súboru", +"Very weak password" => "Veľmi slabé heslo", +"Weak password" => "Slabé heslo", +"So-so password" => "Priemerné heslo", +"Good password" => "Dobré heslo", +"Strong password" => "Silné heslo", "Shared" => "Zdieľané", "Share" => "Zdieľať", "Error" => "Chyba", @@ -103,6 +110,7 @@ $TRANSLATIONS = array( "The update was unsuccessful. Please report this issue to the ownCloud community." => "Aktualizácia nebola úspešná. Problém nahláste ownCloud comunite.", "The update was successful. Redirecting you to ownCloud now." => "Aktualizácia bola úspešná. Presmerovávam vás na prihlasovaciu stránku.", "%s password reset" => "reset hesla %s", +"A problem has occurred whilst sending the email, please contact your administrator." => "Vyskytol sa problém pri odosielaní emailu, prosím obráťte sa na správcu.", "Use the following link to reset your password: {link}" => "Použite nasledujúci odkaz pre obnovenie vášho hesla: {link}", "The link to reset your password has been sent to your email.
    If you do not receive it within a reasonable amount of time, check your spam/junk folders.
    If it is not there ask your local administrator ." => "Odkaz na obnovenie hesla bol odoslaný na vašu emailovú adresu.
    Ak ho v krátkej dobe neobdržíte, skontrolujte si váš kôš a priečinok spam.
    Ak ho ani tam nenájdete, kontaktujte svojho administrátora.", "Request failed!
    Did you make sure your email/username was right?" => "Požiadavka zlyhala.
    Uistili ste sa, že vaše používateľské meno a email sú správne?", @@ -115,6 +123,8 @@ $TRANSLATIONS = array( "To login page" => "Na prihlasovaciu stránku", "New password" => "Nové heslo", "Reset password" => "Obnovenie hesla", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Mac OS X nie je podporovaný a %s nebude správne fungovať na tejto platforme. Použite ho na vlastné riziko!", +"For the best results, please consider using a GNU/Linux server instead." => "Pre dosiahnutie najlepších výsledkov, prosím zvážte použitie GNU/Linux servera.", "Personal" => "Osobné", "Users" => "Používatelia", "Apps" => "Aplikácie", @@ -129,7 +139,7 @@ $TRANSLATIONS = array( "Error unfavoriting" => "Chyba pri odobratí z obľúbených", "Access forbidden" => "Prístup odmietnutý", "Cloud not found" => "Nenájdené", -"Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" => "Ahoj,\n\nchcem ti dať navedomie, že %s s tebou zdieľa %s.\nTu je odkaz: %s\n\n", +"Hey there,\n\njust letting you know that %s shared %s with you.\nView it: %s\n\n" => "Dobrý deň,\n\nPoužívateľ %s zdieľa s vami súbor, alebo priečinok s názvom %s.\nPre zobrazenie kliknite na túto linku: %s\n", "The share will expire on %s." => "Zdieľanie expiruje %s.", "Cheers!" => "Pekný deň!", "Security Warning" => "Bezpečnostné varovanie", @@ -140,6 +150,7 @@ $TRANSLATIONS = array( "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." => "Váš priečinok s dátami a súbormi je dostupný z internetu, lebo súbor .htaccess nefunguje.", "For information how to properly configure your server, please see the documentation." => "Pre informácie, ako správne nastaviť váš server, sa pozrite do dokumentácie.", "Create an admin account" => "Vytvoriť administrátorský účet", +"Storage & database" => "Úložislo & databáza", "Data folder" => "Priečinok dát", "Configure the database" => "Nastaviť databázu", "will be used" => "bude použité", @@ -162,6 +173,7 @@ $TRANSLATIONS = array( "remember" => "zapamätať", "Log in" => "Prihlásiť sa", "Alternative Logins" => "Alternatívne prihlásenie", +"Hey there,

    just letting you know that %s shared %s with you.
    View it!

    " => "Dobrý deň,

    Používateľ %s zdieľa s vami súbor, alebo priečinok s názvom »%s«.
    Pre zobrazenie kliknite na túto linku!

    ", "This ownCloud instance is currently in single user mode." => "Táto inštancia ownCloudu je teraz v jednopoužívateľskom móde.", "This means only administrators can use the instance." => "Len správca systému môže používať túto inštanciu.", "Contact your system administrator if this message persists or appeared unexpectedly." => "Kontaktujte prosím správcu systému, ak sa táto správa objavuje opakovane alebo neočakávane.", diff --git a/core/l10n/sl.php b/core/l10n/sl.php index 2cfdfd11899..7476d9f9c7c 100644 --- a/core/l10n/sl.php +++ b/core/l10n/sl.php @@ -50,6 +50,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Napaka nalaganja predloge sporočil: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} spor datotek","{count} spora datotek","{count} spori datotek","{count} sporov datotek"), "One file conflict" => "En spor datotek", +"New Files" => "Nove datoteke", "Which files do you want to keep?" => "Katare datoteke želite ohraniti?", "If you select both versions, the copied file will have a number added to its name." => "Če izberete obe različici, bo kopirani datoteki k imenu dodana številka.", "Cancel" => "Prekliči", @@ -122,6 +123,8 @@ $TRANSLATIONS = array( "To login page" => "Na prijavno stran", "New password" => "Novo geslo", "Reset password" => "Ponastavi geslo", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Sistem Mac OS X ni podprt, zato %s ne bo deloval zanesljivo v tem okolju. Program uporabljate na lastno odgovornost! ", +"For the best results, please consider using a GNU/Linux server instead." => "Za najbolj še rezultate je priporočljivo uporabljati strežnik GNU/Linux.", "Personal" => "Osebno", "Users" => "Uporabniki", "Apps" => "Programi", diff --git a/core/l10n/sv.php b/core/l10n/sv.php index c4e92e62171..d46c204d7c3 100644 --- a/core/l10n/sv.php +++ b/core/l10n/sv.php @@ -1,5 +1,6 @@ "Utgångsdatumet är i det förflutna.", "Couldn't send mail to following users: %s " => "Gick inte att skicka e-post till följande användare: %s", "Turned on maintenance mode" => "Aktiverade underhållsläge", "Turned off maintenance mode" => "Deaktiverade underhållsläge", @@ -49,6 +50,8 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Fel uppstod under inläsningen av meddelandemallen: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} filkonflikt","{count} filkonflikter"), "One file conflict" => "En filkonflikt", +"New Files" => "Nya filer", +"Already existing files" => "Filer som redan existerar", "Which files do you want to keep?" => "Vilken fil vill du behålla?", "If you select both versions, the copied file will have a number added to its name." => "Om du väljer båda versionerna kommer de kopierade filerna ha nummer tillagda i filnamnet.", "Cancel" => "Avbryt", @@ -56,6 +59,11 @@ $TRANSLATIONS = array( "(all selected)" => "(Alla valda)", "({count} selected)" => "({count} valda)", "Error loading file exists template" => "Fel uppstod filmall existerar", +"Very weak password" => "Väldigt svagt lösenord", +"Weak password" => "Svagt lösenord", +"So-so password" => "Okej lösenord", +"Good password" => "Bra lösenord", +"Strong password" => "Starkt lösenord", "Shared" => "Delad", "Share" => "Dela", "Error" => "Fel", @@ -99,9 +107,11 @@ $TRANSLATIONS = array( "Edit tags" => "Editera taggar", "Error loading dialog template: {error}" => "Fel under laddning utav dialog mall: {fel}", "No tags selected for deletion." => "Inga taggar valda för borttagning.", +"Please reload the page." => "Vänligen ladda om sidan.", "The update was unsuccessful. Please report this issue to the ownCloud community." => "Uppdateringen misslyckades. Rapportera detta problem till ownCloud Community.", "The update was successful. Redirecting you to ownCloud now." => "Uppdateringen lyckades. Du omdirigeras nu till OwnCloud.", "%s password reset" => "%s återställ lösenord", +"A problem has occurred whilst sending the email, please contact your administrator." => "Ett problem har uppstått under tiden e-post sändes, vänligen kontakta din administratör.", "Use the following link to reset your password: {link}" => "Använd följande länk för att återställa lösenordet: {link}", "The link to reset your password has been sent to your email.
    If you do not receive it within a reasonable amount of time, check your spam/junk folders.
    If it is not there ask your local administrator ." => "Länken för att återställa ditt lösenorden har skickats till din e-postadress
    Om du inte har erhållit meddelandet inom kort, vänligen kontrollera din skräppost-mapp
    Om den inte finns där, vänligen kontakta din administratör.", "Request failed!
    Did you make sure your email/username was right?" => "Begäran misslyckades!
    Är du helt säker på att din e-postadress/användarnamn är korrekt?", @@ -114,6 +124,8 @@ $TRANSLATIONS = array( "To login page" => "Till logginsidan", "New password" => "Nytt lösenord", "Reset password" => "Återställ lösenordet", +"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " => "Mac OS X stöds inte och %s kommer inte att fungera korrekt på denna plattform. Använd på egen risk!", +"For the best results, please consider using a GNU/Linux server instead." => "För bästa resultat, överväg att använda en GNU/Linux server istället.", "Personal" => "Personligt", "Users" => "Användare", "Apps" => "Program", @@ -139,6 +151,7 @@ $TRANSLATIONS = array( "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." => "Din datakatalog och filer är förmodligen tillgängliga från Internet, eftersom .htaccess-filen inte fungerar.", "For information how to properly configure your server, please see the documentation." => "För information hur du korrekt konfigurerar din servern, se ownCloud dokumentationen.", "Create an admin account" => "Skapa ett administratörskonto", +"Storage & database" => "Lagring & databas", "Data folder" => "Datamapp", "Configure the database" => "Konfigurera databasen", "will be used" => "kommer att användas", @@ -149,6 +162,7 @@ $TRANSLATIONS = array( "Database host" => "Databasserver", "Finish setup" => "Avsluta installation", "Finishing …" => "Avslutar ...", +"This application requires JavaScript to be enabled for correct operation. Please enable JavaScript and re-load this interface." => "Denna applikation kräver JavaScript aktiverat för att fungera korrekt. Vänligen aktivera JavaScript och ladda om gränssnittet.", "%s is available. Get more information on how to update." => "%s är tillgänglig. Få mer information om hur du går tillväga för att uppdatera.", "Log out" => "Logga ut", "Automatic logon rejected!" => "Automatisk inloggning inte tillåten!", @@ -160,6 +174,9 @@ $TRANSLATIONS = array( "remember" => "kom ihåg", "Log in" => "Logga in", "Alternative Logins" => "Alternativa inloggningar", +"Hey there,

    just letting you know that %s shared %s with you.
    View it!

    " => "Hej där,

    ville bara informera dig om att %s delade %s med dig.
    Visa den!

    ", +"This ownCloud instance is currently in single user mode." => "Denna ownCloud instans är för närvarande i enanvändarläge", +"This means only administrators can use the instance." => "Detta betyder att endast administartörer kan använda instansen.", "Contact your system administrator if this message persists or appeared unexpectedly." => "Hör av dig till din system administratör ifall detta meddelande fortsätter eller visas oväntat.", "Thank you for your patience." => "Tack för ditt tålamod.", "Updating ownCloud to version %s, this may take a while." => "Uppdaterar ownCloud till version %s, detta kan ta en stund.", diff --git a/core/l10n/th_TH.php b/core/l10n/th_TH.php index 85a9b4ab238..9ee3c60f947 100644 --- a/core/l10n/th_TH.php +++ b/core/l10n/th_TH.php @@ -37,6 +37,7 @@ $TRANSLATIONS = array( "No" => "ไม่ตกลง", "Ok" => "ตกลง", "_{count} file conflict_::_{count} file conflicts_" => array(""), +"New Files" => "ไฟล์ใหม่", "Cancel" => "ยกเลิก", "Shared" => "แชร์แล้ว", "Share" => "แชร์", diff --git a/core/l10n/tr.php b/core/l10n/tr.php index 03544cd3c0f..8f9c60c157b 100644 --- a/core/l10n/tr.php +++ b/core/l10n/tr.php @@ -31,7 +31,7 @@ $TRANSLATIONS = array( "December" => "Aralık", "Settings" => "Ayarlar", "Saving..." => "Kaydediliyor...", -"seconds ago" => "saniye önce", +"seconds ago" => "saniyeler önce", "_%n minute ago_::_%n minutes ago_" => array("%n dakika önce","%n dakika önce"), "_%n hour ago_::_%n hours ago_" => array("%n saat önce","%n saat önce"), "today" => "bugün", @@ -42,7 +42,7 @@ $TRANSLATIONS = array( "months ago" => "ay önce", "last year" => "geçen yıl", "years ago" => "yıl önce", -"Choose" => "seç", +"Choose" => "Seç", "Error loading file picker template: {error}" => "Dosya seçici şablonu yüklenirken hata: {error}", "Yes" => "Evet", "No" => "Hayır", @@ -50,8 +50,10 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "İleti şablonu yüklenirken hata: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} dosya çakışması","{count} dosya çakışması"), "One file conflict" => "Bir dosya çakışması", +"New Files" => "Yeni Dosyalar", +"Already existing files" => "Zaten mevcut olan dosyalar", "Which files do you want to keep?" => "Hangi dosyaları saklamak istiyorsunuz?", -"If you select both versions, the copied file will have a number added to its name." => "Eğer iki sürümü de seçerseniz, kopyalanan dosya ismine eklenmiş bir sayı içerecektir.", +"If you select both versions, the copied file will have a number added to its name." => "İki sürümü de seçerseniz, kopyalanan dosyanın ismine bir sayı ilave edilecektir.", "Cancel" => "İptal", "Continue" => "Devam et", "(all selected)" => "(tümü seçildi)", @@ -65,7 +67,7 @@ $TRANSLATIONS = array( "Shared" => "Paylaşılan", "Share" => "Paylaş", "Error" => "Hata", -"Error while sharing" => "Paylaşım sırasında hata ", +"Error while sharing" => "Paylaşım sırasında hata", "Error while unsharing" => "Paylaşım iptal edilirken hata", "Error while changing permissions" => "İzinleri değiştirirken hata oluştu", "Shared with you and the group {group} by {owner}" => "{owner} tarafından sizinle ve {group} ile paylaştırılmış", @@ -111,7 +113,7 @@ $TRANSLATIONS = array( "%s password reset" => "%s parola sıfırlama", "A problem has occurred whilst sending the email, please contact your administrator." => "E-posta gönderilirken bir hata oluştu. Lütfen yönetinizle iletişime geçin.", "Use the following link to reset your password: {link}" => "Parolanızı sıfırlamak için bu bağlantıyı kullanın: {link}", -"The link to reset your password has been sent to your email.
    If you do not receive it within a reasonable amount of time, check your spam/junk folders.
    If it is not there ask your local administrator ." => "Parolanızı değiştirme bağlantısı e-posta adresinize gönderildi.
    Eğer makül bir süre içerisinde mesajı almadıysanız spam/junk dizinini kontrol ediniz.
    Eğer orada da bulamazsanız sistem yöneticinize sorunuz.", +"The link to reset your password has been sent to your email.
    If you do not receive it within a reasonable amount of time, check your spam/junk folders.
    If it is not there ask your local administrator ." => "Parolanızı değiştirme bağlantısı e-posta adresinize gönderildi.
    Eğer makül bir süre içerisinde mesajı almadıysanız spam/junk/gereksiz dizinini kontrol ediniz.
    Eğer yine bulamazsanız sistem yöneticinize sorunuz.", "Request failed!
    Did you make sure your email/username was right?" => "İstek başarısız!
    E-posta ve/veya kullanıcı adınızın doğru olduğundan emin misiniz?", "You will receive a link to reset your password via Email." => "Parolanızı sıfırlamak için bir bağlantıyı e-posta olarak alacaksınız.", "Username" => "Kullanıcı Adı", @@ -159,7 +161,7 @@ $TRANSLATIONS = array( "Database tablespace" => "Veritabanı tablo alanı", "Database host" => "Veritabanı sunucusu", "Finish setup" => "Kurulumu tamamla", -"Finishing …" => "Tamamlanıyor ..", +"Finishing …" => "Tamamlanıyor ...", "This application requires JavaScript to be enabled for correct operation. Please enable JavaScript and re-load this interface." => "Uygulama, doğru çalışabilmesi için JavaScript'in etkinleştirilmesini gerektiriyor. Lütfen JavaScript'i etkinleştirin ve bu arayüzü yeniden yükleyin.", "%s is available. Get more information on how to update." => "%s mevcut. Güncelleştirme hakkında daha fazla bilgi alın.", "Log out" => "Çıkış yap", diff --git a/core/l10n/uk.php b/core/l10n/uk.php index ade29981b49..f6bcfdcdc8d 100644 --- a/core/l10n/uk.php +++ b/core/l10n/uk.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Помилка при завантаженні шаблону повідомлення: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} файловий конфлікт","{count} файлових конфліктів","{count} файлових конфліктів"), "One file conflict" => "Один файловий конфлікт", +"New Files" => "Нових Файлів", "Which files do you want to keep?" => "Які файли ви хочете залишити?", "If you select both versions, the copied file will have a number added to its name." => "Якщо ви оберете обидві версії, скопійований файл буде мати номер, доданий у його ім'я.", "Cancel" => "Відмінити", diff --git a/core/l10n/vi.php b/core/l10n/vi.php index be99580d942..319f68b6355 100644 --- a/core/l10n/vi.php +++ b/core/l10n/vi.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "Lỗi khi tải mẫu thông điệp: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} tập tin xung đột"), "One file conflict" => "Một tập tin xung đột", +"New Files" => "File mới", "Which files do you want to keep?" => "Bạn muốn tiếp tục với những tập tin nào?", "If you select both versions, the copied file will have a number added to its name." => "Nếu bạn chọn cả hai phiên bản, tập tin được sao chép sẽ được đánh thêm số vào tên của nó.", "Cancel" => "Hủy", diff --git a/core/l10n/zh_CN.php b/core/l10n/zh_CN.php index e5a6a254e54..68f50baf98f 100644 --- a/core/l10n/zh_CN.php +++ b/core/l10n/zh_CN.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "加载消息模板出错: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} 个文件冲突"), "One file conflict" => "1个文件冲突", +"New Files" => "新文件", "Which files do you want to keep?" => "想要保留哪一个文件呢?", "If you select both versions, the copied file will have a number added to its name." => "如果同时选择了连个版本,复制的文件名将会添加上一个数字。", "Cancel" => "取消", diff --git a/core/l10n/zh_TW.php b/core/l10n/zh_TW.php index dae143cef40..0799344697a 100644 --- a/core/l10n/zh_TW.php +++ b/core/l10n/zh_TW.php @@ -49,6 +49,7 @@ $TRANSLATIONS = array( "Error loading message template: {error}" => "載入訊息樣板出錯: {error}", "_{count} file conflict_::_{count} file conflicts_" => array("{count} 個檔案衝突"), "One file conflict" => "一個檔案衝突", +"New Files" => "新檔案", "Which files do you want to keep?" => "您要保留哪一個檔案?", "If you select both versions, the copied file will have a number added to its name." => "如果您同時選擇兩個版本,被複製的那個檔案名稱後面會加上編號", "Cancel" => "取消", diff --git a/core/lostpassword/templates/resetpassword.php b/core/lostpassword/templates/resetpassword.php index 0ab32acca60..881455f5a9d 100644 --- a/core/lostpassword/templates/resetpassword.php +++ b/core/lostpassword/templates/resetpassword.php @@ -1,14 +1,14 @@ -
    +
    -

    t('Your password was reset'); ?>

    -

    t('To login page'); ?>

    +

    t('Your password was reset')); ?>

    +

    t('To login page')); ?>

    - +

    - +
    diff --git a/core/setup/controller.php b/core/setup/controller.php index bb9c9101fe2..1a8e9b2b764 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -20,7 +20,7 @@ class Controller { $errors = array('errors' => $e); if(count($e) > 0) { - $options = array_merge($post, $opts, $errors); + $options = array_merge($opts, $post, $errors); $this->display($options); } else { @@ -28,7 +28,8 @@ class Controller { } } else { - $this->display($opts); + $options = array_merge($opts, $post); + $this->display($options); } } @@ -41,6 +42,7 @@ class Controller { 'dbname' => '', 'dbtablespace' => '', 'dbhost' => '', + 'dbtype' => '', ); $parameters = array_merge($defaults, $post); diff --git a/core/templates/layout.guest.php b/core/templates/layout.guest.php index 91157b923a5..5788d1d5bd3 100644 --- a/core/templates/layout.guest.php +++ b/core/templates/layout.guest.php @@ -36,7 +36,7 @@
    diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index 3d897503480..ba5f6ef9b54 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -15,7 +15,7 @@ - + @@ -46,7 +46,7 @@
    -
    +

    t('Setup Warning'));?>

    @@ -79,42 +79,42 @@ if (!$_['isWebDavWorking']) { t('Please double check the installation guides.', link_to_docs('admin-install'))); ?> -
    +
    -
    +

    t('Module \'fileinfo\' missing'));?>

    t('The PHP module \'fileinfo\' is missing. We strongly recommend to enable this module to get best results with mime-type detection.')); ?> -
    +
    -
    +

    t('Your PHP version is outdated'));?>

    t('Your PHP version is outdated. We strongly recommend to update to 5.3.8 or newer because older versions are known to be broken. It is possible that this installation is not working correctly.')); ?> -
    +
    -
    +

    t('Locale not working'));?>

    @@ -132,21 +132,21 @@ if (!$_['isLocaleWorking']) { ?> -
    +
    -
    +

    t('Internet connection not working'));?>

    t('This server has no working internet connection. This means that some of the features like mounting of external storage, notifications about updates or installation of 3rd party apps don´t work. Accessing files from remote and sending of notification emails might also not work. We suggest to enable internet connection for this server if you want to have all features.')); ?> -
    + @@ -156,7 +156,7 @@ if (!$_['internetconnectionworking']) { } ;?> -
    +

    t('Cron'));?>

    @@ -199,9 +199,9 @@ if (!$_['internetconnectionworking']) {
    t("Use systems cron service to call the cron.php file every 15 minutes.")); ?>

    -
    + -
    +

    t('Sharing'));?>

    @@ -255,9 +255,9 @@ if (!$_['internetconnectionworking']) {
    -
    + -
    +

    t('Security'));?>

    @@ -288,9 +288,9 @@ if (!$_['internetconnectionworking']) {
    -
    + -
    +

    t('Email Server'));?>

    t('This is used for sending out notifications.')); ?>

    @@ -370,9 +370,9 @@ if (!$_['internetconnectionworking']) { t( 'Test email settings' )); ?> -
    + -
    +

    t('Log'));?>

    t('Log level'));?> - - - -
    -
    -
    +
    +

    t('Password'));?>

    +
    t('Your password was changed');?>
    +
    t('Unable to change your password');?>
    + + + + +
    +
    -
    -
    -

    t('Full Name');?>

    - - - -
    + +

    t('Full Name');?>

    + + +
    -
    -
    -

    t('Email'));?>

    - -
    - t('Fill in an email address to enable password recovery and receive notifications'));?> -
    + +

    t('Email'));?>

    + +
    + t('Fill in an email address to enable password recovery and receive notifications'));?>
    -
    -
    -

    t('Profile picture')); ?>

    -
    -

    - - -
    t('Upload new')); ?>
    - -
    t('Select new from Files')); ?>
    -
    t('Remove image')); ?>

    - t('Either png or jpg. Ideally square but you will be able to crop it.')); ?> - - t('Your avatar is provided by your original account.')); ?> - -
    - -
    + +

    t('Profile picture')); ?>

    +
    +

    + + +
    t('Upload new')); ?>
    + +
    t('Select new from Files')); ?>
    +
    t('Remove image')); ?>

    + t('Either png or jpg. Ideally square but you will be able to crop it.')); ?> + + t('Your avatar is provided by your original account.')); ?> + +
    +
    -
    -
    -

    t('Language'));?>

    - + + + - - - - - - - - - - - t('Help translate'));?> - - -
    + + + + + + + + + t('Help translate'));?> + +
    -
    +

    t('WebDAV'));?>


    t('Use this address to access your Files via WebDAV', array(link_to_docs('user-webdav'))));?> -
    + -
    +

    t( 'Encryption' ) ); ?>

    @@ -174,18 +164,17 @@ if($_['passwordChangeSupported']) {


    -
    + -
    +

    t('Version'));?>

    getName()); ?>
    t('Developed by the ownCloud community, the source code is licensed under the AGPL.')); ?> -
    - + + + diff --git a/settings/users.php b/settings/users.php index 2f1c63a0b59..f09d0e90d3c 100644 --- a/settings/users.php +++ b/settings/users.php @@ -6,7 +6,6 @@ */ OC_Util::checkSubAdminUser(); -OC_App::loadApps(); // We have some javascript foo! OC_Util::addScript( 'settings', 'users' ); diff --git a/status.php b/status.php index 88422100f14..861eaed9cd2 100644 --- a/status.php +++ b/status.php @@ -21,8 +21,6 @@ * */ -$RUNTIME_NOAPPS = true; //no apps, yet - try { require_once 'lib/base.php'; diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 70de7cd1c44..99374d68a5c 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -16,3 +16,4 @@ if (!class_exists('PHPUnit_Framework_TestCase')) { OC_Hook::clear(); OC_Log::$enabled = false; +OC_FileProxy::clearProxies(); diff --git a/tests/data/lorem-big.txt b/tests/data/lorem-big.txt new file mode 100644 index 00000000000..3712b9d30f0 --- /dev/null +++ b/tests/data/lorem-big.txt @@ -0,0 +1,29 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id hendrerit felis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed dictum dolor nec lobortis sagittis. Aliquam blandit lobortis ullamcorper. Donec malesuada ante ante, vel cursus purus suscipit ut. Sed a eros vitae lorem tristique hendrerit a a odio. Cras interdum mi lectus, sed molestie mauris tempus sit amet. Praesent auctor neque venenatis diam tincidunt sodales. Maecenas tincidunt ligula et ipsum dignissim, et molestie dui hendrerit. Nunc lobortis mauris vel tempor tristique. Sed consectetur bibendum nunc. Pellentesque augue velit, interdum ac posuere eu, eleifend et massa. Vestibulum ac mi eu mi viverra iaculis. Sed consequat leo adipiscing dui varius, sagittis vestibulum massa vehicula. + +Praesent imperdiet erat vitae dui placerat, sit amet vulputate tortor viverra. In laoreet elit lorem, at luctus est tempor ac. Nam elementum scelerisque nisl vitae accumsan. Curabitur cursus rutrum est, ut adipiscing ante elementum ut. Ut lectus sem, luctus ut massa non, dignissim vestibulum ipsum. Suspendisse non convallis enim, aliquam adipiscing velit. Donec pharetra non turpis hendrerit porttitor. Aliquam erat volutpat. + +Cras eget arcu eu dolor faucibus accumsan non eget orci. Integer quis quam tincidunt, faucibus neque in, imperdiet lacus. Aenean dui turpis, lacinia quis ligula non, semper adipiscing tellus. Curabitur vitae dui quis nisl malesuada commodo. Nunc eleifend metus enim, eu aliquet dui semper sit amet. Sed a odio sapien. Suspendisse vitae ante id sapien semper accumsan. Sed vestibulum erat quis laoreet pellentesque. Nullam placerat ligula eu odio faucibus, eget dictum orci tristique. Quisque sit amet pulvinar velit, lacinia dictum sem. + +Phasellus id sagittis lacus. Vivamus facilisis convallis metus, sit amet ultricies purus gravida quis. Vivamus eget egestas arcu, a euismod risus. Fusce metus arcu, molestie ut lacinia at, commodo eu nibh. In leo tortor, feugiat aliquet semper in, malesuada ac nulla. Fusce tempor ultricies blandit. Pellentesque et lorem quam. Suspendisse eros eros, mattis ut porttitor vitae, fermentum eget augue. Aliquam vitae justo sed est dictum lobortis. Cras lacinia commodo ligula sed ornare. Donec ut eros semper, sodales tellus quis, cursus quam. Quisque elementum ullamcorper pellentesque. Integer in rutrum ante, vel condimentum metus. Aliquam erat volutpat. + +Quisque convallis tempus eros, sit amet mattis ipsum eleifend in. Mauris volutpat, urna ut commodo tempus, est quam scelerisque erat, eget consequat nulla arcu id eros. Nam elementum nibh quis tincidunt adipiscing. Fusce tristique pretium mollis. Nulla quis ornare felis, vel lacinia diam. In et dui et mauris vestibulum commodo. In hac habitasse platea dictumst. Vestibulum viverra pellentesque tortor, tempor vehicula orci. Praesent rutrum turpis ipsum, ac commodo nisi vehicula ac. + +Nulla gravida ultrices mauris. Ut congue purus nec dolor euismod, vitae auctor elit condimentum. Nullam elementum velit lectus, fringilla pharetra sem hendrerit sit amet. Cras quis lobortis nisi, id interdum massa. Proin eget porttitor sapien. Vivamus quam odio, consectetur at rhoncus vel, posuere in nisi. Donec hendrerit urna ac massa tristique, pellentesque consequat orci dapibus. Mauris mi erat, aliquet id adipiscing ultricies, ultrices nec lacus. Proin imperdiet elit magna, ut suscipit metus faucibus eget. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas at leo lorem. Donec mi nibh, blandit ut mi quis, dictum adipiscing ante. Curabitur sodales blandit odio id viverra. Fusce sagittis rutrum nibh. Mauris risus lacus, placerat at dictum in, varius volutpat quam. + +Ut accumsan tincidunt dui, non semper lorem sodales nec. Curabitur pellentesque velit nec erat ultrices, in convallis diam suscipit. Curabitur pellentesque convallis mi. Phasellus iaculis orci quis nisi semper auctor. Vestibulum eleifend tortor quis odio feugiat, pulvinar congue turpis blandit. Sed viverra diam risus, vel mattis orci dignissim ut. Cras pellentesque dapibus dolor. Morbi tempor eleifend magna. Ut sodales ut sapien sed elementum. In hac habitasse platea dictumst. + +Nullam eget sagittis tellus. Donec a tellus id ligula viverra pellentesque. Pellentesque nulla turpis, pretium vel sem vel, placerat ultricies diam. Donec felis nibh, rhoncus id ornare at, lobortis vel massa. Nullam eu luctus ipsum. Mauris consequat dictum aliquam. Suspendisse ullamcorper aliquam mauris, viverra tincidunt augue suscipit at. Sed luctus scelerisque justo ut semper. Phasellus massa mauris, molestie at nulla eget, dictum ultricies nisi. Aliquam rhoncus nisl sed urna egestas, vel luctus lectus euismod. Mauris sagittis dapibus leo. Donec vitae dignissim risus, ac ultricies augue. Ut vulputate tortor sed dui consectetur placerat. Nullam viverra non diam vel dignissim. + +Suspendisse potenti. Integer facilisis neque vitae euismod adipiscing. Aenean dictum leo commodo dui sodales, sit amet volutpat mauris gravida. Proin tempus convallis eros at consectetur. Proin nisl purus, dictum vel euismod ut, imperdiet quis est. Etiam sollicitudin lobortis neque eget pulvinar. Etiam venenatis vel sem ut posuere. Aliquam consectetur rhoncus facilisis. Morbi a viverra orci. + +Praesent ut vehicula orci, vel convallis risus. Suspendisse consectetur varius interdum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin vel sodales enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur suscipit tristique justo vel dapibus. Sed tincidunt mattis massa a auctor. Donec in tincidunt elit. Curabitur interdum neque at ante fringilla tempus. In hac habitasse platea dictumst. Vivamus luctus ligula ut nisl fermentum egestas. Praesent pulvinar accumsan neque. Sed nec leo sit amet arcu vehicula vehicula non ac diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; + +Morbi vel arcu quis neque dictum ullamcorper. Pellentesque condimentum consequat lacinia. Vestibulum eleifend placerat erat, eu hendrerit dui pulvinar eget. Vestibulum accumsan, lectus id vehicula fringilla, erat eros dictum massa, ut tristique libero mi eu ante. In at ante nunc. Praesent sodales ullamcorper porta. Curabitur egestas odio elit. Praesent et libero malesuada, venenatis lorem vitae, eleifend nisl. Donec dapibus euismod turpis, nec porttitor turpis dapibus ac. Fusce iaculis lacus eget dictum aliquam. Sed dictum eu enim ac posuere. Ut accumsan, ipsum et laoreet consectetur, ipsum quam dapibus diam, ac molestie ligula dui id massa. Nulla aliquam mauris congue nibh vestibulum imperdiet. + +Aenean ultricies, orci vel consectetur suscipit, ante nisi eleifend est, vitae suscipit risus erat dictum dui. Ut nisi diam, tristique sed nisl nec, aliquam gravida orci. Vestibulum in molestie sem. Ut eu molestie mi. Suspendisse potenti. Nunc sagittis lorem ut est vehicula, vitae imperdiet leo rutrum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec pharetra urna pretium, faucibus orci cursus, sodales purus. Duis iaculis dignissim augue, non aliquet ligula elementum quis. Sed tempus a nisi et faucibus. Donec mattis ligula ac sem aliquam, sed sodales est ullamcorper. Cras vel orci est. Integer eget ultricies nisi. + +Quisque rhoncus, nisl vel auctor consectetur, sapien augue iaculis urna, quis suscipit arcu dolor ac est. Fusce sit amet quam lacinia, malesuada lorem vitae, dapibus justo. Mauris eget massa nec dolor volutpat tempor ut eu ante. Donec risus mi, aliquam at euismod vulputate, ullamcorper non leo. Etiam ac elit velit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sollicitudin enim sed felis pharetra, a convallis mi venenatis. Donec convallis non velit venenatis suscipit. Sed massa risus, dictum quis aliquam ut, placerat quis arcu. Donec at nisi neque. Nullam porta et mi vel ultricies. Donec vel aliquam sem. Mauris varius, ipsum interdum mattis rhoncus, nunc nisl vehicula tortor, quis condimentum nibh nisl vel ante. Sed vel pretium dui. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce pulvinar molestie neque, quis luctus ante. + +Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec ac ipsum egestas, luctus urna aliquet, fringilla tortor. Cras eleifend sed tellus tempor congue. Integer venenatis magna dignissim pharetra cursus. Nulla volutpat, sem sit amet malesuada laoreet, odio libero consectetur orci, sit amet pellentesque neque ligula quis libero. Morbi nec interdum metus, in imperdiet justo. Fusce euismod egestas nulla et elementum. Etiam aliquam lectus quis eros semper, sed dapibus velit ultrices. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Proin sed elit vel massa placerat mattis et vel mauris. Aliquam accumsan ante ligula, at accumsan enim pellentesque sit amet. Sed eget quam vel nunc molestie iaculis vitae nec massa. Vivamus sed accumsan libero. Duis pretium quam at blandit sollicitudin. Nullam sodales sit amet elit ac adipiscing. Ut ullamcorper dignissim sapien. Nulla facilisi. Fusce sed consequat lectus, et tempus ipsum. Aliquam vestibulum lectus vitae quam mollis, et adipiscing nisl lobortis diff --git a/tests/karma.config.js b/tests/karma.config.js index 529bd31338f..338e3f868e9 100644 --- a/tests/karma.config.js +++ b/tests/karma.config.js @@ -121,6 +121,9 @@ module.exports = function(config) { files.push('apps/' + appsToTest[i] + '/tests/js/*.js'); } + // serve images to avoid warnings + files.push({pattern: 'core/img/**/*', watched: false, included: false, served: true}); + config.set({ // base path, that will be used to resolve files and exclude @@ -137,6 +140,11 @@ module.exports = function(config) { ], + proxies: { + // prevent warnings for images + '/context.html//core/img/': 'http://localhost:9876/base/core/img/' + }, + // test results reporter to use // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' reporters: ['dots', 'junit', 'coverage'], @@ -167,7 +175,7 @@ module.exports = function(config) { logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, + autoWatch: true, // Start these browsers, currently available: // - Chrome diff --git a/tests/lib/api.php b/tests/lib/api.php index 233beebd68a..0f7d08543ea 100644 --- a/tests/lib/api.php +++ b/tests/lib/api.php @@ -37,7 +37,7 @@ class Test_API extends PHPUnit_Framework_TestCase { function dataProviderTestOneResult() { return array( array(100, true), - array(101, true), + array(101, false), array(997, false), ); } diff --git a/tests/lib/appframework/dependencyinjection/DIContainerTest.php b/tests/lib/appframework/dependencyinjection/DIContainerTest.php index f3ebff0207f..d1bc900fb28 100644 --- a/tests/lib/appframework/dependencyinjection/DIContainerTest.php +++ b/tests/lib/appframework/dependencyinjection/DIContainerTest.php @@ -70,7 +70,7 @@ class DIContainerTest extends \PHPUnit_Framework_TestCase { public function testMiddlewareDispatcherIncludesSecurityMiddleware(){ - $this->container['Request'] = new Request(); + $this->container['Request'] = new Request(array('method' => 'GET')); $security = $this->container['SecurityMiddleware']; $dispatcher = $this->container['MiddlewareDispatcher']; diff --git a/tests/lib/appframework/http/JSONResponseTest.php b/tests/lib/appframework/http/JSONResponseTest.php index 534c54cbcee..b9b7c7d6382 100644 --- a/tests/lib/appframework/http/JSONResponseTest.php +++ b/tests/lib/appframework/http/JSONResponseTest.php @@ -28,6 +28,7 @@ namespace OC\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http; //require_once(__DIR__ . "/../classloader.php"); @@ -95,4 +96,13 @@ class JSONResponseTest extends \PHPUnit_Framework_TestCase { $this->assertEquals($code, $response->getStatus()); } + public function testChainability() { + $params = array('hi', 'yo'); + $this->json->setData($params) + ->setStatus(Http::STATUS_NOT_FOUND); + + $this->assertEquals(Http::STATUS_NOT_FOUND, $this->json->getStatus()); + $this->assertEquals(array('hi', 'yo'), $this->json->getData()); + } + } diff --git a/tests/lib/appframework/http/RequestTest.php b/tests/lib/appframework/http/RequestTest.php index 00473a8c44f..58828d17bb2 100644 --- a/tests/lib/appframework/http/RequestTest.php +++ b/tests/lib/appframework/http/RequestTest.php @@ -18,6 +18,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { stream_wrapper_unregister('fakeinput'); } stream_wrapper_register('fakeinput', 'RequestStream'); + $this->stream = 'fakeinput://data'; } public function tearDown() { @@ -30,7 +31,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'method' => 'GET', ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); // Countable $this->assertEquals(2, count($request)); @@ -54,9 +55,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), 'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'), 'urlParams' => array('user' => 'jw', 'name' => 'Johnny Weissmüller'), + 'method' => 'GET' ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $this->assertEquals(3, count($request)); $this->assertEquals('Janey', $request->{'nickname'}); @@ -70,9 +72,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase { public function testImmutableArrayAccess() { $vars = array( 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + 'method' => 'GET' ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $request['nickname'] = 'Janey'; } @@ -82,9 +85,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase { public function testImmutableMagicAccess() { $vars = array( 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + 'method' => 'GET' ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $request->{'nickname'} = 'Janey'; } @@ -97,7 +101,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'method' => 'GET', ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $result = $request->post; } @@ -107,7 +111,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'method' => 'GET', ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $this->assertEquals('GET', $request->method); $result = $request->get; $this->assertEquals('John Q. Public', $result['name']); @@ -119,10 +123,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase { $data = '{"name": "John Q. Public", "nickname": "Joey"}'; $vars = array( 'method' => 'POST', - 'server' => array('CONTENT_TYPE' => 'application/json; utf-8'), + 'server' => array('CONTENT_TYPE' => 'application/json; utf-8') ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $this->assertEquals('POST', $request->method); $result = $request->post; $this->assertEquals('John Q. Public', $result['name']); @@ -140,7 +144,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'server' => array('CONTENT_TYPE' => 'application/x-www-form-urlencoded'), ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $this->assertEquals('PATCH', $request->method); $result = $request->patch; @@ -159,7 +163,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'server' => array('CONTENT_TYPE' => 'application/json; utf-8'), ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $this->assertEquals('PUT', $request->method); $result = $request->put; @@ -174,7 +178,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'server' => array('CONTENT_TYPE' => 'application/json; utf-8'), ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $this->assertEquals('PATCH', $request->method); $result = $request->patch; @@ -193,7 +197,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { 'server' => array('CONTENT_TYPE' => 'image/png'), ); - $request = new Request($vars); + $request = new Request($vars, $this->stream); $this->assertEquals('PUT', $request->method); $resource = $request->put; $contents = stream_get_contents($resource); diff --git a/tests/lib/appframework/http/ResponseTest.php b/tests/lib/appframework/http/ResponseTest.php index 063ab8b5d33..27350725d79 100644 --- a/tests/lib/appframework/http/ResponseTest.php +++ b/tests/lib/appframework/http/ResponseTest.php @@ -117,5 +117,25 @@ class ResponseTest extends \PHPUnit_Framework_TestCase { $this->assertEquals('Thu, 01 Jan 1970 00:00:01 +0000', $headers['Last-Modified']); } + public function testChainability() { + $lastModified = new \DateTime(null, new \DateTimeZone('GMT')); + $lastModified->setTimestamp(1); + + $this->childResponse->setEtag('hi') + ->setStatus(Http::STATUS_NOT_FOUND) + ->setLastModified($lastModified) + ->cacheFor(33) + ->addHeader('hello', 'world'); + + $headers = $this->childResponse->getHeaders(); + + $this->assertEquals('world', $headers['hello']); + $this->assertEquals(Http::STATUS_NOT_FOUND, $this->childResponse->getStatus()); + $this->assertEquals('hi', $this->childResponse->getEtag()); + $this->assertEquals('Thu, 01 Jan 1970 00:00:01 +0000', $headers['Last-Modified']); + $this->assertEquals('max-age=33, must-revalidate', + $headers['Cache-Control']); + + } } diff --git a/tests/lib/appframework/http/TemplateResponseTest.php b/tests/lib/appframework/http/TemplateResponseTest.php index a583d9da14f..0b158edff6f 100644 --- a/tests/lib/appframework/http/TemplateResponseTest.php +++ b/tests/lib/appframework/http/TemplateResponseTest.php @@ -25,6 +25,7 @@ namespace OC\AppFramework\Http; use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Http; class TemplateResponseTest extends \PHPUnit_Framework_TestCase { @@ -98,4 +99,13 @@ class TemplateResponseTest extends \PHPUnit_Framework_TestCase { $this->assertEquals($render, $this->tpl->getRenderAs()); } + public function testChainability() { + $params = array('hi' => 'yo'); + $this->tpl->setParams($params) + ->setStatus(Http::STATUS_NOT_FOUND); + + $this->assertEquals(Http::STATUS_NOT_FOUND, $this->tpl->getStatus()); + $this->assertEquals(array('hi' => 'yo'), $this->tpl->getParams()); + } + } diff --git a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php index f16b14150c3..935f97d2a6f 100644 --- a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php +++ b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php @@ -132,7 +132,7 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { private function getControllerMock(){ return $this->getMock('OCP\AppFramework\Controller', array('method'), - array($this->getAPIMock(), new Request())); + array($this->getAPIMock(), new Request(array('method' => 'GET')))); } diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php index 9f2675bf0b4..261ab0b26af 100644 --- a/tests/lib/appframework/routing/RoutingTest.php +++ b/tests/lib/appframework/routing/RoutingTest.php @@ -36,6 +36,16 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open'); } + public function testSimpleRouteWithRequirements() + { + $routes = array('routes' => array( + array('name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'requirements' => array('something')) + )); + + $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open', array('something')); + } + + /** * @expectedException \UnexpectedValueException */ @@ -85,10 +95,10 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase * @param string $controllerName * @param string $actionName */ - private function assertSimpleRoute($routes, $name, $verb, $url, $controllerName, $actionName) + private function assertSimpleRoute($routes, $name, $verb, $url, $controllerName, $actionName, array $requirements=array()) { // route mocks - $route = $this->mockRoute($verb, $controllerName, $actionName); + $route = $this->mockRoute($verb, $controllerName, $actionName, $requirements); // router mock $router = $this->getMock("\OC\Route\Router", array('create')); @@ -166,15 +176,15 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase } /** - * @param $verb - * @param $controllerName - * @param $actionName + * @param string $verb + * @param string $controllerName + * @param string $actionName * @return \PHPUnit_Framework_MockObject_MockObject */ - private function mockRoute($verb, $controllerName, $actionName) + private function mockRoute($verb, $controllerName, $actionName, array $requirements=array()) { $container = new DIContainer('app1'); - $route = $this->getMock("\OC\Route\Route", array('method', 'action'), array(), '', false); + $route = $this->getMock("\OC\Route\Route", array('method', 'action', 'requirements'), array(), '', false); $route ->expects($this->exactly(1)) ->method('method') @@ -186,6 +196,14 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase ->method('action') ->with($this->equalTo(new RouteActionHandler($container, $controllerName, $actionName))) ->will($this->returnValue($route)); + + if(count($requirements) > 0) { + $route + ->expects($this->exactly(1)) + ->method('requirements') + ->with($this->equalTo($requirements)) + ->will($this->returnValue($route)); + } return $route; } diff --git a/tests/lib/dbschema.php b/tests/lib/dbschema.php index 11e9fcdf4fa..cfa2d6fd9aa 100644 --- a/tests/lib/dbschema.php +++ b/tests/lib/dbschema.php @@ -71,6 +71,9 @@ class Test_DBSchema extends PHPUnit_Framework_TestCase { $this->assertTableNotExist($this->table2); } + /** + * @param string $table + */ public function tableExist($table) { switch (OC_Config::getValue( 'dbtype', 'sqlite' )) { diff --git a/tests/lib/files/filesystem.php b/tests/lib/files/filesystem.php index 90f1dfe581b..53f528af793 100644 --- a/tests/lib/files/filesystem.php +++ b/tests/lib/files/filesystem.php @@ -226,4 +226,55 @@ class Filesystem extends \PHPUnit_Framework_TestCase { $path = $arguments['path']; $this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized } + + /** + * Test that the default cache dir is part of the user's home + */ + public function testMountDefaultCacheDir() { + $userId = uniqid('user_'); + $oldCachePath = \OC_Config::getValue('cache_path', ''); + // no cache path configured + \OC_Config::setValue('cache_path', ''); + + \OC_User::createUser($userId, $userId); + \OC\Files\Filesystem::initMountPoints($userId); + + $this->assertEquals( + '/' . $userId . '/', + \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache') + ); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache'); + $this->assertInstanceOf('\OC\Files\Storage\Home', $storage); + $this->assertEquals('cache', $internalPath); + \OC_User::deleteUser($userId); + + \OC_Config::setValue('cache_path', $oldCachePath); + } + + /** + * Test that an external cache is mounted into + * the user's home + */ + public function testMountExternalCacheDir() { + $userId = uniqid('user_'); + + $oldCachePath = \OC_Config::getValue('cache_path', ''); + // set cache path to temp dir + $cachePath = \OC_Helper::tmpFolder() . '/extcache'; + \OC_Config::setValue('cache_path', $cachePath); + + \OC_User::createUser($userId, $userId); + \OC\Files\Filesystem::initMountPoints($userId); + + $this->assertEquals( + '/' . $userId . '/cache/', + \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache') + ); + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache'); + $this->assertInstanceOf('\OC\Files\Storage\Local', $storage); + $this->assertEquals('', $internalPath); + \OC_User::deleteUser($userId); + + \OC_Config::setValue('cache_path', $oldCachePath); + } } diff --git a/tests/lib/files/storage/storage.php b/tests/lib/files/storage/storage.php index f9291758606..38cd17ac8c9 100644 --- a/tests/lib/files/storage/storage.php +++ b/tests/lib/files/storage/storage.php @@ -64,17 +64,17 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { * @dataProvider directoryProvider */ public function testDirectories($directory) { - $this->assertFalse($this->instance->file_exists('/'.$directory)); + $this->assertFalse($this->instance->file_exists('/' . $directory)); - $this->assertTrue($this->instance->mkdir('/'.$directory)); + $this->assertTrue($this->instance->mkdir('/' . $directory)); - $this->assertTrue($this->instance->file_exists('/'.$directory)); - $this->assertTrue($this->instance->is_dir('/'.$directory)); - $this->assertFalse($this->instance->is_file('/'.$directory)); - $this->assertEquals('dir', $this->instance->filetype('/'.$directory)); - $this->assertEquals(0, $this->instance->filesize('/'.$directory)); - $this->assertTrue($this->instance->isReadable('/'.$directory)); - $this->assertTrue($this->instance->isUpdatable('/'.$directory)); + $this->assertTrue($this->instance->file_exists('/' . $directory)); + $this->assertTrue($this->instance->is_dir('/' . $directory)); + $this->assertFalse($this->instance->is_file('/' . $directory)); + $this->assertEquals('dir', $this->instance->filetype('/' . $directory)); + $this->assertEquals(0, $this->instance->filesize('/' . $directory)); + $this->assertTrue($this->instance->isReadable('/' . $directory)); + $this->assertTrue($this->instance->isUpdatable('/' . $directory)); $dh = $this->instance->opendir('/'); $content = array(); @@ -85,13 +85,13 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { } $this->assertEquals(array($directory), $content); - $this->assertFalse($this->instance->mkdir('/'.$directory)); //cant create existing folders - $this->assertTrue($this->instance->rmdir('/'.$directory)); + $this->assertFalse($this->instance->mkdir('/' . $directory)); //cant create existing folders + $this->assertTrue($this->instance->rmdir('/' . $directory)); $this->wait(); - $this->assertFalse($this->instance->file_exists('/'.$directory)); + $this->assertFalse($this->instance->file_exists('/' . $directory)); - $this->assertFalse($this->instance->rmdir('/'.$directory)); //cant remove non existing folders + $this->assertFalse($this->instance->rmdir('/' . $directory)); //cant remove non existing folders $dh = $this->instance->opendir('/'); $content = array(); @@ -103,8 +103,7 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { $this->assertEquals(array(), $content); } - public function directoryProvider() - { + public function directoryProvider() { return array( array('folder'), array(' folder'), @@ -113,11 +112,23 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { array('spéciäl földer'), ); } + + function loremFileProvider() { + $root = \OC::$SERVERROOT . '/tests/data/'; + return array( + // small file + array($root . 'lorem.txt'), + // bigger file (> 8 KB which is the standard PHP block size) + array($root . 'lorem-big.txt') + ); + } + /** * test the various uses of file_get_contents and file_put_contents + * + * @dataProvider loremFileProvider */ - public function testGetPutContents() { - $sourceFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + public function testGetPutContents($sourceFile) { $sourceText = file_get_contents($sourceFile); //fill a file with string data @@ -298,4 +309,40 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { $this->assertFalse($this->instance->file_exists('folder/bar')); $this->assertFalse($this->instance->file_exists('folder')); } + + public function hashProvider() { + return array( + array('Foobar', 'md5'), + array('Foobar', 'sha1'), + array('Foobar', 'sha256'), + ); + } + + /** + * @dataProvider hashProvider + */ + public function testHash($data, $type) { + $this->instance->file_put_contents('hash.txt', $data); + $this->assertEquals(hash($type, $data), $this->instance->hash($type, 'hash.txt')); + $this->assertEquals(hash($type, $data, true), $this->instance->hash($type, 'hash.txt', true)); + } + + public function testHashInFileName() { + $this->instance->file_put_contents('#test.txt', 'data'); + $this->assertEquals('data', $this->instance->file_get_contents('#test.txt')); + + $this->instance->mkdir('#foo'); + $this->instance->file_put_contents('#foo/test.txt', 'data'); + $this->assertEquals('data', $this->instance->file_get_contents('#foo/test.txt')); + + $dh = $this->instance->opendir('#foo'); + $content = array(); + while ($file = readdir($dh)) { + if ($file != '.' and $file != '..') { + $content[] = $file; + } + } + + $this->assertEquals(array('test.txt'), $content); + } } diff --git a/tests/lib/group/group.php b/tests/lib/group/group.php index 3982c00e45f..147532f9947 100644 --- a/tests/lib/group/group.php +++ b/tests/lib/group/group.php @@ -299,6 +299,68 @@ class Group extends \PHPUnit_Framework_TestCase { $this->assertEquals('user1', $user1->getUID()); } + public function testCountUsers() { + $backend1 = $this->getMock('OC_Group_Database'); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', array($backend1), $userManager); + + $backend1->expects($this->once()) + ->method('countUsersInGroup') + ->with('group1', '2') + ->will($this->returnValue(3)); + + $backend1->expects($this->any()) + ->method('implementsActions') + ->will($this->returnValue(true)); + + $users = $group->count('2'); + + $this->assertSame(3, $users); + } + + public function testCountUsersMultipleBackends() { + $backend1 = $this->getMock('OC_Group_Database'); + $backend2 = $this->getMock('OC_Group_Database'); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', array($backend1, $backend2), $userManager); + + $backend1->expects($this->once()) + ->method('countUsersInGroup') + ->with('group1', '2') + ->will($this->returnValue(3)); + $backend1->expects($this->any()) + ->method('implementsActions') + ->will($this->returnValue(true)); + + $backend2->expects($this->once()) + ->method('countUsersInGroup') + ->with('group1', '2') + ->will($this->returnValue(4)); + $backend2->expects($this->any()) + ->method('implementsActions') + ->will($this->returnValue(true)); + + $users = $group->count('2'); + + $this->assertSame(7, $users); + } + + public function testCountUsersNoMethod() { + $backend1 = $this->getMock('OC_Group_Database'); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', array($backend1), $userManager); + + $backend1->expects($this->never()) + ->method('countUsersInGroup'); + $backend1->expects($this->any()) + ->method('implementsActions') + ->will($this->returnValue(false)); + + $users = $group->count('2'); + + $this->assertSame(false, $users); + } + public function testDelete() { $backend = $this->getMock('OC_Group_Database'); $userManager = $this->getUserManager(); diff --git a/tests/lib/mail.php b/tests/lib/mail.php index a88a9d797ae..3cc9868e25e 100644 --- a/tests/lib/mail.php +++ b/tests/lib/mail.php @@ -8,6 +8,15 @@ class Test_Mail extends PHPUnit_Framework_TestCase { + protected function setUp() + { + if (!function_exists('idn_to_ascii')) { + $this->markTestSkipped( + 'The intl extension is not available.' + ); + } + } + /** * @dataProvider buildAsciiEmailProvider * @param $expected diff --git a/tests/lib/preview.php b/tests/lib/preview.php index 353b66fd6d6..4ef61fb8257 100644 --- a/tests/lib/preview.php +++ b/tests/lib/preview.php @@ -10,66 +10,73 @@ namespace Test; class Preview extends \PHPUnit_Framework_TestCase { - public function testIsPreviewDeleted() { - $user = $this->initFS(); + /** + * @var string + */ + private $user; + + /** + * @var \OC\Files\View + */ + private $rootView; + + public function setUp() { + $this->user = $this->initFS(); - $rootView = new \OC\Files\View(''); - $rootView->mkdir('/'.$user); - $rootView->mkdir('/'.$user.'/files'); + $this->rootView = new \OC\Files\View(''); + $this->rootView->mkdir('/'.$this->user); + $this->rootView->mkdir('/'.$this->user.'/files'); + } + + public function testIsPreviewDeleted() { - $samplefile = '/'.$user.'/files/test.txt'; + $sampleFile = '/'.$this->user.'/files/test.txt'; - $rootView->file_put_contents($samplefile, 'dummy file data'); + $this->rootView->file_put_contents($sampleFile, 'dummy file data'); $x = 50; $y = 50; - $preview = new \OC\Preview($user, 'files/', 'test.txt', $x, $y); + $preview = new \OC\Preview($this->user, 'files/', 'test.txt', $x, $y); $preview->getPreview(); - $fileinfo = $rootView->getFileInfo($samplefile); - $fileid = $fileinfo['fileid']; + $fileInfo = $this->rootView->getFileInfo($sampleFile); + $fileId = $fileInfo['fileid']; - $thumbcachefile = '/' . $user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileid . '/' . $x . '-' . $y . '.png'; + $thumbCacheFile = '/' . $this->user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileId . '/' . $x . '-' . $y . '.png'; - $this->assertEquals($rootView->file_exists($thumbcachefile), true); + $this->assertEquals($this->rootView->file_exists($thumbCacheFile), true); $preview->deletePreview(); - $this->assertEquals($rootView->file_exists($thumbcachefile), false); + $this->assertEquals($this->rootView->file_exists($thumbCacheFile), false); } public function testAreAllPreviewsDeleted() { - $user = $this->initFS(); - $rootView = new \OC\Files\View(''); - $rootView->mkdir('/'.$user); - $rootView->mkdir('/'.$user.'/files'); + $sampleFile = '/'.$this->user.'/files/test.txt'; - $samplefile = '/'.$user.'/files/test.txt'; - - $rootView->file_put_contents($samplefile, 'dummy file data'); + $this->rootView->file_put_contents($sampleFile, 'dummy file data'); $x = 50; $y = 50; - $preview = new \OC\Preview($user, 'files/', 'test.txt', $x, $y); + $preview = new \OC\Preview($this->user, 'files/', 'test.txt', $x, $y); $preview->getPreview(); - $fileinfo = $rootView->getFileInfo($samplefile); - $fileid = $fileinfo['fileid']; + $fileInfo = $this->rootView->getFileInfo($sampleFile); + $fileId = $fileInfo['fileid']; - $thumbcachefolder = '/' . $user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileid . '/'; + $thumbCacheFolder = '/' . $this->user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileId . '/'; - $this->assertEquals($rootView->is_dir($thumbcachefolder), true); + $this->assertEquals($this->rootView->is_dir($thumbCacheFolder), true); $preview->deleteAllPreviews(); - $this->assertEquals($rootView->is_dir($thumbcachefolder), false); + $this->assertEquals($this->rootView->is_dir($thumbCacheFolder), false); } public function testIsMaxSizeWorking() { - $user = $this->initFS(); $maxX = 250; $maxY = 250; @@ -77,15 +84,11 @@ class Preview extends \PHPUnit_Framework_TestCase { \OC_Config::setValue('preview_max_x', $maxX); \OC_Config::setValue('preview_max_y', $maxY); - $rootView = new \OC\Files\View(''); - $rootView->mkdir('/'.$user); - $rootView->mkdir('/'.$user.'/files'); - - $samplefile = '/'.$user.'/files/test.txt'; + $sampleFile = '/'.$this->user.'/files/test.txt'; - $rootView->file_put_contents($samplefile, 'dummy file data'); + $this->rootView->file_put_contents($sampleFile, 'dummy file data'); - $preview = new \OC\Preview($user, 'files/', 'test.txt', 1000, 1000); + $preview = new \OC\Preview($this->user, 'files/', 'test.txt', 1000, 1000); $image = $preview->getPreview(); $this->assertEquals($image->width(), $maxX); @@ -108,18 +111,13 @@ class Preview extends \PHPUnit_Framework_TestCase { * @dataProvider txtBlacklist */ public function testIsTransparent($extension, $data, $expectedResult) { - $user = $this->initFS(); - - $rootView = new \OC\Files\View(''); - $rootView->mkdir('/'.$user); - $rootView->mkdir('/'.$user.'/files'); $x = 32; $y = 32; - $sample = '/'.$user.'/files/test.'.$extension; - $rootView->file_put_contents($sample, $data); - $preview = new \OC\Preview($user, 'files/', 'test.'.$extension, $x, $y); + $sample = '/'.$this->user.'/files/test.'.$extension; + $this->rootView->file_put_contents($sample, $data); + $preview = new \OC\Preview($this->user, 'files/', 'test.'.$extension, $x, $y); $image = $preview->getPreview(); $resource = $image->resource(); @@ -133,6 +131,64 @@ class Preview extends \PHPUnit_Framework_TestCase { ); } + public function testCreationFromCached() { + + $sampleFile = '/'.$this->user.'/files/test.txt'; + + $this->rootView->file_put_contents($sampleFile, 'dummy file data'); + + // create base preview + $x = 150; + $y = 150; + + $preview = new \OC\Preview($this->user, 'files/', 'test.txt', $x, $y); + $preview->getPreview(); + + $fileInfo = $this->rootView->getFileInfo($sampleFile); + $fileId = $fileInfo['fileid']; + + $thumbCacheFile = '/' . $this->user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileId . '/' . $x . '-' . $y . '.png'; + + $this->assertEquals($this->rootView->file_exists($thumbCacheFile), true); + + + // create smaller previews + $preview = new \OC\Preview($this->user, 'files/', 'test.txt', 50, 50); + $isCached = $preview->isCached($fileId); + + $this->assertEquals($this->user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileId . '/150-150.png', $isCached); + } + + /* + public function testScalingUp() { + + $sampleFile = '/'.$this->user.'/files/test.txt'; + + $this->rootView->file_put_contents($sampleFile, 'dummy file data'); + + // create base preview + $x = 150; + $y = 150; + + $preview = new \OC\Preview($this->user, 'files/', 'test.txt', $x, $y); + $preview->getPreview(); + + $fileInfo = $this->rootView->getFileInfo($sampleFile); + $fileId = $fileInfo['fileid']; + + $thumbCacheFile = '/' . $this->user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileId . '/' . $x . '-' . $y . '.png'; + + $this->assertEquals($this->rootView->file_exists($thumbCacheFile), true); + + + // create bigger previews - with scale up + $preview = new \OC\Preview($this->user, 'files/', 'test.txt', 250, 250); + $isCached = $preview->isCached($fileId); + + $this->assertEquals($this->user . '/' . \OC\Preview::THUMBNAILS_FOLDER . '/' . $fileId . '/150-150.png', $isCached); + } + */ + private function initFS() { // create a new user with his own filesystem view // this gets called by each test in this test class diff --git a/tests/lib/public/ocpconfig.php b/tests/lib/public/ocpconfig.php new file mode 100644 index 00000000000..43a9ca625ee --- /dev/null +++ b/tests/lib/public/ocpconfig.php @@ -0,0 +1,37 @@ +. + */ + +class Test_OCPConfig extends PHPUnit_Framework_TestCase +{ + + public function testSetAppValueIfSetToNull() { + + $key = uniqid("key-"); + + $result = \OCP\Config::setAppValue('unit-test', $key, null); + $this->assertTrue($result); + + $result = \OCP\Config::setAppValue('unit-test', $key, '12'); + $this->assertTrue($result); + + } + +} diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index b5cba9430aa..aae91fa1087 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -282,7 +282,7 @@ class Test_Share extends PHPUnit_Framework_TestCase { OC_User::setUserId($this->user2); $this->assertEquals(array(OCP\PERMISSION_READ), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS)); OC_User::setUserId($this->user3); - $this->assertFalse(OCP\Share::getItemSharedWith('test', 'test.txt')); + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt')); // Reshare again, and then have owner unshare OC_User::setUserId($this->user1); @@ -292,9 +292,9 @@ class Test_Share extends PHPUnit_Framework_TestCase { OC_User::setUserId($this->user1); $this->assertTrue(OCP\Share::unshare('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2)); OC_User::setUserId($this->user2); - $this->assertFalse(OCP\Share::getItemSharedWith('test', 'test.txt')); + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt')); OC_User::setUserId($this->user3); - $this->assertFalse(OCP\Share::getItemSharedWith('test', 'test.txt')); + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt')); // Attempt target conflict OC_User::setUserId($this->user1); @@ -325,7 +325,7 @@ class Test_Share extends PHPUnit_Framework_TestCase { ); OC_User::setUserId($this->user2); - $this->assertFalse( + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE), 'Failed asserting that user 2 no longer has access to test.txt after expiration.' ); @@ -526,13 +526,13 @@ class Test_Share extends PHPUnit_Framework_TestCase { ); OC_User::setUserId($this->user2); - $this->assertFalse( + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE), 'Failed asserting that user 2 no longer has access to test.txt after expiration.' ); OC_User::setUserId($this->user3); - $this->assertFalse( + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE), 'Failed asserting that user 3 no longer has access to test.txt after expiration.' ); diff --git a/tests/lib/urlgenerator.php b/tests/lib/urlgenerator.php index 875a7f06580..8e605d88f32 100644 --- a/tests/lib/urlgenerator.php +++ b/tests/lib/urlgenerator.php @@ -12,17 +12,32 @@ class Test_Urlgenerator extends PHPUnit_Framework_TestCase { /** * @small * @brief test absolute URL construction - * @dataProvider provideURLs + * @dataProvider provideDocRootURLs */ - function testGetAbsoluteURL($url, $expectedResult) { + function testGetAbsoluteURLDocRoot($url, $expectedResult) { + \OC::$WEBROOT = ''; $urlGenerator = new \OC\URLGenerator(null); $result = $urlGenerator->getAbsoluteURL($url); $this->assertEquals($expectedResult, $result); } - public function provideURLs() { + /** + * @small + * @brief test absolute URL construction + * @dataProvider provideSubDirURLs + */ + function testGetAbsoluteURLSubDir($url, $expectedResult) { + + \OC::$WEBROOT = '/owncloud'; + $urlGenerator = new \OC\URLGenerator(null); + $result = $urlGenerator->getAbsoluteURL($url); + + $this->assertEquals($expectedResult, $result); + } + + public function provideDocRootURLs() { return array( array("index.php", "http://localhost/index.php"), array("/index.php", "http://localhost/index.php"), @@ -30,5 +45,14 @@ class Test_Urlgenerator extends PHPUnit_Framework_TestCase { array("apps/index.php", "http://localhost/apps/index.php"), ); } + + public function provideSubDirURLs() { + return array( + array("index.php", "http://localhost/owncloud/index.php"), + array("/index.php", "http://localhost/owncloud/index.php"), + array("/apps/index.php", "http://localhost/owncloud/apps/index.php"), + array("apps/index.php", "http://localhost/owncloud/apps/index.php"), + ); + } }