diff --git a/apps/files/ajax/delete.php b/apps/files/ajax/delete.php
deleted file mode 100644
index 2d02869df14f135c3d6fdffa0116af638a77dbef..0000000000000000000000000000000000000000
--- a/apps/files/ajax/delete.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program 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, version 3,
- * along with this program.  If not, see <http://www.gnu.org/licenses/>
- *
- */
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-
-// Get data
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$allFiles = isset($_POST["allfiles"]) ? (string)$_POST["allfiles"] : false;
-
-// delete all files in dir ?
-if ($allFiles === 'true') {
-	$files = array();
-	$fileList = \OC\Files\Filesystem::getDirectoryContent($dir);
-	foreach ($fileList as $fileInfo) {
-		$files[] = $fileInfo['name'];
-	}
-} else {
-	$files = isset($_POST["file"]) ? (string)$_POST["file"] : (string)$_POST["files"];
-	$files = json_decode($files);
-}
-$filesWithError = '';
-
-$success = true;
-
-//Now delete
-foreach ($files as $file) {
-	try {
-		if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) &&
-			!(\OC\Files\Filesystem::isDeletable($dir . '/' . $file) &&
-				\OC\Files\Filesystem::unlink($dir . '/' . $file))
-		) {
-			$filesWithError .= $file . "\n";
-			$success = false;
-		}
-	} catch (\Exception $e) {
-		$filesWithError .= $file . "\n";
-		$success = false;
-	}
-}
-
-// get array with updated storage stats (e.g. max file size) after upload
-try {
-	$storageStats = \OCA\Files\Helper::buildFileStorageStatistics($dir);
-} catch(\OCP\Files\NotFoundException $e) {
-	OCP\JSON::error(['data' => ['message' => 'File not found']]);
-	return;
-}
-
-if ($success) {
-	OCP\JSON::success(array("data" => array_merge(array("dir" => $dir, "files" => $files), $storageStats)));
-} else {
-	OCP\JSON::error(array("data" => array_merge(array("message" => "Could not delete:\n" . $filesWithError), $storageStats)));
-}
diff --git a/apps/files/ajax/move.php b/apps/files/ajax/move.php
deleted file mode 100644
index 0961636a116bde8096b8e94574c62b210c74bc27..0000000000000000000000000000000000000000
--- a/apps/files/ajax/move.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program 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, version 3,
- * along with this program.  If not, see <http://www.gnu.org/licenses/>
- *
- */
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-// Get data
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$file = isset($_POST['file']) ? (string)$_POST['file'] : '';
-$target = isset($_POST['target']) ? rawurldecode((string)$_POST['target']) : '';
-
-$l = \OC::$server->getL10N('files');
-
-if(\OC\Files\Filesystem::file_exists($target . '/' . $file)) {
-	OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s - File with this name already exists", array($file)) )));
-	exit;
-}
-
-if ($target != '' || strtolower($file) != 'shared') {
-	$targetFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file);
-	$sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file);
-	try {
-		if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) {
-			OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file )));
-		} else {
-			OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
-		}
-	} catch (\OCP\Files\NotPermittedException $e) {
-		OCP\JSON::error(array("data" => array( "message" => $l->t("Permission denied") )));
-	} catch (\Exception $e) {
-		OCP\JSON::error(array("data" => array( "message" => $e->getMessage())));
-	}
-}else{
-	OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
-}
diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php
deleted file mode 100644
index be09b288d4b479b71205e8f4e756679ebaf91579..0000000000000000000000000000000000000000
--- a/apps/files/ajax/newfile.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-/**
- * @author Andreas Fischer <bantu@owncloud.com>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program 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, version 3,
- * along with this program.  If not, see <http://www.gnu.org/licenses/>
- *
- */
-// Init owncloud
-global $eventSource;
-
-\OCP\JSON::checkLoggedIn();
-\OCP\JSON::callCheck();
-
-\OC::$server->getSession()->close();
-
-// Get the params
-$dir = isset( $_REQUEST['dir'] ) ? '/'.trim((string)$_REQUEST['dir'], '/\\') : '';
-$fileName = isset( $_REQUEST['filename'] ) ? trim((string)$_REQUEST['filename'], '/\\') : '';
-
-$l10n = \OC::$server->getL10N('files');
-
-$result = array(
-	'success' 	=> false,
-	'data'		=> NULL
-);
-
-try {
-	\OC\Files\Filesystem::getView()->verifyPath($dir, $fileName);
-} catch (\OCP\Files\InvalidPathException $ex) {
-	$result['data'] = [
-		'message' => $ex->getMessage()];
-	OCP\JSON::error($result);
-	return;
-}
-
-if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
-	$result['data'] = array('message' => (string)$l10n->t(
-			'The target folder has been moved or deleted.'),
-			'code' => 'targetnotfound'
-		);
-	OCP\JSON::error($result);
-	exit();
-}
-
-$target = $dir.'/'.$fileName;
-
-if (\OC\Files\Filesystem::file_exists($target)) {
-	$result['data'] = array('message' => (string)$l10n->t(
-			'The name %s is already used in the folder %s. Please choose a different name.',
-			array($fileName, $dir))
-		);
-	OCP\JSON::error($result);
-	exit();
-}
-
-$success = false;
-$templateManager = OC_Helper::getFileTemplateManager();
-$mimeType = OC_Helper::getMimetypeDetector()->detectPath($target);
-$content = $templateManager->getTemplate($mimeType);
-
-try {
-	if($content) {
-		$success = \OC\Files\Filesystem::file_put_contents($target, $content);
-	} else {
-		$success = \OC\Files\Filesystem::touch($target);
-	}
-} catch (\Exception $e) {
-	$result = [
-		'success' => false,
-		'data' => [
-			'message' => $e->getMessage()
-		]
-	];
-	OCP\JSON::error($result);
-	exit();
-}
-
-if($success) {
-	$meta = \OC\Files\Filesystem::getFileInfo($target);
-	OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
-	return;
-}
-
-OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the file') )));
diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php
deleted file mode 100644
index a2897dd437ac798539937186f210f6d4ea4deabc..0000000000000000000000000000000000000000
--- a/apps/files/ajax/newfolder.php
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program 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, version 3,
- * along with this program.  If not, see <http://www.gnu.org/licenses/>
- *
- */
-// Init owncloud
-
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-// Get the params
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$folderName = isset($_POST['foldername']) ?(string) $_POST['foldername'] : '';
-
-$l10n = \OC::$server->getL10N('files');
-
-$result = array(
-	'success' 	=> false,
-	'data'		=> NULL
-	);
-
-try {
-	\OC\Files\Filesystem::getView()->verifyPath($dir, $folderName);
-} catch (\OCP\Files\InvalidPathException $ex) {
-	$result['data'] = [
-		'message' => $ex->getMessage()];
-	OCP\JSON::error($result);
-	return;
-}
-
-if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
-	$result['data'] = array('message' => (string)$l10n->t(
-			'The target folder has been moved or deleted.'),
-			'code' => 'targetnotfound'
-		);
-	OCP\JSON::error($result);
-	exit();
-}
-
-$target = $dir . '/' . $folderName;
-		
-if (\OC\Files\Filesystem::file_exists($target)) {
-	$result['data'] = array('message' => $l10n->t(
-			'The name %s is already used in the folder %s. Please choose a different name.',
-			array($folderName, $dir))
-		);
-	OCP\JSON::error($result);
-	exit();
-}
-
-try {
-	if(\OC\Files\Filesystem::mkdir($target)) {
-		if ( $dir !== '/') {
-			$path = $dir.'/'.$folderName;
-		} else {
-			$path = '/'.$folderName;
-		}
-		$meta = \OC\Files\Filesystem::getFileInfo($path);
-		$meta['type'] = 'dir'; // missing ?!
-		OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
-		exit();
-	}
-} catch (\Exception $e) {
-	$result = [
-		'success' => false,
-		'data' => [
-			'message' => $e->getMessage()
-		]
-	];
-	OCP\JSON::error($result);
-	exit();
-}
-
-OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the folder') )));
diff --git a/apps/files/ajax/rename.php b/apps/files/ajax/rename.php
deleted file mode 100644
index a24a57b10464cc47e553ead57a6da09536c6f2ad..0000000000000000000000000000000000000000
--- a/apps/files/ajax/rename.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program 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, version 3,
- * along with this program.  If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-$l10n = \OC::$server->getL10N('files');
-
-$files = new \OCA\Files\App(
-	\OC\Files\Filesystem::getView(),
-	\OC::$server->getL10N('files')
-);
-try {
-	$result = $files->rename(
-		isset($_GET['dir']) ? (string)$_GET['dir'] : '',
-		isset($_GET['file']) ? (string)$_GET['file'] : '',
-		isset($_GET['newname']) ? (string)$_GET['newname'] : ''
-	);
-} catch (\Exception $e) {
-	$result = [
-		'success' => false,
-		'data' => [
-			'message' => $e->getMessage()
-		]
-	];
-}
-
-if($result['success'] === true){
-	OCP\JSON::success(['data' => $result['data']]);
-} else {
-	OCP\JSON::error(['data' => $result['data']]);
-}
diff --git a/apps/files/js/app.js b/apps/files/js/app.js
index f31770466fed598a00fbd6dd288e0f6ef3956140..ff505d417f1ecca396a25c1f5d9c8d525d3aee03 100644
--- a/apps/files/js/app.js
+++ b/apps/files/js/app.js
@@ -71,7 +71,8 @@
 					folderDropOptions: folderDropOptions,
 					fileActions: fileActions,
 					allowLegacyActions: true,
-					scrollTo: urlParams.scrollto
+					scrollTo: urlParams.scrollto,
+					filesClient: OC.Files.getClient()
 				}
 			);
 			this.files.initialize();
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 6a767d48a289130376977c0fb224a0c70c4ff3c1..32385c424789ed416d3e515ec58794b3104e3927 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -575,7 +575,8 @@
 				},
 				actionHandler: function (filename, context) {
 					var dir = context.dir || context.fileList.getCurrentDirectory();
-					var url = context.fileList.getDownloadUrl(filename, dir);
+					var isDir = context.$file.attr('data-type') === 'dir';
+					var url = context.fileList.getDownloadUrl(filename, dir, isDir);
 
 					var downloadFileaction = $(context.$file).find('.fileactions .action-download');
 
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index d1f68d98eab041951d1a368252afaa0372ea489f..2c97816df00805fb0d187e26cf4444f8e05d3b61 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -22,11 +22,12 @@
 	 *
 	 * @param $el container element with existing markup for the #controls
 	 * and a table
-	 * @param [options] map of options, see other parameters
-	 * @param [options.scrollContainer] scrollable container, defaults to $(window)
-	 * @param [options.dragOptions] drag options, disabled by default
-	 * @param [options.folderDropOptions] folder drop options, disabled by default
-	 * @param [options.detailsViewEnabled=true] whether to enable details view
+	 * @param {Object} [options] map of options, see other parameters
+	 * @param {Object} [options.scrollContainer] scrollable container, defaults to $(window)
+	 * @param {Object} [options.dragOptions] drag options, disabled by default
+	 * @param {Object} [options.folderDropOptions] folder drop options, disabled by default
+	 * @param {boolean} [options.detailsViewEnabled=true] whether to enable details view
+	 * @param {OC.Files.Client} [options.filesClient] files client to use
 	 */
 	var FileList = function($el, options) {
 		this.initialize($el, options);
@@ -73,6 +74,13 @@
 		 */
 		_detailsView: null,
 
+		/**
+		 * Files client instance
+		 *
+		 * @type OC.Files.Client
+		 */
+		filesClient: null,
+
 		/**
 		 * Whether the file list was initialized already.
 		 * @type boolean
@@ -92,10 +100,17 @@
 		 * Array of files in the current folder.
 		 * The entries are of file data.
 		 *
-		 * @type Array.<Object>
+		 * @type Array.<OC.Files.FileInfo>
 		 */
 		files: [],
 
+		/**
+		 * Current directory entry
+		 *
+		 * @type OC.Files.FileInfo
+		 */
+		dirInfo: null,
+
 		/**
 		 * File actions handler, defaults to OCA.Files.FileActions
 		 * @type OCA.Files.FileActions
@@ -149,7 +164,7 @@
 		 * When false, clicking on a table header will call reload().
 		 * When true, clicking on a table header will simply resort the list.
 		 */
-		_clientSideSort: false,
+		_clientSideSort: true,
 
 		/**
 		 * Current directory
@@ -170,6 +185,7 @@
 		 * @param options.dragOptions drag options, disabled by default
 		 * @param options.folderDropOptions folder drop options, disabled by default
 		 * @param options.scrollTo name of file to scroll to after the first load
+		 * @param {OC.Files.Client} [options.filesClient] files API client
 		 * @private
 		 */
 		initialize: function($el, options) {
@@ -185,6 +201,12 @@
 			if (options.folderDropOptions) {
 				this._folderDropOptions = options.folderDropOptions;
 			}
+			if (options.filesClient) {
+				this.filesClient = options.filesClient;
+			} else {
+				// default client if not specified
+				this.filesClient = OC.Files.getClient();
+			}
 
 			this.$el = $el;
 			if (options.id) {
@@ -209,6 +231,8 @@
 			this.files = [];
 			this._selectedFiles = {};
 			this._selectionSummary = new OCA.Files.FileSummary();
+			// dummy root dir info
+			this.dirInfo = new OC.Files.FileInfo({});
 
 			this.fileSummary = this._createSummary();
 
@@ -359,7 +383,7 @@
 				var highlightState = $tr.hasClass('highlighted');
 				$tr = self.updateRow(
 					$tr,
-					_.extend({isPreviewAvailable: true}, model.toJSON()),
+					model.toJSON(),
 					{updateSummary: true, silent: false, animate: true}
 				);
 				$tr.toggleClass('highlighted', highlightState);
@@ -618,7 +642,7 @@
 			};
 
 			OCA.Files.FileActions.updateFileActionSpinner(downloadFileaction, true);
-			OCA.Files.Files.handleDownload(this.getDownloadUrl(files, dir), disableLoadingState);
+			OCA.Files.Files.handleDownload(this.getDownloadUrl(files, dir, true), disableLoadingState);
 			return false;
 		},
 
@@ -894,16 +918,39 @@
 				self.$el.closest('#app-content').trigger(jQuery.Event('apprendered'));
 			});
 		},
+
+		/**
+		 * Returns the icon URL matching the given file info
+		 *
+		 * @param {OC.Files.FileInfo} fileInfo file info
+		 *
+		 * @return {string} icon URL
+		 */
+		_getIconUrl: function(fileInfo) {
+			var mimeType = fileInfo.mimetype || 'application/octet-stream';
+			if (mimeType === 'httpd/unix-directory') {
+				// use default folder icon
+				if (fileInfo.mountType === 'shared' || fileInfo.mountType === 'shared-root') {
+					return OC.MimeType.getIconUrl('dir-shared');
+				} else if (fileInfo.mountType === 'external-root') {
+					return OC.MimeType.getIconUrl('dir-external');
+				}
+				return OC.MimeType.getIconUrl('dir');
+			}
+			return OC.MimeType.getIconUrl(mimeType);
+		},
+
 		/**
 		 * Creates a new table row element using the given file data.
-		 * @param {OCA.Files.FileInfo} fileData file info attributes
+		 * @param {OC.Files.FileInfo} fileData file info attributes
 		 * @param options map of attributes
 		 * @return new tr element (not appended to the table)
 		 */
 		_createRow: function(fileData, options) {
 			var td, simpleSize, basename, extension, sizeColor,
-				icon = OC.MimeType.getIconUrl(fileData.mimetype),
+				icon = fileData.icon || this._getIconUrl(fileData),
 				name = fileData.name,
+				// TODO: get rid of type, only use mime type
 				type = fileData.type || 'file',
 				mtime = parseInt(fileData.mtime, 10),
 				mime = fileData.mimetype,
@@ -943,6 +990,14 @@
 			}
 
 			if (fileData.mountType) {
+				// FIXME: HACK: detect shared-root
+				if (fileData.mountType === 'shared' && this.dirInfo.mountType !== 'shared') {
+					// if parent folder isn't share, assume the displayed folder is a share root
+					fileData.mountType = 'shared-root';
+				} else if (fileData.mountType === 'external' && this.dirInfo.mountType !== 'external') {
+					// if parent folder isn't external, assume the displayed folder is the external storage root
+					fileData.mountType = 'external-root';
+				}
 				tr.attr('data-mounttype', fileData.mountType);
 			}
 
@@ -953,24 +1008,16 @@
 				path = this.getCurrentDirectory();
 			}
 
-			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 = $('<td class="filename"></td>');
 
 
 			// linkUrl
-			if (type === 'dir') {
+			if (mime === 'httpd/unix-directory') {
 				linkUrl = this.linkTo(path + '/' + name);
 			}
 			else {
-				linkUrl = this.getDownloadUrl(name, path);
+				linkUrl = this.getDownloadUrl(name, path, type === 'dir');
 			}
 			if (this._allowSelection) {
 				td.append(
@@ -996,7 +1043,7 @@
 				basename = '';
 				extension = name;
 			// split extension from filename for non dirs
-			} else if (type !== 'dir' && name.indexOf('.') !== -1) {
+			} else if (mime !== 'httpd/unix-directory' && name.indexOf('.') !== -1) {
 				basename = name.substr(0, name.lastIndexOf('.'));
 				extension = name.substr(name.lastIndexOf('.'));
 			} else {
@@ -1018,7 +1065,7 @@
 				nameSpan.tooltip({placement: 'right'});
 			}
 			// dirs can show the number of uploaded files
-			if (type === 'dir') {
+			if (mime !== 'httpd/unix-directory') {
 				linkElem.append($('<span></span>').attr({
 					'class': 'uploadtext',
 					'currentUploads': 0
@@ -1074,7 +1121,7 @@
 		 * Adds an entry to the files array and also into the DOM
 		 * in a sorted manner.
 		 *
-		 * @param {OCA.Files.FileInfo} fileData map of file attributes
+		 * @param {OC.Files.FileInfo} fileData map of file attributes
 		 * @param {Object} [options] map of attributes
 		 * @param {boolean} [options.updateSummary] true to update the summary
 		 * after adding (default), false otherwise. Defaults to true.
@@ -1147,7 +1194,7 @@
 		 * Creates a new row element based on the given attributes
 		 * and returns it.
 		 *
-		 * @param {OCA.Files.FileInfo} fileData map of file attributes
+		 * @param {OC.Files.FileInfo} fileData map of file attributes
 		 * @param {Object} [options] map of attributes
 		 * @param {int} [options.index] index at which to insert the element
 		 * @param {boolean} [options.updateSummary] true to update the summary
@@ -1182,7 +1229,7 @@
 				filenameTd.draggable(this._dragOptions);
 			}
 			// allow dropping on folders
-			if (this._folderDropOptions && fileData.type === 'dir') {
+			if (this._folderDropOptions && mime === 'httpd/unix-directory') {
 				filenameTd.droppable(this._folderDropOptions);
 			}
 
@@ -1193,7 +1240,7 @@
 			// display actions
 			this.fileActions.display(filenameTd, !options.silent, this);
 
-			if (fileData.isPreviewAvailable && mime !== 'httpd/unix-directory') {
+			if (mime !== 'httpd/unix-directory') {
 				var iconDiv = filenameTd.find('.thumbnail');
 				// lazy load / newly inserted td ?
 				// the typeof check ensures that the default value of animate is true
@@ -1343,17 +1390,7 @@
 			this._currentFileModel = null;
 			this.$el.find('.select-all').prop('checked', false);
 			this.showMask();
-			if (this._reloadCall) {
-				this._reloadCall.abort();
-			}
-			this._reloadCall = $.ajax({
-				url: this.getAjaxUrl('list'),
-				data: {
-					dir : this.getCurrentDirectory(),
-					sort: this._sort,
-					sortdirection: this._sortDirection
-				}
-			});
+			this._reloadCall = this.filesClient.getFolderContents(this.getCurrentDirectory(), {includeParent: true});
 			if (this._detailsView) {
 				// close sidebar
 				this._updateDetailsView(null);
@@ -1361,24 +1398,19 @@
 			var callBack = this.reloadCallback.bind(this);
 			return this._reloadCall.then(callBack, callBack);
 		},
-		reloadCallback: function(result) {
+		reloadCallback: function(status, result) {
 			delete this._reloadCall;
 			this.hideMask();
 
-			if (!result || result.status === 'error') {
-				// if the error is not related to folder we're trying to load, reload the page to handle logout etc
-				if (result.data.error === 'authentication_error' ||
-					result.data.error === 'token_expired' ||
-					result.data.error === 'application_not_enabled'
-				) {
-					OC.redirect(OC.generateUrl('apps/files'));
-				}
-				OC.Notification.showTemporary(result.data.message);
+			if (status === 401) {
+				// TODO: append current URL to be able to get back after logging in again
+				OC.redirect(OC.generateUrl('apps/files'));
+				OC.Notification.show(result);
 				return false;
 			}
 
 			// Firewall Blocked request?
-			if (result.status === 403) {
+			if (status === 403) {
 				// Go home
 				this.changeDirectory('/');
 				OC.Notification.showTemporary(t('files', 'This operation is forbidden'));
@@ -1386,32 +1418,49 @@
 			}
 
 			// Did share service die or something else fail?
-			if (result.status === 500) {
+			if (status === 500) {
 				// Go home
 				this.changeDirectory('/');
-				OC.Notification.showTemporary(t('files', 'This directory is unavailable, please check the logs or contact the administrator'));
+				OC.Notification.showTemporary(
+					t('files', 'This directory is unavailable, please check the logs or contact the administrator')
+				);
+				return false;
+			}
+
+			if (status === 503) {
+				// Go home
+				if (this.getCurrentDirectory() !== '/') {
+					this.changeDirectory('/');
+					// TODO: read error message from exception
+					OC.Notification.showTemporary(
+						t('files', 'Storage not available')
+					);
+				}
 				return false;
 			}
 
-			if (result.status === 404) {
+			if (status === 404) {
 				// go back home
 				this.changeDirectory('/');
 				return false;
 			}
 			// aborted ?
-			if (result.status === 0){
+			if (status === 0){
 				return true;
 			}
 
-			// TODO: should rather return upload file size through
-			// the files list ajax call
+			// TODO: parse remaining quota from PROPFIND response
 			this.updateStorageStatistics(true);
 
-			if (result.data.permissions) {
-				this.setDirectoryPermissions(result.data.permissions);
+			// first entry is the root
+			this.dirInfo = result.shift();
+
+			if (this.dirInfo.permissions) {
+				this.setDirectoryPermissions(this.dirInfo.permissions);
 			}
 
-			this.setFiles(result.data.files);
+			result.sort(this._sortComparator);
+			this.setFiles(result);
 			return true;
 		},
 
@@ -1419,12 +1468,15 @@
 			OCA.Files.Files.updateStorageStatistics(this.getCurrentDirectory(), force);
 		},
 
+		/**
+		 * @deprecated do not use nor override
+		 */
 		getAjaxUrl: function(action, params) {
 			return OCA.Files.Files.getAjaxUrl(action, params);
 		},
 
-		getDownloadUrl: function(files, dir) {
-			return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory());
+		getDownloadUrl: function(files, dir, isDir) {
+			return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory(), isDir);
 		},
 
 		/**
@@ -1489,8 +1541,6 @@
 			if (etag){
 				// use etag as cache buster
 				urlSpec.c = etag;
-			} else {
-				console.warn('OCA.Files.FileList.lazyLoadPreview(): missing etag argument');
 			}
 
 			previewURL = self.generatePreviewUrl(urlSpec);
@@ -1514,6 +1564,9 @@
 			img.src = previewURL;
 		},
 
+		/**
+		 * @deprecated
+		 */
 		setDirectoryPermissions: function(permissions) {
 			var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
 			this.$el.find('#permissions').val(permissions);
@@ -1610,7 +1663,7 @@
 		 * fileData should be inserted, considering the current
 		 * sorting
 		 *
-		 * @param {OCA.Files.FileInfo} fileData file info
+		 * @param {OC.Files.FileInfo} fileData file info
 		 */
 		_findInsertionIndex: function(fileData) {
 			var index = 0;
@@ -1628,6 +1681,9 @@
 		move: function(fileNames, targetPath) {
 			var self = this;
 			var dir = this.getCurrentDirectory();
+			if (dir.charAt(dir.length - 1) !== '/') {
+				dir += '/';
+			}
 			var target = OC.basename(targetPath);
 			if (!_.isArray(fileNames)) {
 				fileNames = [fileNames];
@@ -1635,46 +1691,42 @@
 			_.each(fileNames, function(fileName) {
 				var $tr = self.findFileEl(fileName);
 				self.showFileBusyState($tr, true);
-				// TODO: improve performance by sending all file names in a single call
-				$.post(
-					OC.filePath('files', 'ajax', 'move.php'),
-					{
-						dir: dir,
-						file: fileName,
-						target: targetPath
-					},
-					function(result) {
-						if (result) {
-							if (result.status === 'success') {
-								// if still viewing the same directory
-								if (self.getCurrentDirectory() === dir) {
-									// recalculate folder size
-									var oldFile = self.findFileEl(target);
-									var newFile = self.findFileEl(fileName);
-									var oldSize = oldFile.data('size');
-									var newSize = oldSize + newFile.data('size');
-									oldFile.data('size', newSize);
-									oldFile.find('td.filesize').text(OC.Util.humanFileSize(newSize));
-
-									// TODO: also update entry in FileList.files
-
-									self.remove(fileName);
-								}
-							} else {
-								OC.Notification.hide();
-								if (result.status === 'error' && result.data.message) {
-									OC.Notification.showTemporary(result.data.message);
-								}
-								else {
-									OC.Notification.showTemporary(t('files', 'Error moving file.'));
-								}
-							}
+				if (targetPath.charAt(targetPath.length - 1) !== '/') {
+					// make sure we move the files into the target dir,
+					// not overwrite it
+					targetPath = targetPath + '/';
+				}
+				self.filesClient.move(dir + fileName, targetPath + fileName)
+					.done(function() {
+						// if still viewing the same directory
+						if (OC.joinPaths(self.getCurrentDirectory(), '/') === dir) {
+							// recalculate folder size
+							var oldFile = self.findFileEl(target);
+							var newFile = self.findFileEl(fileName);
+							var oldSize = oldFile.data('size');
+							var newSize = oldSize + newFile.data('size');
+							oldFile.data('size', newSize);
+							oldFile.find('td.filesize').text(OC.Util.humanFileSize(newSize));
+
+							// TODO: also update entry in FileList.files
+							self.remove(fileName);
+						}
+					})
+					.fail(function(status) {
+						if (status === 412) {
+							// TODO: some day here we should invoke the conflict dialog
+							OC.Notification.showTemporary(
+								t('files', 'Could not move "{file}", target exists', {file: fileName})
+							);
 						} else {
-							OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
+							OC.Notification.showTemporary(
+								t('files', 'Could not move "{file}"', {file: fileName})
+							);
 						}
+					})
+					.always(function() {
 						self.showFileBusyState($tr, false);
-					}
-				);
+					});
 			});
 
 		},
@@ -1700,16 +1752,16 @@
 		 * Triggers file rename input field for the given file name.
 		 * If the user enters a new name, the file will be renamed.
 		 *
-		 * @param oldname file name of the file to rename
+		 * @param oldName file name of the file to rename
 		 */
-		rename: function(oldname) {
+		rename: function(oldName) {
 			var self = this;
 			var tr, td, input, form;
-			tr = this.findFileEl(oldname);
+			tr = this.findFileEl(oldName);
 			var oldFileInfo = this.files[tr.index()];
 			tr.data('renaming',true);
 			td = tr.children('td.filename');
-			input = $('<input type="text" class="filename"/>').val(oldname);
+			input = $('<input type="text" class="filename"/>').val(oldName);
 			form = $('<form></form>');
 			form.append(input);
 			td.children('a.name').hide();
@@ -1724,11 +1776,11 @@
 			input.selectRange(0, len);
 			var checkInput = function () {
 				var filename = input.val();
-				if (filename !== oldname) {
+				if (filename !== oldName) {
 					// Files.isFileNameValid(filename) throws an exception itself
 					OCA.Files.Files.isFileNameValid(filename);
 					if (self.inList(filename)) {
-						throw t('files', '{new_name} already exists', {new_name: filename});
+						throw t('files', '{newName} already exists', {newName: filename});
 					}
 				}
 				return true;
@@ -1741,6 +1793,14 @@
 				td.children('a.name').show();
 			}
 
+			function updateInList(fileInfo) {
+				tr.remove();
+				tr = self.add(fileInfo, {updateSummary: false, silent: true});
+				self.$fileList.trigger($.Event('fileActionsReady', {fileList: self, $files: $(tr)}));
+				self._updateDetailsView(fileInfo.name);
+			}
+
+			// TODO: too many nested blocks, move parts into functions
 			form.submit(function(event) {
 				event.stopPropagation();
 				event.preventDefault();
@@ -1753,7 +1813,7 @@
 					input.tooltip('hide');
 					form.remove();
 
-					if (newName !== oldname) {
+					if (newName !== oldName) {
 						checkInput();
 						// mark as loading (temp element)
 						self.showFileBusyState(tr, true);
@@ -1765,34 +1825,46 @@
 						td.find('a.name span.nametext').text(basename);
 						td.children('a.name').show();
 
-						$.ajax({
-							url: OC.filePath('files','ajax','rename.php'),
-							data: {
-								dir : tr.attr('data-path') || self.getCurrentDirectory(),
-								newname: newName,
-								file: oldname
-							},
-							success: function(result) {
-								var fileInfo;
-								if (!result || result.status === 'error') {
-									OC.dialogs.alert(result.data.message, t('files', 'Could not rename file'));
-									fileInfo = oldFileInfo;
-									if (result.data.code === 'sourcenotfound') {
-										self.remove(result.data.newname, {updateSummary: true});
-										return;
-									}
-								}
-								else {
-									fileInfo = result.data;
+						var path = tr.attr('data-path') || self.getCurrentDirectory();
+						self.filesClient.move(path + '/' + oldName, path + '/' + newName)
+							.done(function() {
+								var fileInfo = self.files.splice(tr.index(), 1)[0];
+								fileInfo.name = newName;
+								updateInList(fileInfo);
+							})
+							.fail(function(status) {
+								// TODO: 409 means current folder does not exist, redirect ?
+								if (status === 404) {
+									// source not found, so remove it from the list
+									OC.Notification.showTemporary(
+										t(
+											'files',
+											'Could not rename "{fileName}", it does not exist any more',
+											{fileName: oldName}
+										)
+									);
+									self.remove(newName, {updateSummary: true});
+									return;
+								} else if (status === 412) {
+									// target exists
+									OC.Notification.showTemporary(
+										t(
+											'files',
+											'The name "{targetName}" is already used in the folder "{dir}". Please choose a different name.',
+											{
+												targetName: newName,
+												dir: self.getCurrentDirectory()
+											}
+										)
+									);
+								} else {
+									// restore the item to its previous state
+									OC.Notification.showTemporary(
+										t('files', 'Could not rename "{fileName}"', {fileName: oldName})
+									);
 								}
-								// reinsert row
-								self.files.splice(tr.index(), 1);
-								tr.remove();
-								tr = self.add(fileInfo, {updateSummary: false, silent: true});
-								self.$fileList.trigger($.Event('fileActionsReady', {fileList: self, $files: $(tr)}));
-								self._updateDetailsView(fileInfo.name, false);
-							}
-						});
+								updateInList(oldFileInfo);
+							});
 					} else {
 						// add back the old file info when cancelled
 						self.files.splice(tr.index(), 1);
@@ -1849,32 +1921,44 @@
 			var promise = deferred.promise();
 
 			OCA.Files.Files.isFileNameValid(name);
-			name = this.getUniqueName(name);
 
 			if (this.lastAction) {
 				this.lastAction();
 			}
 
-			$.post(
-				OC.generateUrl('/apps/files/ajax/newfile.php'),
-				{
-					dir: this.getCurrentDirectory(),
-					filename: name
-				},
-				function(result) {
-					if (result.status === 'success') {
-						self.add(result.data, {animate: true, scrollTo: true});
-						deferred.resolve(result.status, result.data);
+			name = this.getUniqueName(name);
+			var targetPath = this.getCurrentDirectory() + '/' + name;
+
+			self.filesClient.putFileContents(
+					targetPath,
+					'',
+					{
+						contentType: 'text/plain',
+						overwrite: true
+					}
+				)
+				.done(function() {
+					// TODO: error handling / conflicts
+					self.filesClient.getFileInfo(targetPath)
+						.then(function(status, data) {
+							self.add(data, {animate: true, scrollTo: true});
+							deferred.resolve(status, data);
+						})
+						.fail(function(status) {
+							OC.Notification.showTemporary(t('files', 'Could not create file "{file}"', {file: name}));
+							deferred.reject(status);
+						});
+				})
+				.fail(function(status) {
+					if (status === 412) {
+						OC.Notification.showTemporary(
+							t('files', 'Could not create file "{file}" because it already exists', {file: name})
+						);
 					} else {
-						if (result.data && result.data.message) {
-							OC.Notification.showTemporary(result.data.message);
-						} else {
-							OC.Notification.showTemporary(t('core', 'Could not create file'));
-						}
-						deferred.reject(result.status, result.data);
+						OC.Notification.showTemporary(t('files', 'Could not create file "{file}"', {file: name}));
 					}
-				}
-			);
+					deferred.reject(status);
+				});
 
 			return promise;
 		},
@@ -1895,32 +1979,50 @@
 			var promise = deferred.promise();
 
 			OCA.Files.Files.isFileNameValid(name);
-			name = this.getUniqueName(name);
 
 			if (this.lastAction) {
 				this.lastAction();
 			}
 
-			$.post(
-				OC.generateUrl('/apps/files/ajax/newfolder.php'),
-				{
-					dir: this.getCurrentDirectory(),
-					foldername: name
-				},
-				function(result) {
-					if (result.status === 'success') {
-						self.add(result.data, {animate: true, scrollTo: true});
-						deferred.resolve(result.status, result.data);
+			name = this.getUniqueName(name);
+			var targetPath = this.getCurrentDirectory() + '/' + name;
+
+			this.filesClient.createDirectory(targetPath)
+				.done(function(createStatus) {
+					self.filesClient.getFileInfo(targetPath)
+						.done(function(status, data) {
+							self.add(data, {animate: true, scrollTo: true});
+							deferred.resolve(status, data);
+						})
+						.fail(function() {
+							OC.Notification.showTemporary(t('files', 'Could not create folder "{dir}"', {dir: name}));
+							deferred.reject(createStatus);
+						});
+				})
+				.fail(function(createStatus) {
+					// method not allowed, folder might exist already
+					if (createStatus === 405) {
+						self.filesClient.getFileInfo(targetPath)
+							.done(function(status, data) {
+								// add it to the list, for completeness
+								self.add(data, {animate: true, scrollTo: true});
+								OC.Notification.showTemporary(
+									t('files', 'Could not create folder "{dir}" because it already exists', {dir: name})
+								);
+								// still consider a failure
+								deferred.reject(createStatus, data);
+							})
+							.fail(function() {
+								OC.Notification.showTemporary(
+									t('files', 'Could not create folder "{dir}"', {dir: name})
+								);
+								deferred.reject(status);
+							});
 					} else {
-						if (result.data && result.data.message) {
-							OC.Notification.showTemporary(result.data.message);
-						} else {
-							OC.Notification.showTemporary(t('core', 'Could not create folder'));
-						}
-						deferred.reject(result.status);
+						OC.Notification.showTemporary(t('files', 'Could not create folder "{dir}"', {dir: name}));
+						deferred.reject(createStatus);
 					}
-				}
-			);
+				});
 
 			return promise;
 		},
@@ -1981,76 +2083,59 @@
 		 */
 		do_delete:function(files, dir) {
 			var self = this;
-			var params;
 			if (files && files.substr) {
 				files=[files];
 			}
+			if (!files) {
+				// delete all files in directory
+				files = _.pluck(this.files, 'name');
+			}
 			if (files) {
 				this.showFileBusyState(files, true);
-				for (var i=0; i<files.length; i++) {
-				}
 			}
 			// Finish any existing actions
 			if (this.lastAction) {
 				this.lastAction();
 			}
 
-			params = {
-				dir: dir || this.getCurrentDirectory()
-			};
-			if (files) {
-				params.files = JSON.stringify(files);
+			dir = dir || this.getCurrentDirectory();
+
+			function removeFromList(file) {
+				var fileEl = self.remove(file, {updateSummary: false});
+				// FIXME: not sure why we need this after the
+				// element isn't even in the DOM any more
+				fileEl.find('.selectCheckBox').prop('checked', false);
+				fileEl.removeClass('selected');
+				self.fileSummary.remove({type: fileEl.attr('data-type'), size: fileEl.attr('data-size')});
+				// TODO: this info should be returned by the ajax call!
+				self.updateEmptyContent();
+				self.fileSummary.update();
+				self.updateSelectionSummary();
+				// FIXME: don't repeat this, do it once all files are done
+				self.updateStorageStatistics();
 			}
-			else {
-				// no files passed, delete all in current dir
-				params.allfiles = true;
-				// show spinner for all files
-				this.showFileBusyState(this.$fileList.find('tr'), true);
-			}
-
-			$.post(OC.filePath('files', 'ajax', 'delete.php'),
-					params,
-					function(result) {
-						if (result.status === 'success') {
-							if (params.allfiles) {
-								self.setFiles([]);
-							}
-							else {
-								$.each(files,function(index,file) {
-									var fileEl = self.remove(file, {updateSummary: false});
-									// FIXME: not sure why we need this after the
-									// element isn't even in the DOM any more
-									fileEl.find('.selectCheckBox').prop('checked', false);
-									fileEl.removeClass('selected');
-									self.fileSummary.remove({type: fileEl.attr('data-type'), size: fileEl.attr('data-size')});
-								});
-							}
-							// TODO: this info should be returned by the ajax call!
-							self.updateEmptyContent();
-							self.fileSummary.update();
-							self.updateSelectionSummary();
-							self.updateStorageStatistics();
-							// in case there was a "storage full" permanent notification
-							OC.Notification.hide();
+
+			_.each(files, function(file) {
+				self.filesClient.remove(dir + '/' + file)
+					.done(function() {
+						removeFromList(file);
+					})
+					.fail(function(status) {
+						if (status === 404) {
+							// the file already did not exist, remove it from the list
+							removeFromList(file);
 						} else {
-							if (result.status === 'error' && result.data.message) {
-								OC.Notification.showTemporary(result.data.message);
-							}
-							else {
-								OC.Notification.showTemporary(t('files', 'Error deleting file.'));
-							}
-							if (params.allfiles) {
-								// reload the page as we don't know what files were deleted
-								// and which ones remain
-								self.reload();
-							}
-							else {
-								$.each(files,function(index,file) {
-									self.showFileBusyState(file, false);
-								});
-							}
+							// only reset the spinner for that one file
+							OC.Notification.showTemporary(
+									t('files', 'Error deleting file "{fileName}".', {fileName: file}),
+									{timeout: 10}
+							);
+							var deleteAction = self.findFileEl(file).find('.action.delete');
+							deleteAction.removeClass('icon-loading-small').addClass('icon-delete');
+							self.showFileBusyState(files, false);
 						}
 					});
+			});
 		},
 		/**
 		 * Creates the file summary section
@@ -2659,8 +2744,8 @@
 		 * Compares two file infos by name, making directories appear
 		 * first.
 		 *
-		 * @param {OCA.Files.FileInfo} fileInfo1 file info
-		 * @param {OCA.Files.FileInfo} fileInfo2 file info
+		 * @param {OC.Files.FileInfo} fileInfo1 file info
+		 * @param {OC.Files.FileInfo} fileInfo2 file info
 		 * @return {int} -1 if the first file must appear before the second one,
 		 * 0 if they are identify, 1 otherwise.
 		 */
@@ -2676,8 +2761,8 @@
 		/**
 		 * Compares two file infos by size.
 		 *
-		 * @param {OCA.Files.FileInfo} fileInfo1 file info
-		 * @param {OCA.Files.FileInfo} fileInfo2 file info
+		 * @param {OC.Files.FileInfo} fileInfo1 file info
+		 * @param {OC.Files.FileInfo} fileInfo2 file info
 		 * @return {int} -1 if the first file must appear before the second one,
 		 * 0 if they are identify, 1 otherwise.
 		 */
@@ -2687,8 +2772,8 @@
 		/**
 		 * Compares two file infos by timestamp.
 		 *
-		 * @param {OCA.Files.FileInfo} fileInfo1 file info
-		 * @param {OCA.Files.FileInfo} fileInfo2 file info
+		 * @param {OC.Files.FileInfo} fileInfo1 file info
+		 * @param {OC.Files.FileInfo} fileInfo2 file info
 		 * @return {int} -1 if the first file must appear before the second one,
 		 * 0 if they are identify, 1 otherwise.
 		 */
@@ -2700,23 +2785,14 @@
 	/**
 	 * File info attributes.
 	 *
-	 * @todo make this a real class in the future
-	 * @typedef {Object} OCA.Files.FileInfo
+	 * @typedef {Object} OC.Files.FileInfo
+	 *
+	 * @lends OC.Files.FileInfo
+	 *
+	 * @deprecated use OC.Files.FileInfo instead
 	 *
-	 * @property {int} id file id
-	 * @property {String} name file name
-	 * @property {String} [path] file path, defaults to the list's current path
-	 * @property {String} mimetype mime type
-	 * @property {String} type "file" for files or "dir" for directories
-	 * @property {int} permissions file permissions
-	 * @property {int} mtime modification time in milliseconds
-	 * @property {boolean} [isShareMountPoint] whether the file is a share mount
-	 * point
-	 * @property {boolean} [isPreviewAvailable] whether a preview is available
-	 * for the given file type
-	 * @property {String} [icon] path to the mime type icon
-	 * @property {String} etag etag of the file
 	 */
+	OCA.Files.FileInfo = OC.Files.FileInfo;
 
 	OCA.Files.FileList = FileList;
 })();
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index ae38511ec05789cc060e91e3f0dbdb9dac881118..6bdd14ac65d51dc89818e49fe337b79693d9427b 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -136,13 +136,27 @@
 
 		/**
 		 * 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
+		 * @param {string} filename string or array of file names to download
+		 * @param {string} [dir] optional directory in which the file name is, defaults to the current directory
+		 * @param {bool} [isDir=false] whether the given filename is a directory and might need a special URL
 		 */
-		getDownloadUrl: function(filename, dir) {
-			if ($.isArray(filename)) {
+		getDownloadUrl: function(filename, dir, isDir) {
+			if (!_.isArray(filename) && !isDir) {
+				var pathSections = dir.split('/');
+				pathSections.push(filename);
+				var encodedPath = '';
+				_.each(pathSections, function(section) {
+					if (section !== '') {
+						encodedPath += '/' + encodeURIComponent(section);
+					}
+				});
+				return OC.linkToRemoteBase('webdav') + encodedPath;
+			}
+
+			if (_.isArray(filename)) {
 				filename = JSON.stringify(filename);
 			}
+
 			var params = {
 				dir: dir,
 				files: filename
@@ -356,8 +370,10 @@ scanFiles.scanning=false;
 
 // TODO: move to FileList
 var createDragShadow = function(event) {
+	// FIXME: inject file list instance somehow
+	/* global FileList, Files */
+
 	//select dragged file
-	var FileList = OCA.Files.App.fileList;
 	var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
 	if (!isDragSelected) {
 		//select dragged file
@@ -394,7 +410,7 @@ var createDragShadow = function(event) {
 				.css('background-image', 'url(' + OC.imagePath('core', 'filetypes/folder.png') + ')');
 		} else {
 			var path = dir + '/' + elem.name;
-			OCA.Files.App.files.lazyLoadPreview(path, elem.mime, function(previewpath) {
+			Files.lazyLoadPreview(path, elem.mimetype, function(previewpath) {
 				newtr.find('td.filename')
 					.css('background-image', 'url(' + previewpath + ')');
 			}, null, null, elem.etag);
@@ -441,7 +457,7 @@ var folderDropOptions = {
 	hoverClass: "canDrop",
 	drop: function( event, ui ) {
 		// don't allow moving a file into a selected folder
-		var FileList = OCA.Files.App.fileList;
+		/* global FileList */
 		if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) {
 			return false;
 		}
diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php
index 5bd8c1275861856eaecbfed0b683232ff641fa9d..18813e224de1ca43b0fa526eae8cfba74da7ade4 100644
--- a/apps/files/lib/app.php
+++ b/apps/files/lib/app.php
@@ -28,108 +28,22 @@
 namespace OCA\Files;
 
 class App {
-	/**
-	 * @var \OC_L10N
-	 */
-	private $l10n;
-
 	/**
 	 * @var \OCP\INavigationManager
 	 */
 	private static $navigationManager;
 
-	/**
-	 * @var \OC\Files\View
-	 */
-	private $view;
-
-	public function __construct($view, $l10n) {
-		$this->view = $view;
-		$this->l10n = $l10n;
-	}
-
 	/**
 	 * Returns the app's navigation manager
 	 *
 	 * @return \OCP\INavigationManager
 	 */
 	public static function getNavigationManager() {
+		// TODO: move this into a service in the Application class
 		if (self::$navigationManager === null) {
 			self::$navigationManager = new \OC\NavigationManager();
 		}
 		return self::$navigationManager;
 	}
 
-	/**
-	 * rename a file
-	 *
-	 * @param string $dir
-	 * @param string $oldname
-	 * @param string $newname
-	 * @return array
-	 */
-	public function rename($dir, $oldname, $newname) {
-		$result = array(
-			'success' 	=> false,
-			'data'		=> NULL
-		);
-
-		try {
-			// check if the new name is conform to file name restrictions
-			$this->view->verifyPath($dir, $newname);
-		} catch (\OCP\Files\InvalidPathException $ex) {
-			$result['data'] = array(
-				'message'	=> $this->l10n->t($ex->getMessage()),
-				'code' => 'invalidname',
-			);
-			return $result;
-		}
-
-		$normalizedOldPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $oldname);
-		$normalizedNewPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $newname);
-
-		// rename to non-existing folder is denied
-		if (!$this->view->file_exists($normalizedOldPath)) {
-			$result['data'] = array(
-				'message'	=> $this->l10n->t('%s could not be renamed as it has been deleted', array($oldname)),
-				'code' => 'sourcenotfound',
-				'oldname' => $oldname,
-				'newname' => $newname,
-			);
-		}else if (!$this->view->file_exists($dir)) {
-			$result['data'] = array('message' => (string)$this->l10n->t(
-					'The target folder has been moved or deleted.',
-					array($dir)),
-					'code' => 'targetnotfound'
-				);
-		// rename to existing file is denied
-		} else if ($this->view->file_exists($normalizedNewPath)) {
-
-			$result['data'] = array(
-				'message'	=> $this->l10n->t(
-						"The name %s is already used in the folder %s. Please choose a different name.",
-						array($newname, $dir))
-			);
-		} else if (
-			// rename to "." is denied
-			$newname !== '.' and
-			// THEN try to rename
-			$this->view->rename($normalizedOldPath, $normalizedNewPath)
-		) {
-			// successful rename
-			$meta = $this->view->getFileInfo($normalizedNewPath);
-			$meta = \OCA\Files\Helper::populateTags(array($meta));
-			$fileInfo = \OCA\Files\Helper::formatFileInfo(current($meta));
-			$fileInfo['path'] = dirname($normalizedNewPath);
-			$result['success'] = true;
-			$result['data'] = $fileInfo;
-		} else {
-			// rename failed
-			$result['data'] = array(
-				'message'	=> $this->l10n->t('%s could not be renamed', array($oldname))
-			);
-		}
-		return $result;
-	}
-
 }
diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php
index fb14cea731f3adebe08d5ab6ef0c8dc3e4602ace..9a4e8d59786ad1b68c64eb77131a92548e728aa6 100644
--- a/apps/files/lib/helper.php
+++ b/apps/files/lib/helper.php
@@ -139,9 +139,6 @@ class Helper {
 		$entry['parentId'] = $i['parent'];
 		$entry['mtime'] = $i['mtime'] * 1000;
 		// only pick out the needed attributes
-		if (\OC::$server->getPreviewManager()->isAvailable($i)) {
-			$entry['isPreviewAvailable'] = true;
-		}
 		$entry['name'] = $i->getName();
 		$entry['permissions'] = $i['permissions'];
 		$entry['mimetype'] = $i['mimetype'];
diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php
deleted file mode 100644
index 859c7042b89cf265762e335e5042b2112077e6ed..0000000000000000000000000000000000000000
--- a/apps/files/tests/ajax_rename.php
+++ /dev/null
@@ -1,232 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program 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, version 3,
- * along with this program.  If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-class Test_OC_Files_App_Rename extends \Test\TestCase {
-	private static $user;
-
-	/**
-	 * @var PHPUnit_Framework_MockObject_MockObject
-	 */
-	private $viewMock;
-
-	/**
-	 * @var \OCA\Files\App
-	 */
-	private $files;
-
-	protected function setUp() {
-		parent::setUp();
-
-		// mock OC_L10n
-		if (!self::$user) {
-			self::$user = uniqid();
-		}
-		\OC_User::createUser(self::$user, 'password');
-		$this->loginAsUser(self::$user);
-
-		$l10nMock = $this->getMock('\OC_L10N', array('t'), array(), '', false);
-		$l10nMock->expects($this->any())
-			->method('t')
-			->will($this->returnArgument(0));
-		$viewMock = $this->getMock('\OC\Files\View', array('rename', 'normalizePath', 'getFileInfo', 'file_exists'), array(), '', false);
-		$viewMock->expects($this->any())
-			->method('normalizePath')
-			->will($this->returnArgument(0));
-		$viewMock->expects($this->any())
-			->method('rename')
-			->will($this->returnValue(true));
-		$this->viewMock = $viewMock;
-		$this->files = new \OCA\Files\App($viewMock, $l10nMock);
-	}
-
-	protected function tearDown() {
-		$result = \OC_User::deleteUser(self::$user);
-		$this->assertTrue($result);
-
-		$this->logout();
-		parent::tearDown();
-	}
-
-	/**
-	 * test rename of file/folder
-	 */
-	function testRenameFolder() {
-		$dir = '/';
-		$oldname = 'oldname';
-		$newname = 'newname';
-
-		$this->viewMock->expects($this->any())
-			->method('file_exists')
-			->with($this->anything())
-			->will($this->returnValueMap(array(
-				array('/', true),
-				array('/oldname', true)
-				)));
-
-
-		$this->viewMock->expects($this->any())
-			->method('getFileInfo')
-			->will($this->returnValue(new \OC\Files\FileInfo(
-				'/new_name',
-				new \OC\Files\Storage\Local(array('datadir' => '/')),
-				'/',
-				array(
-				'fileid' => 123,
-				'type' => 'dir',
-				'mimetype' => 'httpd/unix-directory',
-				'mtime' => 0,
-				'permissions' => 31,
-				'size' => 18,
-				'etag' => 'abcdef',
-				'directory' => '/',
-				'name' => 'new_name',
-			), null)));
-
-		$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(18, $result['data']['size']);
-		$this->assertEquals('httpd/unix-directory', $result['data']['mimetype']);
-		$this->assertEquals('abcdef', $result['data']['etag']);
-		$this->assertFalse(isset($result['data']['tags']));
-		$this->assertEquals('/', $result['data']['path']);
-	}
-
-	/**
-	 * test rename of file with tag
-	 */
-	function testRenameFileWithTag() {
-		$taggerMock = $this->getMock('\OCP\ITags');
-		$taggerMock->expects($this->any())
-			->method('getTagsForObjects')
-			->with(array(123))
-			->will($this->returnValue(array(123 => array('tag1', 'tag2'))));
-		$tagManagerMock = $this->getMock('\OCP\ITagManager');
-		$tagManagerMock->expects($this->any())
-			->method('load')
-			->with('files')
-			->will($this->returnValue($taggerMock));
-		$oldTagManager = \OC::$server->query('TagManager');
-		\OC::$server->registerService('TagManager', function ($c) use ($tagManagerMock) {
-			return $tagManagerMock;
-		});
-
-		$dir = '/';
-		$oldname = 'oldname.txt';
-		$newname = 'newname.txt';
-
-		$this->viewMock->expects($this->any())
-			->method('file_exists')
-			->with($this->anything())
-			->will($this->returnValueMap(array(
-				array('/', true),
-				array('/oldname.txt', true)
-				)));
-
-
-		$this->viewMock->expects($this->any())
-			->method('getFileInfo')
-			->will($this->returnValue(new \OC\Files\FileInfo(
-				'/new_name.txt',
-				new \OC\Files\Storage\Local(array('datadir' => '/')),
-				'/',
-				array(
-				'fileid' => 123,
-				'type' => 'file',
-				'mimetype' => 'text/plain',
-				'mtime' => 0,
-				'permissions' => 31,
-				'size' => 18,
-				'etag' => 'abcdef',
-				'directory' => '/',
-				'name' => 'new_name.txt',
-			), null)));
-
-		$result = $this->files->rename($dir, $oldname, $newname);
-
-		$this->assertTrue($result['success']);
-		$this->assertEquals(123, $result['data']['id']);
-		$this->assertEquals('new_name.txt', $result['data']['name']);
-		$this->assertEquals(18, $result['data']['size']);
-		$this->assertEquals('text/plain', $result['data']['mimetype']);
-		$this->assertEquals('abcdef', $result['data']['etag']);
-		$this->assertEquals(array('tag1', 'tag2'), $result['data']['tags']);
-		$this->assertEquals('/', $result['data']['path']);
-
-		\OC::$server->registerService('TagManager', function ($c) use ($oldTagManager) {
-			return $oldTagManager;
-		});
-	}
-
-	/**
-	 * Test rename inside a folder that doesn't exist any more
-	 */
-	function testRenameInNonExistingFolder() {
-		$dir = '/unexist';
-		$oldname = 'oldname';
-		$newname = 'newname';
-
-		$this->viewMock->expects($this->at(0))
-			->method('file_exists')
-			->with('/unexist/oldname')
-			->will($this->returnValue(false));
-
-		$this->viewMock->expects($this->any())
-			->method('getFileInfo')
-			->will($this->returnValue(array(
-				'fileid' => 123,
-				'type' => 'dir',
-				'mimetype' => 'httpd/unix-directory',
-				'size' => 18,
-				'etag' => 'abcdef',
-				'directory' => '/unexist',
-				'name' => 'new_name',
-			)));
-
-		$result = $this->files->rename($dir, $oldname, $newname);
-
-		$this->assertFalse($result['success']);
-		$this->assertEquals('sourcenotfound', $result['data']['code']);
-	}
-
-	/**
-	 * Test move to invalid name
-	 */
-	function testRenameToInvalidName() {
-		$dir = '/';
-		$oldname = 'oldname';
-		$newname = 'abc\\';
-
-		$result = $this->files->rename($dir, $oldname, $newname);
-
-		$this->assertFalse($result['success']);
-		$this->assertEquals('File name contains at least one invalid character', $result['data']['message']);
-		$this->assertEquals('invalidname', $result['data']['code']);
-	}
-}
diff --git a/apps/files/tests/js/favoritesfilelistspec.js b/apps/files/tests/js/favoritesfilelistspec.js
index 608ddaca18be94fcc96a20fa988a8b06d218180f..1c833d334e21bd4949146e679625c46fd6b2e996 100644
--- a/apps/files/tests/js/favoritesfilelistspec.js
+++ b/apps/files/tests/js/favoritesfilelistspec.js
@@ -100,8 +100,7 @@ describe('OCA.Files.FavoritesFileList tests', function() {
 			expect($tr.attr('data-mtime')).toEqual('11111000');
 			expect($tr.find('a.name').attr('href')).toEqual(
 				OC.webroot +
-				'/index.php/apps/files/ajax/download.php' +
-				'?dir=%2Fsomedir&files=test.txt'
+				'/remote.php/webdav/somedir/test.txt'
 			);
 			expect($tr.find('.nametext').text().trim()).toEqual('test.txt');
 		});
diff --git a/apps/files/tests/js/fileUploadSpec.js b/apps/files/tests/js/fileUploadSpec.js
index a49a5d4e2e07446d2a7cc5def4b8584dd3383d41..8a0d6b019523f2e6bfa79b1da5f0964371af68e4 100644
--- a/apps/files/tests/js/fileUploadSpec.js
+++ b/apps/files/tests/js/fileUploadSpec.js
@@ -19,6 +19,8 @@
 *
 */
 
+/* global FileList */
+
 describe('OC.Upload tests', function() {
 	var $dummyUploader;
 	var testFile;
diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js
index d29164c51366e584cc68ba0f98ac510724b478b1..a905a4d969d8cb6b8b5e037771628253598bcf45 100644
--- a/apps/files/tests/js/fileactionsSpec.js
+++ b/apps/files/tests/js/fileactionsSpec.js
@@ -584,7 +584,7 @@ describe('OCA.Files.FileActions tests', function() {
 				expect(busyStub.calledWith('testName.txt', true)).toEqual(true);
 				expect(handleDownloadStub.calledOnce).toEqual(true);
 				expect(handleDownloadStub.getCall(0).args[0]).toEqual(
-					OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt'
+					OC.webroot + '/remote.php/webdav/subdir/testName.txt'
 				);
 				busyStub.reset();
 				handleDownloadStub.yield();
diff --git a/apps/files/tests/js/fileactionsmenuSpec.js b/apps/files/tests/js/fileactionsmenuSpec.js
index dee542458b625df72ed907da65952ca3a25d0056..747a746a602522d5aa915d9baee0f489bc32a93e 100644
--- a/apps/files/tests/js/fileactionsmenuSpec.js
+++ b/apps/files/tests/js/fileactionsmenuSpec.js
@@ -237,8 +237,8 @@ describe('OCA.Files.FileActionsMenu tests', function() {
 			expect(redirectStub.calledOnce).toEqual(true);
 			expect(redirectStub.getCall(0).args[0]).toContain(
 				OC.webroot +
-				'/index.php/apps/files/ajax/download.php' +
-				'?dir=%2Fsubdir&files=testName.txt');
+				'/remote.php/webdav/subdir/testName.txt'
+			);
 			redirectStub.restore();
 		});
 		it('takes the file\'s path into account when clicking download', function() {
@@ -269,8 +269,7 @@ describe('OCA.Files.FileActionsMenu tests', function() {
 
 			expect(redirectStub.calledOnce).toEqual(true);
 			expect(redirectStub.getCall(0).args[0]).toContain(
-				OC.webroot + '/index.php/apps/files/ajax/download.php' +
-				'?dir=%2Fanotherpath%2Fthere&files=testName.txt'
+				OC.webroot + '/remote.php/webdav/anotherpath/there/testName.txt'
 			);
 			redirectStub.restore();
 		});
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index 05e6fcc6122b5e0ecc508dbe9204bc561ac6eaaf..9f7ad50bc608716b00c421b5608051826b9a636a 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -20,8 +20,11 @@
 */
 
 describe('OCA.Files.FileList tests', function() {
-	var testFiles, alertStub, notificationStub, fileList, pageSizeStub;
+	var FileInfo = OC.Files.FileInfo;
+	var testFiles, testRoot, notificationStub, fileList, pageSizeStub;
 	var bcResizeStub;
+	var filesClient;
+	var redirectStub;
 
 	/**
 	 * Generate test file data
@@ -38,21 +41,29 @@ describe('OCA.Files.FileList tests', function() {
 				name += '0';
 			}
 			name += i + '.txt';
-			files.push({
+			files.push(new FileInfo({
 				id: i,
 				type: 'file',
 				name: name,
 				mimetype: 'text/plain',
 				size: i * 2,
 				etag: 'abc'
-			});
+			}));
 		}
 		return files;
 	}
 
 	beforeEach(function() {
-		alertStub = sinon.stub(OC.dialogs, 'alert');
-		notificationStub = sinon.stub(OC.Notification, 'show');
+		filesClient = new OC.Files.Client({
+			host: 'localhost',
+			port: 80,
+			// FIXME: uncomment after fixing the test OC.webroot
+			//root: OC.webroot + '/remote.php/webdav',
+			root: '/remote.php/webdav',
+			useHTTPS: false
+		});
+		redirectStub = sinon.stub(OC, 'redirect');
+		notificationStub = sinon.stub(OC.Notification, 'showTemporary');
 		// prevent resize algo to mess up breadcrumb order while
 		// testing
 		bcResizeStub = sinon.stub(OCA.Files.BreadCrumb.prototype, '_resize');
@@ -93,7 +104,17 @@ describe('OCA.Files.FileList tests', function() {
 			'</div>'
 		);
 
-		testFiles = [{
+		testRoot = new FileInfo({
+			// root entry
+			id: 99,
+			type: 'dir',
+			name: '/subdir',
+			mimetype: 'httpd/unix-directory',
+			size: 1200000,
+			etag: 'a0b0c0d0',
+			permissions: OC.PERMISSION_ALL
+		});
+		testFiles = [new FileInfo({
 			id: 1,
 			type: 'file',
 			name: 'One.txt',
@@ -102,7 +123,7 @@ describe('OCA.Files.FileList tests', function() {
 			size: 12,
 			etag: 'abc',
 			permissions: OC.PERMISSION_ALL
-		}, {
+		}), new FileInfo({
 			id: 2,
 			type: 'file',
 			name: 'Two.jpg',
@@ -111,7 +132,7 @@ describe('OCA.Files.FileList tests', function() {
 			size: 12049,
 			etag: 'def',
 			permissions: OC.PERMISSION_ALL
-		}, {
+		}), new FileInfo({
 			id: 3,
 			type: 'file',
 			name: 'Three.pdf',
@@ -120,7 +141,7 @@ describe('OCA.Files.FileList tests', function() {
 			size: 58009,
 			etag: '123',
 			permissions: OC.PERMISSION_ALL
-		}, {
+		}), new FileInfo({
 			id: 4,
 			type: 'dir',
 			name: 'somedir',
@@ -129,9 +150,11 @@ describe('OCA.Files.FileList tests', function() {
 			size: 250,
 			etag: '456',
 			permissions: OC.PERMISSION_ALL
-		}];
+		})];
 		pageSizeStub = sinon.stub(OCA.Files.FileList.prototype, 'pageSize').returns(20);
-		fileList = new OCA.Files.FileList($('#app-content-files'));
+		fileList = new OCA.Files.FileList($('#app-content-files'), {
+			filesClient: filesClient
+		});
 	});
 	afterEach(function() {
 		testFiles = undefined;
@@ -141,9 +164,9 @@ describe('OCA.Files.FileList tests', function() {
 		fileList = undefined;
 
 		notificationStub.restore();
-		alertStub.restore();
 		bcResizeStub.restore();
 		pageSizeStub.restore();
+		redirectStub.restore();
 	});
 	describe('Getters', function() {
 		it('Returns the current directory', function() {
@@ -166,15 +189,14 @@ describe('OCA.Files.FileList tests', function() {
 			clock.restore();
 		});
 		it('generates file element with correct attributes when calling add() with file data', function() {
-			var fileData = {
+			var fileData = new FileInfo({
 				id: 18,
-				type: 'file',
 				name: 'testName.txt',
 				mimetype: 'text/plain',
-				size: '1234',
+				size: 1234,
 				etag: 'a01234c',
-				mtime: '123456'
-			};
+				mtime: 123456
+			});
 			var $tr = fileList.add(fileData);
 
 			expect($tr).toBeDefined();
@@ -188,7 +210,7 @@ describe('OCA.Files.FileList tests', function() {
 			expect($tr.attr('data-mime')).toEqual('text/plain');
 			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');
+				.toEqual(OC.webroot + '/remote.php/webdav/subdir/testName.txt');
 			expect($tr.find('.nametext').text().trim()).toEqual('testName.txt');
 
 			expect($tr.find('.filesize').text()).toEqual('1 kB');
@@ -196,15 +218,14 @@ describe('OCA.Files.FileList tests', function() {
 			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 = {
+			var fileData = new FileInfo({
 				id: 19,
-				type: 'dir',
 				name: 'testFolder',
 				mimetype: 'httpd/unix-directory',
-				size: '1234',
+				size: 1234,
 				etag: 'a01234c',
-				mtime: '123456'
-			};
+				mtime: 123456
+			});
 			var $tr = fileList.add(fileData);
 
 			expect($tr).toBeDefined();
@@ -297,7 +318,6 @@ describe('OCA.Files.FileList tests', function() {
 			expect($tr.index()).toEqual(4);
 		});
 		it('inserts files in a sorted manner when insert option is enabled', function() {
-			var $tr;
 			for (var i = 0; i < testFiles.length; i++) {
 				fileList.add(testFiles[i]);
 			}
@@ -423,28 +443,31 @@ describe('OCA.Files.FileList tests', function() {
 		});
 	});
 	describe('Deleting files', function() {
+		var deferredDelete;
+		var deleteStub;
+
+		beforeEach(function() {
+			deferredDelete = $.Deferred();
+			deleteStub = sinon.stub(filesClient, 'remove').returns(deferredDelete.promise());
+		});
+		afterEach(function() {
+			deleteStub.restore();
+		});
+
 		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"]'});
+			expect(deleteStub.calledTwice).toEqual(true);
+			expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+			expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
 		}
 		it('calls delete.php, removes the deleted entries and updates summary', function() {
 			var $summary;
 			fileList.setFiles(testFiles);
 			doDelete();
 
-			fakeServer.requests[0].respond(
-				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({status: 'success'})
-			);
+			deferredDelete.resolve(200);
 
 			expect(fileList.findFileEl('One.txt').length).toEqual(0);
 			expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
@@ -482,11 +505,7 @@ describe('OCA.Files.FileList tests', function() {
 			fileList.setFiles([testFiles[0], testFiles[1]]);
 			doDelete();
 
-			fakeServer.requests[0].respond(
-				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({status: 'success'})
-			);
+			deferredDelete.resolve(200);
 
 			expect(fileList.$fileList.find('tr').length).toEqual(0);
 
@@ -501,21 +520,41 @@ describe('OCA.Files.FileList tests', function() {
 			fileList.setFiles(testFiles);
 			doDelete();
 
-			fakeServer.requests[0].respond(
-				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({status: 'error', data: {message: 'WOOT'}})
-			);
+			deferredDelete.reject(403);
 
 			// 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').length).toEqual(4);
 
-			expect(notificationStub.calledOnce).toEqual(true);
+			expect(notificationStub.calledTwice).toEqual(true);
+		});
+		it('remove file from list if delete call returned 404 not found', function() {
+			fileList.setFiles(testFiles);
+			doDelete();
+
+			deferredDelete.reject(404);
+
+			// files are still in the list
+			expect(fileList.findFileEl('One.txt').length).toEqual(0);
+			expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
+			expect(fileList.$fileList.find('tr').length).toEqual(2);
+
+			expect(notificationStub.notCalled).toEqual(true);
 		});
 	});
 	describe('Renaming files', function() {
+		var deferredRename;
+		var renameStub;
+
+		beforeEach(function() {
+			deferredRename = $.Deferred();
+			renameStub = sinon.stub(filesClient, 'move').returns(deferredRename.promise());
+		});
+		afterEach(function() {
+			renameStub.restore();
+		});
+
 		function doCancelRename() {
 			var $input;
 			for (var i = 0; i < testFiles.length; i++) {
@@ -530,10 +569,10 @@ describe('OCA.Files.FileList tests', function() {
 			// trigger submit because triggering blur doesn't work in all browsers
 			$input.closest('form').trigger('submit');
 
-			expect(fakeServer.requests.length).toEqual(0);
+			expect(renameStub.notCalled).toEqual(true);
 		}
 		function doRename() {
-			var $input, request;
+			var $input;
 
 			for (var i = 0; i < testFiles.length; i++) {
 				var file = testFiles[i];
@@ -548,83 +587,61 @@ describe('OCA.Files.FileList tests', function() {
 			// trigger submit because triggering blur doesn't work in all browsers
 			$input.closest('form').trigger('submit');
 
-			expect(fakeServer.requests.length).toEqual(1);
-			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': '/some/subdir', newname: 'Tu_after_three.txt', file: 'One.txt'});
+			expect(renameStub.calledOnce).toEqual(true);
+			expect(renameStub.getCall(0).args[0]).toEqual('/some/subdir/One.txt');
+			expect(renameStub.getCall(0).args[1]).toEqual('/some/subdir/Tu_after_three.txt');
 		}
 		it('Inserts renamed file entry at correct position if rename ajax call suceeded', function() {
 			doRename();
 
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'success',
-				data: {
-					name: 'Tu_after_three.txt',
-					type: 'file'
-				}
-			}));
+			deferredRename.resolve(201);
 
 			// element stays renamed
 			expect(fileList.findFileEl('One.txt').length).toEqual(0);
 			expect(fileList.findFileEl('Tu_after_three.txt').length).toEqual(1);
-			expect(fileList.findFileEl('Tu_after_three.txt').index()).toEqual(2); // after Two.txt
+			expect(fileList.findFileEl('Tu_after_three.txt').index()).toEqual(2); // after Two.jpg
 
-			expect(alertStub.notCalled).toEqual(true);
+			expect(notificationStub.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'
-				}
-			}));
+			deferredRename.reject(403);
 
 			// element was reverted
 			expect(fileList.findFileEl('One.txt').length).toEqual(1);
 			expect(fileList.findFileEl('One.txt').index()).toEqual(1); // after somedir
 			expect(fileList.findFileEl('Tu_after_three.txt').length).toEqual(0);
 
-			expect(alertStub.calledOnce).toEqual(true);
+			expect(notificationStub.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: 'Tu_after_three.txt'
-				}
-			}));
+			deferredRename.resolve(201);
 
 			$tr = fileList.findFileEl('Tu_after_three.txt');
-			expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=Tu_after_three.txt');
+			expect($tr.find('a.name').attr('href'))
+				.toEqual(OC.webroot + '/remote.php/webdav/some/subdir/Tu_after_three.txt');
 		});
 		it('Triggers "fileActionsReady" event after rename', function() {
 			var handler = sinon.stub();
 			fileList.$fileList.on('fileActionsReady', handler);
 			doRename();
 			expect(handler.notCalled).toEqual(true);
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'success',
-				data: {
-					name: 'Tu_after_three.txt'
-				}
-			}));
+
+			deferredRename.resolve(201);
+
 			expect(handler.calledOnce).toEqual(true);
 			expect(fileList.$fileList.find('.test').length).toEqual(0);
 		});
 		it('Leaves the summary alone when reinserting renamed element', function() {
 			var $summary = $('#filestable .summary');
 			doRename();
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'success',
-				data: {
-					name: 'Tu_after_three.txt'
-				}
-			}));
+
+			deferredRename.resolve(201);
+
 			expect($summary.find('.info').text()).toEqual('1 folder and 3 files');
 		});
 		it('Leaves the summary alone when cancel renaming', function() {
@@ -668,7 +685,7 @@ describe('OCA.Files.FileList tests', function() {
 
 			// trigger submit does not send server request
 			$input.closest('form').trigger('submit');
-			expect(fakeServer.requests.length).toEqual(0);
+			expect(renameStub.notCalled).toEqual(true);
 
 			// simulate escape key
 			$input.trigger(new $.Event('keyup', {keyCode: 27}));
@@ -694,12 +711,7 @@ describe('OCA.Files.FileList tests', function() {
 			expect(OC.TestUtil.getImageUrl(fileList.findFileEl('Tu_after_three.txt').find('.thumbnail')))
 				.toEqual(OC.imagePath('core', 'loading.gif'));
 
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'error',
-				data: {
-					message: 'Something went wrong'
-				}
-			}));
+			deferredRename.reject(409);
 
 			expect(fileList.findFileEl('One.txt').length).toEqual(1);
 			expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
@@ -707,25 +719,27 @@ describe('OCA.Files.FileList tests', function() {
 		});
 	});
 	describe('Moving files', function() {
+		var deferredMove;
+		var moveStub;
+
 		beforeEach(function() {
+			deferredMove = $.Deferred();
+			moveStub = sinon.stub(filesClient, 'move').returns(deferredMove.promise());
+
 			fileList.setFiles(testFiles);
 		});
+		afterEach(function() {
+			moveStub.restore();
+		});
+
 		it('Moves single file to target folder', function() {
-			var request;
 			fileList.move('One.txt', '/somedir');
 
-			expect(fakeServer.requests.length).toEqual(1);
-			request = fakeServer.requests[0];
-			expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
-			expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+			expect(moveStub.calledOnce).toEqual(true);
+			expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+			expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
 
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'success',
-				data: {
-					name: 'One.txt',
-					type: 'file'
-				}
-			}));
+			deferredMove.resolve(201);
 
 			expect(fileList.findFileEl('One.txt').length).toEqual(0);
 
@@ -736,39 +750,28 @@ describe('OCA.Files.FileList tests', function() {
 			expect(notificationStub.notCalled).toEqual(true);
 		});
 		it('Moves list of files to target folder', function() {
-			var request;
+			var deferredMove1 = $.Deferred();
+			var deferredMove2 = $.Deferred();
+			moveStub.onCall(0).returns(deferredMove1.promise());
+			moveStub.onCall(1).returns(deferredMove2.promise());
+
 			fileList.move(['One.txt', 'Two.jpg'], '/somedir');
 
-			expect(fakeServer.requests.length).toEqual(2);
-			request = fakeServer.requests[0];
-			expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
-			expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+			expect(moveStub.calledTwice).toEqual(true);
+			expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+			expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
+			expect(moveStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
+			expect(moveStub.getCall(1).args[1]).toEqual('/somedir/Two.jpg');
 
-			request = fakeServer.requests[1];
-			expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
-			expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'Two.jpg', target: '/somedir'});
-
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'success',
-				data: {
-					name: 'One.txt',
-					type: 'file'
-				}
-			}));
+			deferredMove1.resolve(201);
 
 			expect(fileList.findFileEl('One.txt').length).toEqual(0);
 
-			// folder size has increased
+			// folder size has increased during move
 			expect(fileList.findFileEl('somedir').data('size')).toEqual(262);
 			expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');
 
-			fakeServer.requests[1].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'success',
-				data: {
-					name: 'Two.jpg',
-					type: 'file'
-				}
-			}));
+			deferredMove2.resolve(201);
 
 			expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
 
@@ -779,47 +782,31 @@ describe('OCA.Files.FileList tests', function() {
 			expect(notificationStub.notCalled).toEqual(true);
 		});
 		it('Shows notification if a file could not be moved', function() {
-			var request;
 			fileList.move('One.txt', '/somedir');
 
-			expect(fakeServer.requests.length).toEqual(1);
-			request = fakeServer.requests[0];
-			expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
-			expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+			expect(moveStub.calledOnce).toEqual(true);
 
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'error',
-				data: {
-					message: 'Error while moving file'
-				}
-			}));
+			deferredMove.reject(409);
 
 			expect(fileList.findFileEl('One.txt').length).toEqual(1);
 
 			expect(notificationStub.calledOnce).toEqual(true);
-			expect(notificationStub.getCall(0).args[0]).toEqual('Error while moving file');
+			expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
 		});
 		it('Restores thumbnail if a file could not be moved', function() {
-			var request;
 			fileList.move('One.txt', '/somedir');
 
 			expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
 				.toEqual(OC.imagePath('core', 'loading.gif'));
 
-			expect(fakeServer.requests.length).toEqual(1);
-			request = fakeServer.requests[0];
+			expect(moveStub.calledOnce).toEqual(true);
 
-			fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
-				status: 'error',
-				data: {
-					message: 'Error while moving file'
-				}
-			}));
+			deferredMove.reject(409);
 
 			expect(fileList.findFileEl('One.txt').length).toEqual(1);
 
 			expect(notificationStub.calledOnce).toEqual(true);
-			expect(notificationStub.getCall(0).args[0]).toEqual('Error while moving file');
+			expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
 
 			expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
 				.toEqual(OC.imagePath('core', 'filetypes/text.svg'));
@@ -878,7 +865,7 @@ describe('OCA.Files.FileList tests', function() {
 				name: 'testFile.txt',
 				directory: '/current dir'
 			};
-			var $tr = fileList.add(fileData);
+			fileList.add(fileData);
 			expect(fileList.findFileEl('testFile.txt').length).toEqual(1);
 		});
 		it('triggers "fileActionsReady" event after update', function() {
@@ -1143,69 +1130,85 @@ describe('OCA.Files.FileList tests', function() {
 		afterEach(function() {
 			previewLoadStub.restore();
 		});
-		it('renders default icon for file when none provided and no preview is available', function() {
+		it('renders default file icon when none provided and no mime type is set', function() {
 			var fileData = {
-				type: 'file',
 				name: 'testFile.txt'
 			};
 			var $tr = fileList.add(fileData);
 			var $imgDiv = $tr.find('td.filename .thumbnail');
 			expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
-			expect(previewLoadStub.notCalled).toEqual(true);
+			// tries to load preview
+			expect(previewLoadStub.calledOnce).toEqual(true);
 		});
-		it('renders default icon for dir when none provided and no preview is available', function() {
+		it('renders default icon for folder when none provided', function() {
 			var fileData = {
-				type: 'dir',
-				name: 'test dir'
+				name: 'test dir',
+				mimetype: 'httpd/unix-directory'
 			};
+
 			var $tr = fileList.add(fileData);
 			var $imgDiv = $tr.find('td.filename .thumbnail');
 			expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/folder.svg');
+			// no preview since it's a directory
 			expect(previewLoadStub.notCalled).toEqual(true);
 		});
 		it('renders provided icon for file when provided', function() {
-			var fileData = {
+			var fileData = new FileInfo({
 				type: 'file',
 				name: 'test file',
 				icon: OC.webroot + '/core/img/filetypes/application-pdf.svg',
 				mimetype: 'application/pdf'
-			};
+			});
 			var $tr = fileList.add(fileData);
 			var $imgDiv = $tr.find('td.filename .thumbnail');
 			expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg');
+			// try loading preview
+			expect(previewLoadStub.calledOnce).toEqual(true);
+		});
+		it('renders provided icon for file when provided', function() {
+			var fileData = new FileInfo({
+				name: 'somefile.pdf',
+				icon: OC.webroot + '/core/img/filetypes/application-pdf.svg'
+			});
+
+			var $tr = fileList.add(fileData);
+			var $imgDiv = $tr.find('td.filename .thumbnail');
+			expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg');
+			// try loading preview
+			expect(previewLoadStub.calledOnce).toEqual(true);
+		});
+		it('renders provided icon for folder when provided', function() {
+			var fileData = new FileInfo({
+				name: 'some folder',
+				mimetype: 'httpd/unix-directory',
+				icon: OC.webroot + '/core/img/filetypes/folder-alt.svg'
+			});
+
+			var $tr = fileList.add(fileData);
+			var $imgDiv = $tr.find('td.filename .thumbnail');
+			expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/folder-alt.svg');
+			// do not load preview for folders
 			expect(previewLoadStub.notCalled).toEqual(true);
 		});
-		it('renders preview when no icon was provided and preview is available', function() {
+		it('renders preview when no icon was provided', function() {
 			var fileData = {
 				type: 'file',
-				name: 'test file',
-				isPreviewAvailable: true
+				name: 'test file'
 			};
 			var $tr = fileList.add(fileData);
 			var $td = $tr.find('td.filename');
-			expect(OC.TestUtil.getImageUrl($td.find('.thumbnail'))).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
+			expect(OC.TestUtil.getImageUrl($td.find('.thumbnail')))
+				.toEqual(OC.webroot + '/core/img/filetypes/file.svg');
 			expect(previewLoadStub.calledOnce).toEqual(true);
 			// third argument is callback
 			previewLoadStub.getCall(0).args[0].callback(OC.webroot + '/somepath.png');
 			expect(OC.TestUtil.getImageUrl($td.find('.thumbnail'))).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 file',
-				isPreviewAvailable: false
-			};
-			var $tr = fileList.add(fileData);
-			var $imgDiv = $tr.find('td.filename .thumbnail');
-			expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
-			expect(previewLoadStub.notCalled).toEqual(true);
-		});
 		it('does not render preview for directories', function() {
 			var fileData = {
 				type: 'dir',
 				mimetype: 'httpd/unix-directory',
-				name: 'test dir',
-				isPreviewAvailable: true
+				name: 'test dir'
 			};
 			var $tr = fileList.add(fileData);
 			var $td = $tr.find('td.filename');
@@ -1217,7 +1220,6 @@ describe('OCA.Files.FileList tests', function() {
 				type: 'dir',
 				mimetype: 'httpd/unix-directory',
 				name: 'test dir',
-				isPreviewAvailable: true,
 				mountType: 'external-root'
 			};
 			var $tr = fileList.add(fileData);
@@ -1230,7 +1232,6 @@ describe('OCA.Files.FileList tests', function() {
 				type: 'dir',
 				mimetype: 'httpd/unix-directory',
 				name: 'test dir',
-				isPreviewAvailable: true,
 				mountType: 'external'
 			};
 			var $tr = fileList.add(fileData);
@@ -1278,75 +1279,47 @@ describe('OCA.Files.FileList tests', function() {
 		});
 	});
 	describe('loading file list', function() {
+		var deferredList;
+		var getFolderContentsStub;
+
 		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)
-				]);
+			deferredList = $.Deferred();
+			getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+		});
+		afterEach(function() {
+			getFolderContentsStub.restore();
 		});
 		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', sort: 'name', sortdirection: 'asc'});
-			fakeServer.respond();
+			expect(getFolderContentsStub.calledOnce).toEqual(true);
+			expect(getFolderContentsStub.calledWith('/subdir')).toEqual(true);
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			expect($('#fileList tr').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', sort: 'name', sortdirection: 'asc'});
-			fakeServer.respond();
+			expect(getFolderContentsStub.calledOnce).toEqual(true);
+			expect(getFolderContentsStub.calledWith('/anothersubdir')).toEqual(true);
 		});
 		it('converts backslashes to slashes when calling changeDirectory()', function() {
 			fileList.changeDirectory('/another\\subdir');
 			expect(fileList.getCurrentDirectory()).toEqual('/another/subdir');
 		});
 		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();
+			deferredList.reject(404);
 			expect(fileList.getCurrentDirectory()).toEqual('/');
 		});
 		it('switches to root dir when current directory is forbidden', function() {
-			fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
-				403, {
-					"Content-Type": "application/json"
-				},
-				''
-			]);
 			fileList.changeDirectory('/unexist');
-			fakeServer.respond();
+			deferredList.reject(403);
 			expect(fileList.getCurrentDirectory()).toEqual('/');
 		});
 		it('switches to root dir when current directory is unavailable', function() {
-			fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
-				500, {
-					"Content-Type": "application/json"
-				},
-				''
-			]);
 			fileList.changeDirectory('/unexist');
-			fakeServer.respond();
+			deferredList.reject(500);
 			expect(fileList.getCurrentDirectory()).toEqual('/');
 		});
 		it('shows mask before loading file list then hides it at the end', function() {
@@ -1355,7 +1328,7 @@ describe('OCA.Files.FileList tests', function() {
 			fileList.changeDirectory('/anothersubdir');
 			expect(showMaskStub.calledOnce).toEqual(true);
 			expect(hideMaskStub.calledOnce).toEqual(false);
-			fakeServer.respond();
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			expect(showMaskStub.calledOnce).toEqual(true);
 			expect(hideMaskStub.calledOnce).toEqual(true);
 			showMaskStub.restore();
@@ -1365,6 +1338,7 @@ describe('OCA.Files.FileList tests', function() {
 			var handler = sinon.stub();
 			$('#app-content-files').on('changeDirectory', handler);
 			fileList.changeDirectory('/somedir');
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			expect(handler.calledOnce).toEqual(true);
 			expect(handler.getCall(0).args[0].dir).toEqual('/somedir');
 		});
@@ -1375,31 +1349,27 @@ describe('OCA.Files.FileList tests', function() {
 		it('refreshes breadcrumb after update', function() {
 			var setDirSpy = sinon.spy(fileList.breadcrumb, 'setDirectory');
 			fileList.changeDirectory('/anothersubdir');
-			fakeServer.respond();
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			expect(fileList.breadcrumb.setDirectory.calledOnce).toEqual(true);
 			expect(fileList.breadcrumb.setDirectory.calledWith('/anothersubdir')).toEqual(true);
 			setDirSpy.restore();
+			getFolderContentsStub.restore();
 		});
 	});
 	describe('breadcrumb events', function() {
+		var deferredList;
+		var getFolderContentsStub;
+
 		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)
-			]);
+			deferredList = $.Deferred();
+			getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+		});
+		afterEach(function() {
+			getFolderContentsStub.restore();
 		});
 		it('clicking on root breadcrumb changes directory to root', function() {
 			fileList.changeDirectory('/subdir/two/three with space/four/five');
-			fakeServer.respond();
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			var changeDirStub = sinon.stub(fileList, 'changeDirectory');
 			fileList.breadcrumb.$el.find('.crumb:eq(0)').trigger({type: 'click', which: 1});
 
@@ -1409,7 +1379,7 @@ describe('OCA.Files.FileList tests', function() {
 		});
 		it('clicking on breadcrumb changes directory', function() {
 			fileList.changeDirectory('/subdir/two/three with space/four/five');
-			fakeServer.respond();
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			var changeDirStub = sinon.stub(fileList, 'changeDirectory');
 			fileList.breadcrumb.$el.find('.crumb:eq(3)').trigger({type: 'click', which: 1});
 
@@ -1418,9 +1388,10 @@ describe('OCA.Files.FileList tests', function() {
 			changeDirStub.restore();
 		});
 		it('dropping files on breadcrumb calls move operation', function() {
-			var request, query, testDir = '/subdir/two/three with space/four/five';
+			var testDir = '/subdir/two/three with space/four/five';
+			var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
 			fileList.changeDirectory(testDir);
-			fakeServer.respond();
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			var $crumb = fileList.breadcrumb.$el.find('.crumb:eq(3)');
 			// no idea what this is but is required by the handler
 			var ui = {
@@ -1436,33 +1407,18 @@ describe('OCA.Files.FileList tests', function() {
 			// simulate drop event
 			fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), 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'
-			});
+			expect(moveStub.callCount).toEqual(2);
+			expect(moveStub.getCall(0).args[0]).toEqual(testDir + '/One.txt');
+			expect(moveStub.getCall(0).args[1]).toEqual('/subdir/two/three with space/One.txt');
+			expect(moveStub.getCall(1).args[0]).toEqual(testDir + '/Two.jpg');
+			expect(moveStub.getCall(1).args[1]).toEqual('/subdir/two/three with space/Two.jpg');
+			moveStub.restore();
 		});
 		it('dropping files on same dir breadcrumb does nothing', function() {
 			var testDir = '/subdir/two/three with space/four/five';
+			var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
 			fileList.changeDirectory(testDir);
-			fakeServer.respond();
+			deferredList.resolve(200, [testRoot].concat(testFiles));
 			var $crumb = fileList.breadcrumb.$el.find('.crumb:last');
 			// no idea what this is but is required by the handler
 			var ui = {
@@ -1479,21 +1435,26 @@ describe('OCA.Files.FileList tests', function() {
 			fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
 
 			// no extra server request
-			expect(fakeServer.requests.length).toEqual(1);
+			expect(moveStub.notCalled).toEqual(true);
 		});
 	});
 	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(fileList.getDownloadUrl('some file.txt'))
+				.toEqual(OC.webroot + '/remote.php/webdav/subdir/some%20file.txt');
+			expect(fileList.getDownloadUrl('some file.txt', '/anotherpath/abc'))
+				.toEqual(OC.webroot + '/remote.php/webdav/anotherpath/abc/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(fileList.getDownloadUrl('some file.txt'))
+				.toEqual(OC.webroot + '/remote.php/webdav/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(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');
 		});
 		it('returns the correct ajax URL', function() {
-			expect(fileList.getAjaxUrl('test', {a:1, b:'x y'})).toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
+			expect(fileList.getAjaxUrl('test', {a:1, b:'x y'}))
+				.toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
 		});
 	});
 	describe('File selection', function() {
@@ -1672,24 +1633,17 @@ describe('OCA.Files.FileList tests', function() {
 		});
 		it('Selection is cleared when switching dirs', function() {
 			$('.select-all').click();
-			var data = {
-				status: 'success',
-				data: {
-					files: testFiles,
-					permissions: 31
-				}
-			};
-			fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php/, [
-					200, {
-						"Content-Type": "application/json"
-					},
-					JSON.stringify(data)
-				]
-			);
+			var deferredList = $.Deferred();
+			var getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+
 			fileList.changeDirectory('/');
-			fakeServer.respond();
+
+			deferredList.resolve(200, [testRoot].concat(testFiles));
+
 			expect($('.select-all').prop('checked')).toEqual(false);
 			expect(_.pluck(fileList.getSelectedFiles(), 'name')).toEqual([]);
+
+			getFolderContentsStub.restore();
 		});
 		it('getSelectedFiles returns the selected files even when they are on the next page', function() {
 			var selectedFiles;
@@ -1796,6 +1750,12 @@ describe('OCA.Files.FileList tests', function() {
 					etag: '456',
 					permissions: OC.PERMISSION_ALL
 				});
+				expect(files[0].id).toEqual(1);
+				expect(files[0].name).toEqual('One.txt');
+				expect(files[1].id).toEqual(3);
+				expect(files[1].name).toEqual('Three.pdf');
+				expect(files[2].id).toEqual(4);
+				expect(files[2].name).toEqual('somedir');
 			});
 			it('Removing a file removes it from the selection', function() {
 				fileList.remove('Three.pdf');
@@ -1824,7 +1784,6 @@ describe('OCA.Files.FileList tests', function() {
 			});
 			describe('Download', function() {
 				it('Opens download URL when clicking "Download"', function() {
-					var redirectStub = sinon.stub(OC, 'redirect');
 					$('.selectedActions .download').click();
 					expect(redirectStub.calledOnce).toEqual(true);
 					expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22One.txt%22%2C%22Three.pdf%22%2C%22somedir%22%5D');
@@ -1833,54 +1792,53 @@ describe('OCA.Files.FileList tests', function() {
 				it('Downloads root folder when all selected in root folder', function() {
 					$('#dir').val('/');
 					$('.select-all').click();
-					var redirectStub = sinon.stub(OC, 'redirect');
 					$('.selectedActions .download').click();
 					expect(redirectStub.calledOnce).toEqual(true);
 					expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=');
-					redirectStub.restore();
 				});
 				it('Downloads parent folder when all selected in subfolder', function() {
 					$('.select-all').click();
-					var redirectStub = sinon.stub(OC, 'redirect');
 					$('.selectedActions .download').click();
 					expect(redirectStub.calledOnce).toEqual(true);
 					expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=subdir');
-					redirectStub.restore();
 				});
 			});
 			describe('Delete', function() {
+				var deleteStub, deferredDelete;
+				beforeEach(function() {
+					deferredDelete = $.Deferred();
+					deleteStub = sinon.stub(filesClient, 'remove').returns(deferredDelete.promise());
+				});
+				afterEach(function() {
+					deleteStub.restore();
+				});
 				it('Deletes selected files when "Delete" clicked', function() {
-					var request;
 					$('.selectedActions .delete-selected').click();
-					expect(fakeServer.requests.length).toEqual(1);
-					request = fakeServer.requests[0];
-					expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
-					expect(OC.parseQueryString(request.requestBody))
-						.toEqual({'dir': '/subdir', files: '["One.txt","Three.pdf","somedir"]'});
-					fakeServer.requests[0].respond(
-						200,
-						{ 'Content-Type': 'application/json' },
-						JSON.stringify({status: 'success'})
-					);
+
+					expect(deleteStub.callCount).toEqual(3);
+					expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+					expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Three.pdf');
+					expect(deleteStub.getCall(2).args[0]).toEqual('/subdir/somedir');
+
+					deferredDelete.resolve(204);
+
 					expect(fileList.findFileEl('One.txt').length).toEqual(0);
 					expect(fileList.findFileEl('Three.pdf').length).toEqual(0);
 					expect(fileList.findFileEl('somedir').length).toEqual(0);
 					expect(fileList.findFileEl('Two.jpg').length).toEqual(1);
 				});
 				it('Deletes all files when all selected when "Delete" clicked', function() {
-					var request;
 					$('.select-all').click();
 					$('.selectedActions .delete-selected').click();
-					expect(fakeServer.requests.length).toEqual(1);
-					request = fakeServer.requests[0];
-					expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
-					expect(OC.parseQueryString(request.requestBody))
-						.toEqual({'dir': '/subdir', allfiles: 'true'});
-					fakeServer.requests[0].respond(
-						200,
-						{ 'Content-Type': 'application/json' },
-						JSON.stringify({status: 'success'})
-					);
+
+					expect(deleteStub.callCount).toEqual(4);
+					expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+					expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
+					expect(deleteStub.getCall(2).args[0]).toEqual('/subdir/Three.pdf');
+					expect(deleteStub.getCall(3).args[0]).toEqual('/subdir/somedir');
+
+					deferredDelete.resolve(204);
+
 					expect(fileList.isEmpty).toEqual(true);
 				});
 			});
@@ -2118,30 +2076,6 @@ describe('OCA.Files.FileList tests', function() {
 		});
 	});
 	describe('Sorting files', function() {
-		it('Sorts by name by default', function() {
-			fileList.reload();
-			expect(fakeServer.requests.length).toEqual(1);
-			var url = fakeServer.requests[0].url;
-			var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
-			expect(query.sort).toEqual('name');
-			expect(query.sortdirection).toEqual('asc');
-		});
-		it('Reloads file list with a different sort when clicking on column header of unsorted column', function() {
-			fileList.$el.find('.column-size .columntitle').click();
-			expect(fakeServer.requests.length).toEqual(1);
-			var url = fakeServer.requests[0].url;
-			var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
-			expect(query.sort).toEqual('size');
-			expect(query.sortdirection).toEqual('desc');
-		});
-		it('Toggles sort direction when clicking on already sorted column', function() {
-			fileList.$el.find('.column-name .columntitle').click();
-			expect(fakeServer.requests.length).toEqual(1);
-			var url = fakeServer.requests[0].url;
-			var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
-			expect(query.sort).toEqual('name');
-			expect(query.sortdirection).toEqual('desc');
-		});
 		it('Toggles the sort indicator when clicking on a column header', function() {
 			var ASC_CLASS = fileList.SORT_INDICATOR_ASC_CLASS;
 			var DESC_CLASS = fileList.SORT_INDICATOR_DESC_CLASS;
@@ -2191,28 +2125,15 @@ describe('OCA.Files.FileList tests', function() {
 		it('Uses correct sort comparator when inserting files', function() {
 			testFiles.sort(OCA.Files.FileList.Comparators.size);
 			testFiles.reverse();	//default is descending
-			// this will make it reload the testFiles with the correct sorting
+			fileList.setFiles(testFiles);
 			fileList.$el.find('.column-size .columntitle').click();
-			expect(fakeServer.requests.length).toEqual(1);
-			fakeServer.requests[0].respond(
-				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({
-					status: 'success',
-					data: {
-						files: testFiles,
-						permissions: 31
-					}
-				})
-			);
-			var newFileData = {
+			var newFileData = new FileInfo({
 				id: 999,
-				type: 'file',
 				name: 'new file.txt',
 				mimetype: 'text/plain',
 				size: 40001,
 				etag: '999'
-			};
+			});
 			fileList.add(newFileData);
 			expect(fileList.findFileEl('Three.pdf').index()).toEqual(0);
 			expect(fileList.findFileEl('new file.txt').index()).toEqual(1);
@@ -2224,41 +2145,18 @@ describe('OCA.Files.FileList tests', function() {
 		});
 		it('Uses correct reversed sort comparator when inserting files', function() {
 			testFiles.sort(OCA.Files.FileList.Comparators.size);
-			// this will make it reload the testFiles with the correct sorting
+			fileList.setFiles(testFiles);
 			fileList.$el.find('.column-size .columntitle').click();
-			expect(fakeServer.requests.length).toEqual(1);
-			fakeServer.requests[0].respond(
-				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({
-					status: 'success',
-					data: {
-						files: testFiles,
-						permissions: 31
-					}
-				})
-			);
+
 			// reverse sort
 			fileList.$el.find('.column-size .columntitle').click();
-			fakeServer.requests[1].respond(
-				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({
-					status: 'success',
-					data: {
-						files: testFiles,
-						permissions: 31
-					}
-				})
-			);
-			var newFileData = {
+			var newFileData = new FileInfo({
 				id: 999,
-				type: 'file',
 				name: 'new file.txt',
 				mimetype: 'text/plain',
 				size: 40001,
 				etag: '999'
-			};
+			});
 			fileList.add(newFileData);
 			expect(fileList.findFileEl('One.txt').index()).toEqual(0);
 			expect(fileList.findFileEl('somedir').index()).toEqual(1);
@@ -2290,87 +2188,96 @@ describe('OCA.Files.FileList tests', function() {
 	});
 	describe('create file', function() {
 		var deferredCreate;
+		var deferredInfo;
+		var createStub;
+		var getFileInfoStub;
 
 		beforeEach(function() {
 			deferredCreate = $.Deferred();
+			deferredInfo = $.Deferred();
+			createStub = sinon.stub(filesClient, 'putFileContents')
+				.returns(deferredCreate.promise());
+			getFileInfoStub = sinon.stub(filesClient, 'getFileInfo')
+				.returns(deferredInfo.promise());
+		});
+		afterEach(function() {
+			createStub.restore();
+			getFileInfoStub.restore();
 		});
 
 		it('creates file with given name and adds it to the list', function() {
-			var deferred = fileList.createFile('test file.txt');
-			var successStub = sinon.stub();
-			var failureStub = sinon.stub();
+			fileList.createFile('test.txt');
 
-			deferred.done(successStub);
-			deferred.fail(failureStub);
+			expect(createStub.calledOnce).toEqual(true);
+			expect(createStub.getCall(0).args[0]).toEqual('/subdir/test.txt');
+			expect(createStub.getCall(0).args[2]).toEqual({
+				contentType: 'text/plain',
+				overwrite: true
+			});
 
-			expect(fakeServer.requests.length).toEqual(1);
-			expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfile.php'));
+			deferredCreate.resolve(200);
 
-			var query = fakeServer.requests[0].requestBody;
-			expect(OC.parseQueryString(query)).toEqual({
-				dir: '/subdir',
-				filename: 'test file.txt'
-			});
+			expect(getFileInfoStub.calledOnce).toEqual(true);
+			expect(getFileInfoStub.getCall(0).args[0]).toEqual('/subdir/test.txt');
 
-			fakeServer.requests[0].respond(
+			deferredInfo.resolve(
 				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({
-					status: 'success',
-					data: {
-						path: '/subdir',
-						name: 'test file.txt',
-						mimetype: 'text/plain'
-					}
+			   	new FileInfo({
+					path: '/subdir',
+					name: 'test.txt',
+					mimetype: 'text/plain'
 				})
 			);
 
-			var $tr = fileList.findFileEl('test file.txt');
+			var $tr = fileList.findFileEl('test.txt');
 			expect($tr.length).toEqual(1);
 			expect($tr.attr('data-mime')).toEqual('text/plain');
-
-			expect(successStub.calledOnce).toEqual(true);
-			expect(failureStub.notCalled).toEqual(true);
 		});
 		// TODO: error cases
 		// TODO: unique name cases
 	});
-	describe('create directory', function() {
-		it('creates directory with given name and adds it to the list', function() {
-			var deferred = fileList.createDirectory('test directory');
-			var successStub = sinon.stub();
-			var failureStub = sinon.stub();
-
-			deferred.done(successStub);
-			deferred.fail(failureStub);
-
-			expect(fakeServer.requests.length).toEqual(1);
-			expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfolder.php'));
-			var query = fakeServer.requests[0].requestBody;
-			expect(OC.parseQueryString(query)).toEqual({
-				dir: '/subdir',
-				foldername: 'test directory'
-			});
+	describe('create folder', function() {
+		var deferredCreate;
+		var deferredInfo;
+		var createStub;
+		var getFileInfoStub;
+
+		beforeEach(function() {
+			deferredCreate = $.Deferred();
+			deferredInfo = $.Deferred();
+			createStub = sinon.stub(filesClient, 'createDirectory')
+				.returns(deferredCreate.promise());
+			getFileInfoStub = sinon.stub(filesClient, 'getFileInfo')
+				.returns(deferredInfo.promise());
+		});
+		afterEach(function() {
+			createStub.restore();
+			getFileInfoStub.restore();
+		});
+
+		it('creates folder with given name and adds it to the list', function() {
+			fileList.createDirectory('sub dir');
+
+			expect(createStub.calledOnce).toEqual(true);
+			expect(createStub.getCall(0).args[0]).toEqual('/subdir/sub dir');
 
-			fakeServer.requests[0].respond(
+			deferredCreate.resolve(200);
+
+			expect(getFileInfoStub.calledOnce).toEqual(true);
+			expect(getFileInfoStub.getCall(0).args[0]).toEqual('/subdir/sub dir');
+
+			deferredInfo.resolve(
 				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({
-					status: 'success',
-					data: {
-						path: '/subdir',
-						name: 'test directory',
-						mimetype: 'httpd/unix-directory'
-					}
+			   	new FileInfo({
+					path: '/subdir',
+					name: 'sub dir',
+					mimetype: 'httpd/unix-directory'
 				})
 			);
 
-			var $tr = fileList.findFileEl('test directory');
+			var $tr = fileList.findFileEl('sub dir');
 			expect($tr.length).toEqual(1);
 			expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
-
-			expect(successStub.calledOnce).toEqual(true);
-			expect(failureStub.notCalled).toEqual(true);
 		});
 		// TODO: error cases
 		// TODO: unique name cases
@@ -2481,14 +2388,14 @@ describe('OCA.Files.FileList tests', function() {
 				expect(ev.result).not.toEqual(false);
 			});
 			it('drop on a folder row inside the table triggers upload to target folder', function() {
-				var ev, formData;
+				var ev;
 				ev = dropOn(fileList.findFileEl('somedir').find('td:eq(2)'), uploadData);
 
 				expect(ev.result).not.toEqual(false);
 				expect(uploadData.targetDir).toEqual('/subdir/somedir');
 			});
 			it('drop on a breadcrumb inside the table triggers upload to target folder', function() {
-				var ev, formData;
+				var ev;
 				fileList.changeDirectory('a/b/c/d');
 				ev = dropOn(fileList.$el.find('.crumb:eq(2)'), uploadData);
 
@@ -2497,32 +2404,50 @@ describe('OCA.Files.FileList tests', function() {
 			});
 		});
 	});
-	describe('Handeling errors', function () {
-		var redirectStub;
+	describe('Handling errors', function () {
+		var deferredList;
+		var getFolderContentsStub;
 
-		beforeEach(function () {
-			redirectStub = sinon.stub(OC, 'redirect');
-
-			fileList = new OCA.Files.FileList($('#app-content-files'));
+		beforeEach(function() {
+			deferredList = $.Deferred();
+			getFolderContentsStub =
+				sinon.stub(filesClient, 'getFolderContents');
+			getFolderContentsStub.onCall(0).returns(deferredList.promise());
+			getFolderContentsStub.onCall(1).returns($.Deferred().promise());
+			fileList.reload();
 		});
-		afterEach(function () {
+		afterEach(function() {
+			getFolderContentsStub.restore();
 			fileList = undefined;
+		});
+		it('redirects to files app in case of auth error', function () {
+			deferredList.reject(401, 'Authentication error');
 
-			redirectStub.restore();
+			expect(redirectStub.calledOnce).toEqual(true);
+			expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files');
+			expect(getFolderContentsStub.calledOnce).toEqual(true);
 		});
-		it('reloads the page on authentication errors', function () {
-			fileList.reload();
-			fakeServer.requests[0].respond(
-				200,
-				{ 'Content-Type': 'application/json' },
-				JSON.stringify({
-					status: 'error',
-					data: {
-						'error': 'authentication_error'
-					}
-				})
-			);
-			expect(redirectStub.calledWith(OC.generateUrl('apps/files'))).toEqual(true);
+		it('redirects to root folder in case of forbidden access', function () {
+			deferredList.reject(403);
+
+			expect(fileList.getCurrentDirectory()).toEqual('/');
+			expect(getFolderContentsStub.calledTwice).toEqual(true);
+		});
+		it('redirects to root folder and shows notification in case of internal server error', function () {
+			expect(notificationStub.notCalled).toEqual(true);
+			deferredList.reject(500);
+
+			expect(fileList.getCurrentDirectory()).toEqual('/');
+			expect(getFolderContentsStub.calledTwice).toEqual(true);
+			expect(notificationStub.calledOnce).toEqual(true);
+		});
+		it('redirects to root folder and shows notification in case of storage not available', function () {
+			expect(notificationStub.notCalled).toEqual(true);
+			deferredList.reject(503, 'Storage not available');
+
+			expect(fileList.getCurrentDirectory()).toEqual('/');
+			expect(getFolderContentsStub.calledTwice).toEqual(true);
+			expect(notificationStub.calledOnce).toEqual(true);
 		});
 	});
 	describe('showFileBusyState', function() {
diff --git a/apps/files/tests/js/filesSpec.js b/apps/files/tests/js/filesSpec.js
index 30e6675c1556c3906aff0219a4b60bfab17e0e8a..b7627d59fdf66945b32531bcaf333b4c097a6c3e 100644
--- a/apps/files/tests/js/filesSpec.js
+++ b/apps/files/tests/js/filesSpec.js
@@ -76,11 +76,11 @@ describe('OCA.Files.Files tests', function() {
 	describe('getDownloadUrl', function() {
 		it('returns the ajax download URL when filename and dir specified', function() {
 			var url = Files.getDownloadUrl('test file.txt', '/subdir');
-			expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=test%20file.txt');
+			expect(url).toEqual(OC.webroot + '/remote.php/webdav/subdir/test%20file.txt');
 		});
-		it('returns the ajax download URL when filename and root dir specific', function() {
+		it('returns the webdav download URL when filename and root dir specified', function() {
 			var url = Files.getDownloadUrl('test file.txt', '/');
-			expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=test%20file.txt');
+			expect(url).toEqual(OC.webroot + '/remote.php/webdav/test%20file.txt');
 		});
 		it('returns the ajax download URL when multiple files specified', function() {
 			var url = Files.getDownloadUrl(['test file.txt', 'abc.txt'], '/subdir');
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index 68bfd63ec89ac4788eca875ed464944353f2fc45..a799d4a94c2a0b437fe4a88311e494cb1b3d32ae 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -231,6 +231,7 @@
 			files = _.chain(files)
 				// convert share data to file data
 				.map(function(share) {
+					// TODO: use OC.Files.FileInfo
 					var file = {
 						id: share.file_source,
 						icon: OC.MimeType.getIconUrl(share.mimetype),
@@ -242,9 +243,6 @@
 					}
 					else {
 						file.type = 'file';
-						if (share.isPreviewAvailable) {
-							file.isPreviewAvailable = true;
-						}
 					}
 					file.share = {
 						id: share.id,
diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js
index b4b6ac4954a9df01ba730ed8006a8da1023f2c8a..fdc9de49c174c5bdab1d3cb59d4dc6db62b00b25 100644
--- a/apps/files_sharing/tests/js/sharedfilelistSpec.js
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -166,8 +166,7 @@ describe('OCA.Sharing.FileList tests', function() {
 			expect($tr.attr('data-share-id')).toEqual('7');
 			expect($tr.find('a.name').attr('href')).toEqual(
 				OC.webroot +
-				'/index.php/apps/files/ajax/download.php' +
-				'?dir=%2Flocal%20path&files=local%20name.txt'
+				'/remote.php/webdav/local%20path/local%20name.txt'
 			);
 			expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
 
@@ -185,8 +184,7 @@ describe('OCA.Sharing.FileList tests', function() {
 			expect($tr.attr('data-share-id')).toEqual('8');
 			expect($tr.find('a.name').attr('href')).toEqual(
 				OC.webroot +
-				'/index.php/apps/files/ajax/download.php' +
-				'?dir=%2F&files=b.txt'
+				'/remote.php/webdav/b.txt'
 			);
 			expect($tr.find('.nametext').text().trim()).toEqual('b.txt');
 		});
@@ -338,8 +336,7 @@ describe('OCA.Sharing.FileList tests', function() {
 			expect($tr.attr('data-share-id')).toEqual('7');
 			expect($tr.find('a.name').attr('href')).toEqual(
 				OC.webroot +
-				'/index.php/apps/files/ajax/download.php' +
-				'?dir=%2Flocal%20path&files=local%20name.txt'
+				'/remote.php/webdav/local%20path/local%20name.txt'
 			);
 			expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
 		});
@@ -429,9 +426,8 @@ describe('OCA.Sharing.FileList tests', function() {
 			expect($tr.attr('data-share-owner')).not.toBeDefined();
 			expect($tr.attr('data-share-id')).toEqual('7');
 			expect($tr.find('a.name').attr('href')).toEqual(
-					OC.webroot +
-					'/index.php/apps/files/ajax/download.php' +
-					'?dir=%2Flocal%20path&files=local%20name.txt');
+				OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
+			);
 
 			expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
 		});
@@ -498,9 +494,7 @@ describe('OCA.Sharing.FileList tests', function() {
 			expect($tr.attr('data-share-owner')).not.toBeDefined();
 			expect($tr.attr('data-share-id')).toEqual('7,8,9');
 			expect($tr.find('a.name').attr('href')).toEqual(
-				OC.webroot +
-				'/index.php/apps/files/ajax/download.php' +
-				'?dir=%2Flocal%20path&files=local%20name.txt'
+				OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
 			);
 			expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
 		});
@@ -592,9 +586,8 @@ describe('OCA.Sharing.FileList tests', function() {
 			expect($tr.attr('data-share-owner')).not.toBeDefined();
 			expect($tr.attr('data-share-id')).toEqual('7');
 			expect($tr.find('a.name').attr('href')).toEqual(
-					OC.webroot +
-					'/index.php/apps/files/ajax/download.php' +
-					'?dir=%2Flocal%20path&files=local%20name.txt');
+				OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
+			);
 
 			expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
 		});
@@ -634,8 +627,7 @@ describe('OCA.Sharing.FileList tests', function() {
 			expect($tr.attr('data-share-id')).toEqual('7');
 			expect($tr.find('a.name').attr('href')).toEqual(
 					OC.webroot +
-					'/index.php/apps/files/ajax/download.php' +
-					'?dir=%2Flocal%20path&files=local%20name.txt');
+					'/remote.php/webdav/local%20path/local%20name.txt');
 
 			expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
 		});
diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js
index 6b624e333a06315de2a9243fca8b26395be4b21c..5812aff82f7abdd34cc54f6678aeb8adcf4379d1 100644
Binary files a/apps/files_trashbin/js/filelist.js and b/apps/files_trashbin/js/filelist.js differ
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index 4448b8130215e65349780c576cc1773e1aa018a3..fe93d0ea65701d09c6e5579c72e1faabd00df027 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -759,7 +759,7 @@ var OCdialogs = {
 					filename: entry.name,
 					date: OC.Util.relativeModifiedDate(entry.mtime)
 				});
-				if (entry.isPreviewAvailable) {
+				if (entry.type === 'file') {
 					var urlSpec = {
 						file: dir + '/' + entry.name
 					};