diff --git a/apps/files/css/files.css b/apps/files/css/files.css
index 748bc2e63a1748060d9631993c3f70f3f7fab5b9..ced2006ec06a666206c142c162d4f93def7c0bdd 100644
--- a/apps/files/css/files.css
+++ b/apps/files/css/files.css
@@ -23,7 +23,9 @@
 #new>ul>li>p { cursor:pointer; }
 #new>ul>li>form>input { padding:0.3em; margin:-0.3em; }
 
-#upload {
+#trash { height:17px;  margin:0 0 0 1em; z-index:1010; position:absolute; right:13.5em; } 
+
+#upload { 
 	height:27px; padding:0; margin-left:0.2em; overflow:hidden;
 }
 #upload a {
@@ -109,6 +111,7 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
 }
 #fileList .fileactions a.action img { position:relative; top:.2em; }
 #fileList a.action { display:inline; margin:-.5em 0; padding:1em .5em 1em .5em !important; }
+#fileList img.move2trash { display:inline; margin:-.5em 0; padding:1em .5em 1em .5em !important; float:right; }
 a.action.delete { float:right; }
 a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
 .selectedActions { display:none; float:right; }
diff --git a/apps/files/index.php b/apps/files/index.php
index d2cd76a71066516b25c11fa9ef186fd2108ee089..7e767cc8a4ff3bb390ecc9fd1c6472bf7bef2361 100644
--- a/apps/files/index.php
+++ b/apps/files/index.php
@@ -131,9 +131,10 @@ if ($needUpgrade) {
 	$tmpl->assign('isCreatable', \OC\Files\Filesystem::isCreatable($dir . '/'));
 	$tmpl->assign('permissions', $permissions);
 	$tmpl->assign('files', $files);
+	$tmpl->assign('trash', \OCP\App::isEnabled('files_trashbin'));
 	$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
 	$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
 	$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true)));
 	$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']);
 	$tmpl->printPage();
-}
+}
\ No newline at end of file
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index f5ee363a4c82e7fd2da9107c6105a03eb98482f5..c30f1bcddd8396feaeb194d65a28441db35e4010 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -147,15 +147,19 @@ $(document).ready(function () {
 	} else {
 		var downloadScope = 'file';
 	}
-	FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
-		return OC.imagePath('core', 'actions/download');
-	}, function (filename) {
-		window.location = OC.filePath('files', 'ajax', 'download.php') + '?files=' + encodeURIComponent(filename) + '&dir=' + encodeURIComponent($('#dir').val());
-	});
-
+	
+	if (typeof disableDownloadActions == 'undefined' || !disableDownloadActions) {
+		FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
+			return OC.imagePath('core', 'actions/download');
+		}, function (filename) {
+			window.location = OC.filePath('files', 'ajax', 'download.php') + '?files=' + encodeURIComponent(filename) + '&dir=' + encodeURIComponent($('#dir').val());
+		});
+	}
+	
 	$('#fileList tr').each(function(){
 		FileActions.display($(this).children('td.filename'));
 	});
+	
 });
 
 FileActions.register('all', 'Delete', OC.PERMISSION_DELETE, function () {
@@ -185,6 +189,7 @@ FileActions.register('all', 'Rename', OC.PERMISSION_UPDATE, function () {
 	FileList.rename(filename);
 });
 
+
 FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename) {
 	window.location = OC.linkTo('files', 'index.php') + '?dir=' + encodeURIComponent($('#dir').val()).replace(/%2F/g, '/') + '/' + encodeURIComponent(filename);
 });
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 04b7d92e2c35065af78f9a98dc8565c19e9d88fe..d0810f70145e520f37ce62279d595f5583ec437b 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -271,65 +271,39 @@ var FileList={
 		}
 	},
 	do_delete:function(files){
+		if(files.substr){
+			files=[files];
+		}	
+		for (var i in files) {
+			var deleteAction = $('tr').filterAttr('data-file',files[i]).children("td.date").children(".action.delete");
+			var oldHTML = deleteAction[0].outerHTML;
+			var newHTML = '<img class="move2trash" data-action="Delete" title="'+t('files', 'perform delete operation')+'" src="'+ OC.imagePath('core', 'loading.gif') +'"></a>';
+			deleteAction[0].outerHTML = newHTML;
+		}
 		// Finish any existing actions
 		if (FileList.lastAction) {
 			FileList.lastAction();
 		}
 
-		FileList.prepareDeletion(files);
-
-		if (!FileList.useUndo) {
-			FileList.lastAction();
-		} else {
-			// NOTE: Temporary fix to change the text to unshared for files in root of Shared folder
-			if ($('#dir').val() == '/Shared') {
-				OC.Notification.showHtml(t('files', 'unshared {files}', {'files': escapeHTML(files)})+'<span class="undo">'+t('files', 'undo')+'</span>');
-			} else {
-                OC.Notification.showHtml(t('files', 'deleted {files}', {'files': escapeHTML(files)})+'<span class="undo">'+t('files', 'undo')+'</span>');
-			}
-		}
-	},
-	finishDelete:function(ready,sync){
-		if(!FileList.deleteCanceled && FileList.deleteFiles){
-			var fileNames=JSON.stringify(FileList.deleteFiles);
-			$.ajax({
-				url: OC.filePath('files', 'ajax', 'delete.php'),
-				async:!sync,
-				type:'post',
-				data: {dir:$('#dir').val(),files:fileNames},
-				complete: function(data){
-					boolOperationFinished(data, function(){
-                        OC.Notification.hide();
-						$.each(FileList.deleteFiles,function(index,file){
-							FileList.remove(file);
+		var fileNames = JSON.stringify(files);
+		$.post(OC.filePath('files', 'ajax', 'delete.php'),
+				{dir:$('#dir').val(),files:fileNames},
+				function(result){
+					if (result.status == 'success') {
+						$.each(files,function(index,file){
+							var files = $('tr').filterAttr('data-file',file);
+							files.hide();
+							files.find('input[type="checkbox"]').removeAttr('checked');
+							files.removeClass('selected');
 						});
-						FileList.deleteCanceled=true;
-						FileList.deleteFiles=null;
-						FileList.lastAction = null;
-						if(ready){
-							ready();
-						}
-					});
-				}
-			});
-		}
-	},
-	prepareDeletion:function(files){
-		if(files.substr){
-			files=[files];
-		}
-		$.each(files,function(index,file){
-			var files = $('tr').filterAttr('data-file',file);
-			files.hide();
-			files.find('input[type="checkbox"]').removeAttr('checked');
-			files.removeClass('selected');
-		});
-		procesSelection();
-		FileList.deleteCanceled=false;
-		FileList.deleteFiles=files;
-		FileList.lastAction = function() {
-			FileList.finishDelete(null, true);
-		};
+						procesSelection();
+					} else {
+						$.each(files,function(index,file) {
+							var deleteAction = $('tr').filterAttr('data-file',file).children("td.date").children(".move2trash");
+							deleteAction[0].outerHTML = oldHTML;
+						});
+					} 
+				});
 	}
 };
 
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index 8e0399b0e0c21509b8b623f794bd9df76e290465..3d09d6aa2b65e9921b3b16b17e89e0fbd282503d 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -114,6 +114,11 @@ $(document).ready(function() {
 		$(this).parent().children('#file_upload_start').trigger('click');
 		return false;
 	});
+	
+	// Show trash bin
+	$('#trash a').live('click', function() {
+		window.location=OC.filePath('files_trashbin', '', 'index.php');
+	});
 
 	var lastChecked;
 
diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php
index b66b523ae38e2a7c5f4ce97880145ab33e51a5a5..2d4ed9ab2d9b33012db04917c041885caa3ab7e6 100644
--- a/apps/files/templates/index.php
+++ b/apps/files/templates/index.php
@@ -35,6 +35,11 @@
 					<a href="#" class="svg" onclick="return false;"></a>
 				</form>
 			</div>
+			<?php if ($_['trash'] ): ?>
+			<div id="trash" class="button">
+				<a><?php echo $l->t('Trash');?></a>
+			</div>
+			<?php endif; ?>
 			<div id="uploadprogresswrapper">
 				<div id="uploadprogressbar"></div>
 				<input type="button" class="stop" style="display:none"
@@ -42,7 +47,6 @@
 					onclick="javascript:Files.cancelUploads();"
 				/>
 			</div>
-
 		</div>
 		<div id="file_action_panel"></div>
 	<?php else:?>
diff --git a/apps/files_trashbin/ajax/undelete.php b/apps/files_trashbin/ajax/undelete.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7bb5b9de2dfc969fa7e05e57f77b2b4434f13c6
--- /dev/null
+++ b/apps/files_trashbin/ajax/undelete.php
@@ -0,0 +1,45 @@
+<?php 
+
+if(!OCP\User::isLoggedIn()) {
+	exit;
+}
+
+$files = $_REQUEST['files'];
+$dirlisting = $_REQUEST['dirlisting'];
+$list = explode(';', $files);
+
+$error = array();
+$success = array();
+
+$i = 0;
+foreach ($list as $file) {
+	if ( $dirlisting=='0') {
+		$delimiter = strrpos($file, '.d');
+		$filename = substr($file, 0, $delimiter);
+		$timestamp =  substr($file, $delimiter+2);
+	} else {
+		$path_parts = pathinfo($file);
+		$filename = $path_parts['basename'];
+		$timestamp = null;
+	}
+	
+	if ( !OCA_Trash\Trashbin::restore($file, $filename, $timestamp) ) {
+		$error[] = $filename;
+	} else {
+		$success[$i]['filename'] = $file;
+		$success[$i]['timestamp'] = $timestamp;
+		$i++;
+	}
+
+}
+
+if ( $error ) {
+	$filelist = '';
+	foreach ( $error as $e ) {
+		$filelist .= $e.', ';
+	}
+	OCP\JSON::error(array("data" => array("message" => "Couldn't restore ".rtrim($filelist,', '), "success" => $success, "error" => $error)));
+} else {
+	OCP\JSON::success(array("data" => array("success" => $success)));
+}
+
diff --git a/apps/files_trashbin/appinfo/app.php b/apps/files_trashbin/appinfo/app.php
new file mode 100644
index 0000000000000000000000000000000000000000..3741d42c781a08848c14eeaae383ed74e880382f
--- /dev/null
+++ b/apps/files_trashbin/appinfo/app.php
@@ -0,0 +1,7 @@
+<?php
+
+OC::$CLASSPATH['OCA_Trash\Hooks'] = 'apps/files_trashbin/lib/hooks.php';
+OC::$CLASSPATH['OCA_Trash\Trashbin'] = 'apps/files_trashbin/lib/trash.php';
+
+
+OCP\Util::connectHook('OC_Filesystem', 'delete', "OCA_Trash\Hooks", "remove_hook");
diff --git a/apps/files_trashbin/appinfo/database.xml b/apps/files_trashbin/appinfo/database.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1144a1c9a974a1fd45af02620b5898062d929ccb
--- /dev/null
+++ b/apps/files_trashbin/appinfo/database.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+
+ <name>*dbname*</name>
+ <create>true</create>
+ <overwrite>false</overwrite>
+
+ <charset>utf8</charset>
+
+ <table>
+
+  <name>*dbprefix*files_trash</name>
+
+  <declaration>
+
+   <field>
+    <name>id</name>
+    <type>text</type>
+    <default></default>
+    <notnull>true</notnull>
+    <length>50</length>
+   </field>
+
+   <field>
+    <name>user</name>
+    <type>text</type>
+    <default></default>
+    <notnull>true</notnull>
+    <length>50</length>
+   </field>
+
+   <field>
+    <name>timestamp</name>
+    <type>text</type>
+    <default></default>
+    <notnull>true</notnull>
+    <length>12</length>
+   </field>
+
+   <field>
+    <name>location</name>
+    <type>text</type>
+    <default></default>
+    <notnull>true</notnull>
+    <length>200</length>
+   </field>
+     
+   <field>
+    <name>type</name>
+    <type>text</type>
+    <default></default>
+    <notnull>true</notnull>
+    <length>4</length>
+   </field>
+   
+   <field>
+    <name>mime</name>
+    <type>text</type>
+    <default></default>
+    <notnull>true</notnull>
+    <length>30</length>
+   </field>
+     
+   <index>
+	   <name>id_index</name>
+	   <field>
+		   <name>id</name>
+		   <sorting>ascending</sorting>
+	   </field>
+   </index>
+   
+      <index>
+	   <name>timestamp_index</name>
+	   <field>
+		   <name>timestamp</name>
+		   <sorting>ascending</sorting>
+	   </field>
+   </index>
+   
+   <index>
+	   <name>user_index</name>
+	   <field>
+		   <name>user</name>
+		   <sorting>ascending</sorting>
+	   </field>
+   </index>
+  
+  </declaration>
+
+ </table>
+
+</database>
diff --git a/apps/files_trashbin/appinfo/info.xml b/apps/files_trashbin/appinfo/info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9b486126361b58fa662d35de74489f2cd13d3a95
--- /dev/null
+++ b/apps/files_trashbin/appinfo/info.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info>
+	<id>files_trashbin</id>
+	<name>Trash</name>
+	<description>Trash bin</description>
+	<licence>AGPL</licence>
+	<author>Bjoern Schiessle</author>
+	<shipped>true</shipped>
+	<require>4.9</require>
+	<default_enable/>
+	<types>
+		<filesystem/>
+	</types>
+</info>
diff --git a/apps/files_trashbin/appinfo/version b/apps/files_trashbin/appinfo/version
new file mode 100644
index 0000000000000000000000000000000000000000..49d59571fbf6e077eece30f8c418b6aad15e20b0
--- /dev/null
+++ b/apps/files_trashbin/appinfo/version
@@ -0,0 +1 @@
+0.1
diff --git a/apps/files_trashbin/download.php b/apps/files_trashbin/download.php
new file mode 100644
index 0000000000000000000000000000000000000000..665697dca5f37527980e54a4cae148543d7460da
--- /dev/null
+++ b/apps/files_trashbin/download.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+* ownCloud - trash bin
+*
+* @author Bjoern Schiessle
+* @copyright 2013 Bjoern Schiessle schiessle@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+// Check if we are a user
+OCP\User::checkLoggedIn();
+
+$filename = $_GET["file"];
+
+$view = new OC_FilesystemView('/'.\OCP\User::getUser().'/files_trashbin');
+
+if(!$view->file_exists($filename)) {
+	header("HTTP/1.0 404 Not Found");
+	$tmpl = new OCP\Template( '', '404', 'guest' );
+	$tmpl->assign('file', $filename);
+	$tmpl->printPage();
+	exit;
+}
+
+$ftype=$view->getMimeType( $filename );
+
+header('Content-Type:'.$ftype);if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) {
+	header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
+} else {
+	header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
+										 . '; filename="' . rawurlencode( basename($filename) ) . '"' );
+}
+OCP\Response::disableCaching();
+header('Content-Length: '. $view->filesize($filename));
+
+OC_Util::obEnd();
+$view->readfile( $filename );
diff --git a/apps/files_trashbin/index.php b/apps/files_trashbin/index.php
new file mode 100644
index 0000000000000000000000000000000000000000..46a601cfdde60523138e5f2c7181b4b1b53453b1
--- /dev/null
+++ b/apps/files_trashbin/index.php
@@ -0,0 +1,100 @@
+<?php
+
+// Check if we are a user
+OCP\User::checkLoggedIn();
+
+OCP\Util::addScript('files_trashbin', 'trash');
+OCP\Util::addScript('files_trashbin', 'disableDefaultActions');
+OCP\Util::addScript('files', 'fileactions');
+$tmpl = new OCP\Template('files_trashbin', 'index', 'user');
+
+$user = \OCP\User::getUser();
+$view = new OC_Filesystemview('/'.$user.'/files_trashbin');
+
+OCP\Util::addStyle('files', 'files');
+OCP\Util::addScript('files', 'filelist');
+
+$dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : '';
+
+if ($dir) {
+	$dirlisting = true;
+	$view = new \OC_FilesystemView('/'.\OCP\User::getUser().'/files_trashbin');
+	$fullpath = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath($dir);
+	$dirContent = opendir($fullpath);
+	$i = 0;
+	while($entryName = readdir($dirContent)) {
+		if ( $entryName != '.' && $entryName != '..' ) {
+			$pos = strpos($dir.'/', '/', 1);
+			$tmp = substr($dir, 0, $pos);
+			$pos = strrpos($tmp, '.d');
+			$timestamp = substr($tmp,$pos+2);
+			$result[] = array(
+					'id' => $entryName,
+					'timestamp' => $timestamp,
+					'mime' =>  $view->getMimeType($dir.'/'.$entryName),
+					'type' => $view->is_dir($dir.'/'.$entryName) ? 'dir' : 'file',
+					'location' => $dir,
+					);
+		}
+	}
+	closedir($fullpath);
+		
+} else {
+	$dirlisting = false;
+	$query = \OC_DB::prepare('SELECT id,location,timestamp,type,mime FROM *PREFIX*files_trash WHERE user=?');
+	$result = $query->execute(array($user))->fetchAll();
+}
+
+$files = array();
+foreach ($result as $r) {
+	$i = array();
+	$i['name'] = $r['id'];
+	$i['date'] = OCP\Util::formatDate($r['timestamp']);
+	$i['timestamp'] = $r['timestamp'];
+	$i['mimetype'] = $r['mime'];
+	$i['type'] = $r['type'];
+	if ($i['type'] == 'file') {
+		$fileinfo = pathinfo($r['id']);
+		$i['basename'] = $fileinfo['filename'];
+		$i['extension'] = isset($fileinfo['extension']) ? ('.'.$fileinfo['extension']) : '';
+	}
+	$i['directory'] = $r['location'];
+	if ($i['directory'] == '/') {
+		$i['directory'] = '';
+	}
+	$i['permissions'] = OCP\PERMISSION_READ;
+	$files[] = $i;
+}
+
+// Make breadcrumb
+$breadcrumb = array(array('dir' => '', 'name' => 'Trash'));
+$pathtohere = '';
+foreach (explode('/', $dir) as $i) {
+	if ($i != '') {
+		if ( preg_match('/^(.+)\.d[0-9]+$/', $i, $match) ) {
+			$name = $match[1];
+		} else {
+			$name = $i;
+		}
+		$pathtohere .= '/' . $i;
+		$breadcrumb[] = array('dir' => $pathtohere, 'name' => $name);
+	}
+}
+
+$breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', '');
+$breadcrumbNav->assign('breadcrumb', $breadcrumb, false);
+$breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php') . '?dir=', false);
+
+$list = new OCP\Template('files_trashbin', 'part.list', '');
+$list->assign('files', $files, false);
+$list->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php'). '?dir='.$dir, false);
+$list->assign('downloadURL', OCP\Util::linkTo('files_trashbin', 'download.php') . '?file='.$dir, false);
+$list->assign('disableSharing', true);
+$list->assign('dirlisting', $dirlisting);
+$list->assign('disableDownloadActions', true);
+$tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage(), false);
+$tmpl->assign('fileList', $list->fetchPage(), false);
+$tmpl->assign('files', $files);
+$tmpl->assign('dir', OC_Filesystem::normalizePath($view->getAbsolutePath()));
+
+$tmpl->printPage();
diff --git a/apps/files_trashbin/js/disableDefaultActions.js b/apps/files_trashbin/js/disableDefaultActions.js
new file mode 100644
index 0000000000000000000000000000000000000000..56b95407dd34cb105f90f8f00776dfffd5b185f5
Binary files /dev/null and b/apps/files_trashbin/js/disableDefaultActions.js differ
diff --git a/apps/files_trashbin/js/trash.js b/apps/files_trashbin/js/trash.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ad0ab04fb9ae653982e3c26765b00e7c4998d3a
Binary files /dev/null and b/apps/files_trashbin/js/trash.js differ
diff --git a/apps/files_trashbin/lib/hooks.php b/apps/files_trashbin/lib/hooks.php
new file mode 100644
index 0000000000000000000000000000000000000000..d3bee105b510ca2974d109e57362d4924a01d733
--- /dev/null
+++ b/apps/files_trashbin/lib/hooks.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * ownCloud - trash bin
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2013 Bjoern Schiessle schiessle@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * This class contains all hooks.
+ */
+
+namespace OCA_Trash;
+
+class Hooks {
+
+	/**
+	 * @brief Copy files to trash bin
+	 * @param array
+	 *
+	 * This function is connected to the delete signal of OC_Filesystem
+	 * to copy the file to the trash bin
+	 */
+	public static function remove_hook($params) {
+		
+		if ( \OCP\App::isEnabled('files_trashbin') ) {
+			$path = $params['path'];
+			Trashbin::move2trash($path);
+		}
+	}
+}
diff --git a/apps/files_trashbin/lib/trash.php b/apps/files_trashbin/lib/trash.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7eff3d44e0bdf1539e2b6f8515242d2b328427e
--- /dev/null
+++ b/apps/files_trashbin/lib/trash.php
@@ -0,0 +1,264 @@
+<?php
+/**
+ * ownCloud - trash bin
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2013 Bjoern Schiessle schiessle@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA_Trash;
+
+class Trashbin {
+	
+	const DEFAULT_RETENTION_OBLIGATION=180; // how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
+	/**
+	 * move file to the trash bin
+	 * 
+	 * @param $file_path path to the deleted file/directory relative to the files root directory
+	 */
+	public static function move2trash($file_path) {
+		$user = \OCP\User::getUser();
+		$view = new \OC_FilesystemView('/'. $user);
+		if (!$view->is_dir('files_trashbin')) {
+			$view->mkdir('files_trashbin');
+			$view->mkdir("versions_trashbin");
+		}
+
+		$path_parts = pathinfo($file_path);
+
+		$deleted = $path_parts['basename'];
+		$location = $path_parts['dirname'];
+		$timestamp = time();
+		$mime = $view->getMimeType('files'.$file_path);
+
+		if ( $view->is_dir('files'.$file_path) ) {
+			$type = 'dir';
+		} else {
+			$type = 'file';
+		}
+
+		self::copy_recursive($file_path, 'files_trashbin/'.$deleted.'.d'.$timestamp, $view);
+		
+		if ( $view->file_exists('files_trashbin/'.$deleted.'.d'.$timestamp) ) {
+			$query = \OC_DB::prepare("INSERT INTO *PREFIX*files_trash (id,timestamp,location,type,mime,user) VALUES (?,?,?,?,?,?)");
+			$result = $query->execute(array($deleted, $timestamp, $location, $type, $mime, $user));
+			if ( !$result ) { // if file couldn't be added to the database than also don't store it in the trash bin.
+				$view->deleteAll('files_trashbin/'.$deleted.'.d'.$timestamp);
+				\OC_Log::write('files_trashbin', 'trash bin database couldn\'t be updated', \OC_log::ERROR);
+				return;
+			}
+	
+			if ( \OCP\App::isEnabled('files_versions') ) {
+				if ( $view->is_dir('files_versions'.$file_path) ) {
+					$view->rename('files_versions'.$file_path, 'versions_trashbin/'. $deleted.'.d'.$timestamp);
+				} else if ( $versions = \OCA_Versions\Storage::getVersions($file_path) ) {
+					foreach ($versions as $v) {
+						$view->rename('files_versions'.$v['path'].'.v'.$v['version'], 'versions_trashbin/'. $deleted.'.v'.$v['version'].'.d'.$timestamp);
+					}
+				}
+			}
+		} else {
+			\OC_Log::write('files_trashbin', 'Couldn\'t move '.$file_path.' to the trash bin' , \OC_log::ERROR);
+		}
+		
+		self::expire();
+	}
+	
+	
+	/**
+	 * restore files from trash bin
+	 * @param $file path to the deleted file
+	 * @param $filename name of the file
+	 * @param $timestamp time when the file was deleted
+	 */
+	public static function restore($file, $filename, $timestamp) {
+
+		$user = \OCP\User::getUser();
+		$view = new \OC_FilesystemView('/'.$user);
+		
+		if ( $timestamp ) {
+			$query = \OC_DB::prepare('SELECT location,type FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
+			$result = $query->execute(array($user,$filename,$timestamp))->fetchAll();
+			if ( count($result) != 1 ) {
+				\OC_Log::write('files_trashbin', 'trash bin database inconsistent!', \OC_Log::ERROR);
+				return false;
+			}
+			
+			// if location no longer exists, restore file in the root directory
+			$location = $result[0]['location'];
+			if ( $result[0]['location'] != '/' && 
+				 (!$view->is_dir('files'.$result[0]['location']) ||
+				 !$view->isUpdatable('files'.$result[0]['location'])) ) {
+				$location = '';
+			}
+		} else {
+			$path_parts = pathinfo($filename);
+			$result[] = array(
+					'location' => $path_parts['dirname'],
+					'type' => $view->is_dir('/files_trashbin/'.$file) ? 'dir' : 'files',
+					);
+			$location = '';
+		}
+		
+		$source = \OC_Filesystem::normalizePath('files_trashbin/'.$file);
+		$target = \OC_Filesystem::normalizePath('files/'.$location.'/'.$filename);
+		
+		// we need a  extension in case a file/dir with the same name already exists
+		$ext = self::getUniqueExtension($location, $filename, $view);
+		$mtime = $view->filemtime($source);
+		if( $view->rename($source, $target.$ext) ) {
+			$view->touch($target.$ext, $mtime);
+			// if versioning app is enabled, copy versions from the trash bin back to the original location
+			if ( \OCP\App::isEnabled('files_versions') ) {
+				if ( $result[0]['type'] == 'dir' ) {
+					$view->rename(\OC_Filesystem::normalizePath('versions_trashbin/'. $file), \OC_Filesystem::normalizePath('files_versions/'.$location.'/'.$filename.$ext));
+				} else if ( $versions = self::getVersionsFromTrash($file, $timestamp) ) {
+					foreach ($versions as $v) {
+						if ($timestamp ) {
+							$view->rename('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
+						} else {
+							$view->rename('versions_trashbin/'.$file.'.v'.$v, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
+						}
+					}
+				}
+			}
+
+			if ( $timestamp ) {
+				$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
+				$query->execute(array($user,$filename,$timestamp));
+			}
+
+			return true;
+		} else {
+			\OC_Log::write('files_trashbin', 'Couldn\'t restore file from trash bin, '.$filename , \OC_log::ERROR);
+		}
+
+		return false;
+	}
+	
+	/**
+	 * clean up the trash bin
+	 */
+	private static function expire() {
+		
+		$view = new \OC_FilesystemView('/'.\OCP\User::getUser());
+		$user = \OCP\User::getUser();
+		
+		$query = \OC_DB::prepare('SELECT location,type,id,timestamp FROM *PREFIX*files_trash WHERE user=?');
+		$result = $query->execute(array($user))->fetchAll();
+		
+		$retention_obligation = \OC_Config::getValue('trashbin_retention_obligation', self::DEFAULT_RETENTION_OBLIGATION);
+		
+		$limit = time() - ($retention_obligation * 86400);
+
+		foreach ( $result as $r ) {
+			$timestamp = $r['timestamp'];
+			$filename = $r['id'];
+			if ( $r['timestamp'] < $limit ) {
+				$view->unlink('files_trashbin/'.$filename.'.d'.$timestamp);
+				if ($r['type'] == 'dir') {
+					$view->unlink('versions_trashbin/'.$filename.'.d'.$timestamp);
+				} else if ( $versions = self::getVersionsFromTrash($filename, $timestamp) ) {
+					foreach ($versions as $v) {
+						$view->unlink('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp);
+					}			
+				}
+			}
+		}
+		
+		$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND timestamp<?');
+		$query->execute(array($user,$limit));
+	}
+	
+	/**
+	 * recursive copy to copy a whole directory
+	 * 
+	 * @param $source source path, relative to the users files directory
+	 * @param $destination destination path relative to the users root directoy
+	 * @param $view file view for the users root directory
+	 */
+	private static function copy_recursive( $source, $destination, $view ) {
+		if ( $view->is_dir( 'files'.$source ) ) {
+			$view->mkdir( $destination );
+			$view->touch($destination,  $view->filemtime('files'.$source));
+			foreach ( \OC_Files::getDirectoryContent($source) as $i ) {
+				$pathDir = $source.'/'.$i['name'];
+				if ( $view->is_dir('files'.$pathDir) ) {
+					self::copy_recursive($pathDir, $destination.'/'.$i['name'], $view);
+				} else {
+					$view->copy( 'files'.$pathDir, $destination . '/' . $i['name'] );
+					$view->touch($destination . '/' . $i['name'], $view->filemtime('files'.$pathDir));
+				}
+			}
+		} else {
+			$view->copy( 'files'.$source, $destination );
+			$view->touch($destination, $view->filemtime('files'.$source));
+		}
+	}
+	
+	/**
+	 * find all versions which belong to the file we want to restore
+	 * @param $filename name of the file which should be restored
+	 * @param $timestamp timestamp when the file was deleted
+	 */
+	private static function getVersionsFromTrash($filename, $timestamp) {
+		$view = new \OC_FilesystemView('/'.\OCP\User::getUser().'/versions_trashbin');
+		$versionsName = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath($filename);
+		$versions = array();
+		
+		if ($timestamp ) {
+		// fetch for old versions
+			$matches = glob( $versionsName.'.v*.d'.$timestamp );
+			$offset = -strlen($timestamp)-2;
+		} else {
+			$matches = glob( $versionsName.'.v*' );
+		}
+		
+		foreach( $matches as $ma ) {
+			if ( $timestamp ) {
+				$parts = explode( '.v', substr($ma, 0, $offset) );
+				$versions[] = ( end( $parts ) );
+			} else {
+				$parts = explode( '.v', $ma );
+				$versions[] = ( end( $parts ) );
+			}
+		}
+		return $versions;
+	}
+	
+	/**
+	 * find unique extension for restored file if a file with the same name already exists
+	 * @param $location where the file should be restored
+	 * @param $filename name of the file
+	 * @param $view filesystem view relative to users root directory
+	 * @return string with unique extension
+	 */
+	private static function getUniqueExtension($location, $filename, $view) {
+		$ext = '';
+		if ( $view->file_exists('files'.$location.'/'.$filename) ) {
+			$tmpext = '.restored';
+			$ext = $tmpext;
+			$i = 1;
+			while ( $view->file_exists('files'.$location.'/'.$filename.$ext) ) {
+				$ext = $tmpext.$i;
+				$i++;
+			}
+		}
+		return $ext;
+	}
+
+}
diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php
new file mode 100644
index 0000000000000000000000000000000000000000..c3e51b4becdfe4d5aad5e30a61c508453416000f
--- /dev/null
+++ b/apps/files_trashbin/templates/index.php
@@ -0,0 +1,34 @@
+<!--[if IE 8]><style>input[type="checkbox"]{padding:0;}table td{position:static !important;}</style><![endif]-->
+<div id="controls">
+	<?php echo($_['breadcrumb']); ?>
+		<div id="file_action_panel"></div>
+</div>
+<div id='notification'></div>
+
+<?php if (isset($_['files']) && count($_['files'])==0):?>
+	<div id="emptyfolder"><?php echo $l->t('Nothing in here. Your trash bin is empty!')?></div>
+<?php endif; ?>
+
+<table>
+	<thead>
+		<tr>
+			<th id='headerName'>
+				<input type="checkbox" id="select_all" />
+				<span class='name'><?php echo $l->t( 'Name' ); ?></span>
+				<span class='selectedActions'>
+						<a href="" class="undelete">
+							<img class="svg" alt="<?php echo $l->t( 'Restore' ); ?>"
+								 src="<?php echo OCP\image_path("core", "actions/undelete.png"); ?>" />
+							<?php echo $l->t('Restore')?>
+						</a>
+				</span>
+			</th>
+			<th id="headerDate">
+				<span id="modified"><?php echo $l->t( 'Deleted' ); ?></span>
+			</th>
+		</tr>
+	</thead>
+	<tbody id="fileList">
+		<?php echo($_['fileList']); ?>
+	</tbody>
+</table>
diff --git a/apps/files_trashbin/templates/part.list.php b/apps/files_trashbin/templates/part.list.php
new file mode 100644
index 0000000000000000000000000000000000000000..fe8a71f44e6514c3ee04af38a310fca3c3e97d34
--- /dev/null
+++ b/apps/files_trashbin/templates/part.list.php
@@ -0,0 +1,76 @@
+<input type="hidden" id="disableSharing" data-status="<?php echo $_['disableSharing']; ?>">
+<?php foreach($_['files'] as $file):
+	$simple_file_size = OCP\simple_file_size($file['size']);
+	// the bigger the file, the darker the shade of grey; megabytes*2
+	$simple_size_color = intval(200-$file['size']/(1024*1024)*2);
+	if($simple_size_color<0) $simple_size_color = 0;
+	$relative_deleted_date = OCP\relative_modified_date($file['timestamp']);
+	// the older the file, the brighter the shade of grey; days*14
+	$relative_date_color = round((time()-$file['mtime'])/60/60/24*14);
+	if($relative_date_color>200) $relative_date_color = 200;
+	$name = str_replace('+', '%20', urlencode($file['name']));
+	$name = str_replace('%2F', '/', $name);
+	$directory = str_replace('+', '%20', urlencode($file['directory']));
+	$directory = str_replace('%2F', '/', $directory); ?>
+	<tr data-filename="<?php echo $file['name'];?>"
+		data-type="<?php echo ($file['type'] == 'dir')?'dir':'file'?>"
+		data-mime="<?php echo $file['mimetype']?>"
+		data-permissions='<?php echo $file['permissions']; ?>'
+		<?php if ( $_['dirlisting'] ): ?>
+		id="<?php echo $file['directory'].'/'.$file['name'];?>"
+		data-file="<?php echo $file['directory'].'/'.$file['name'];?>"
+		data-timestamp=''
+		data-dirlisting=1
+		<?php  else: ?>
+		id="<?php echo $file['name'].'.d'.$file['timestamp'];?>"
+		data-file="<?php echo $file['name'].'.d'.$file['timestamp'];?>"
+		data-timestamp='<?php echo $file['timestamp'];?>'
+		data-dirlisting=0
+		<?php endif; ?>>
+		<td class="filename svg"
+		<?php if($file['type'] == 'dir'): ?>
+			style="background-image:url(<?php echo OCP\mimetype_icon('dir'); ?>)"
+		<?php else: ?>
+			style="background-image:url(<?php echo OCP\mimetype_icon($file['mimetype']); ?>)"
+		<?php endif; ?>
+			>
+		<?php if(!isset($_['readonly']) || !$_['readonly']): ?><input type="checkbox" /><?php endif; ?>
+		<?php if($file['type'] == 'dir'): ?>
+			<?php if( $_['dirlisting'] ): ?>
+				<a class="name" href="<?php echo $_['baseURL'].'/'.$name; ?>" title="">
+			<?php else: ?>
+				<a class="name" href="<?php echo $_['baseURL'].'/'.$name.'.d'.$file['timestamp']; ?>" title="">
+			<?php endif; ?>
+		<?php else: ?>
+			<?php if( $_['dirlisting'] ): ?>
+				<a class="name" href="<?php echo $_['downloadURL'].'/'.$name; ?>" title="">
+			<?php else: ?>
+				<a class="name" href="<?php echo $_['downloadURL'].'/'.$name.'.d'.$file['timestamp'];?>" title="">
+			<?php endif; ?>
+		<?php endif; ?>
+			<span class="nametext">
+				<?php if($file['type'] == 'dir'):?>
+					<?php echo htmlspecialchars($file['name']);?>
+				<?php else:?>
+					<?php echo htmlspecialchars($file['basename']);?><span
+						class='extension'><?php echo $file['extension'];?></span>
+				<?php endif;?>
+			</span>
+			<?php if($file['type'] == 'dir'):?>
+				<span class="uploadtext" currentUploads="0">
+				</span>
+			<?php endif;?>
+			</a>
+		</td>
+		<td class="date">
+			<span class="modified"
+				  title="<?php echo $file['date']; ?>"
+				  style="color:rgb(<?php echo $relative_date_color.','
+												.$relative_date_color.','
+												.$relative_date_color ?>)">
+				<?php echo $relative_deleted_date; ?>
+			</span>
+		</td>
+	</tr>
+<?php endforeach;
+ 
\ No newline at end of file
diff --git a/apps/files_versions/appinfo/app.php b/apps/files_versions/appinfo/app.php
index afc0a67edbac4024d373b27dc6f915052e19e9fe..edd0a2f70226a5c5cfb1c0a05362342830d2f2be 100644
--- a/apps/files_versions/appinfo/app.php
+++ b/apps/files_versions/appinfo/app.php
@@ -12,5 +12,5 @@ OCP\Util::addscript('files_versions', 'versions');
 // Listen to write signals
 OCP\Util::connectHook('OC_Filesystem', 'write', "OCA_Versions\Hooks", "write_hook");
 // Listen to delete and rename signals
-OCP\Util::connectHook('OC_Filesystem', 'delete', "OCA_Versions\Hooks", "remove_hook");
+OCP\Util::connectHook('OC_Filesystem', 'post-delete', "OCA_Versions\Hooks", "remove_hook");
 OCP\Util::connectHook('OC_Filesystem', 'rename', "OCA_Versions\Hooks", "rename_hook");
\ No newline at end of file
diff --git a/config/config.sample.php b/config/config.sample.php
index 78d513c7f23d044f53de2245fafaab3f2cb7992a..05663a09a46b4d22fbca6289b9165a07a43514d1 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -102,6 +102,9 @@ $CONFIG = array(
 /* Password to use for sendmail mail, depends on mail_smtpauth if this is used */
 "mail_smtppassword" => "",
 
+/* How long should ownCloud keep deleted files in the trash bin, default value:  180 days */
+'trashbin_retention_obligation' => 180,
+
 /* Check 3rdparty apps for malicious code fragments */
 "appcodechecker" => "",
 
diff --git a/core/img/actions/undelete.png b/core/img/actions/undelete.png
new file mode 100644
index 0000000000000000000000000000000000000000..d712527ef617dca921bcf75b917a1f728bc2102c
Binary files /dev/null and b/core/img/actions/undelete.png differ