summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--apps/files_sharing/ajax/share.php16
-rw-r--r--apps/files_sharing/ajax/unshare.php11
-rw-r--r--apps/files_sharing/ajax/userautocomplete.php29
-rw-r--r--apps/files_sharing/appinfo/app.php13
-rw-r--r--apps/files_sharing/appinfo/database.xml42
-rw-r--r--apps/files_sharing/appinfo/info.xml10
-rw-r--r--apps/files_sharing/js/list.js54
-rw-r--r--apps/files_sharing/js/share.js95
-rw-r--r--apps/files_sharing/lib_share.php314
-rw-r--r--apps/files_sharing/list.php40
-rw-r--r--apps/files_sharing/sharedstorage.php510
-rw-r--r--apps/files_sharing/templates/list.php30
-rw-r--r--lib/base.php5
-rw-r--r--lib/filesystem.php5
15 files changed, 1173 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 94de5aec803..e62a5abd965 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,4 @@ RCS/*
# Lokalize
*lokalize*
-.project
+.project \ No newline at end of file
diff --git a/apps/files_sharing/ajax/share.php b/apps/files_sharing/ajax/share.php
new file mode 100644
index 00000000000..b2c3a477958
--- /dev/null
+++ b/apps/files_sharing/ajax/share.php
@@ -0,0 +1,16 @@
+<?php
+$RUNTIME_NOAPPS = true;
+
+require_once('../../../lib/base.php');
+require_once('../lib_share.php');
+
+$sources = $_GET['sources'];
+$uid_shared_with = $_GET['uid_shared_with'];
+$permissions = $_GET['permissions'];
+foreach ($sources as $source) {
+ foreach ($uid_shared_with as $uid) {
+ new OC_SHARE($source, $uid, $permissions);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/apps/files_sharing/ajax/unshare.php b/apps/files_sharing/ajax/unshare.php
new file mode 100644
index 00000000000..4d83d332257
--- /dev/null
+++ b/apps/files_sharing/ajax/unshare.php
@@ -0,0 +1,11 @@
+<?php
+$RUNTIME_NOAPPS = true;
+
+require_once('../../../lib/base.php');
+require_once('../lib_share.php');
+
+$source = $_GET['source'];
+$uid_shared_with = $_GET['uid_shared_with'];
+OC_SHARE::unshare($source, $uid_shared_with);
+
+?> \ No newline at end of file
diff --git a/apps/files_sharing/ajax/userautocomplete.php b/apps/files_sharing/ajax/userautocomplete.php
new file mode 100644
index 00000000000..6e1469ae348
--- /dev/null
+++ b/apps/files_sharing/ajax/userautocomplete.php
@@ -0,0 +1,29 @@
+<?php
+$RUNTIME_NOAPPS = true;
+
+require_once('../../../lib/base.php');
+
+if (!OC_USER::isLoggedIn()) {
+ echo json_encode(array("status" => "error", "data" => array("message" => "Authentication error")));
+ exit();
+}
+$query = $_GET['term'];
+$length = strlen($query);
+$query = strtolower($query);
+$users = array();
+$ocusers = OC_USER::getUsers();
+$self = OC_USER::getUser();
+$groups = OC_GROUP::getUserGroups($self);
+foreach ($ocusers as $user) {
+ if ($user != $self && substr(strtolower($user), 0, $length) == $query) {
+ $users[] = (object)array('id' => $user, 'label' => $user, 'name' => $user);
+ }
+}
+foreach ($groups as $group) {
+ if (substr(strtolower($group), 0, $length) == $query) {
+ $users[] = (object)array('id' => $group, 'label' => $group, 'name' => $group);
+ }
+}
+echo json_encode($users);
+
+?>
diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php
new file mode 100644
index 00000000000..879bd1ea0eb
--- /dev/null
+++ b/apps/files_sharing/appinfo/app.php
@@ -0,0 +1,13 @@
+<?php
+
+require_once('apps/files_sharing/lib_share.php');
+
+OC_UTIL::addScript("files_sharing", "share");
+
+OC_APP::addNavigationEntry( array( "id" => "files_sharing_list",
+ "order" => 10,
+ "href" => OC_HELPER::linkTo( "files_sharing", "list.php" ),
+ "name" => "Share",
+ "icon" => OC_HELPER::imagePath( "files_sharing", "share.png" )));
+
+?> \ No newline at end of file
diff --git a/apps/files_sharing/appinfo/database.xml b/apps/files_sharing/appinfo/database.xml
new file mode 100644
index 00000000000..7ddaca21aec
--- /dev/null
+++ b/apps/files_sharing/appinfo/database.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+ <name>*dbname*</name>
+ <create>true</create>
+ <overwrite>false</overwrite>
+ <charset>latin1</charset>
+ <table>
+ <name>*dbprefix*sharing</name>
+ <declaration>
+ <field>
+ <name>uid_owner</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+ <field>
+ <name>uid_shared_with</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>64</length>
+ </field>
+ <field>
+ <name>source</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>128</length>
+ </field>
+ <field>
+ <name>target</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>128</length>
+ </field>
+ <field>
+ <name>is_writeable</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>1</length>
+ </field>
+ </declaration>
+ </table>
+</database>
diff --git a/apps/files_sharing/appinfo/info.xml b/apps/files_sharing/appinfo/info.xml
new file mode 100644
index 00000000000..2fbb3300f69
--- /dev/null
+++ b/apps/files_sharing/appinfo/info.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<info>
+ <id>files_sharing</id>
+ <name>Share Files</name>
+ <description>File sharing between users</description>
+ <version>0.1</version>
+ <licence>AGPL</licence>
+ <author>Michael Gapczynski</author>
+ <require>2</require>
+</info> \ No newline at end of file
diff --git a/apps/files_sharing/js/list.js b/apps/files_sharing/js/list.js
new file mode 100644
index 00000000000..41eabd1f4af
--- /dev/null
+++ b/apps/files_sharing/js/list.js
@@ -0,0 +1,54 @@
+$(document).ready(function() {
+ $( "#source" ).autocomplete({
+ source: "../../files/ajax/autocomplete.php",
+ minLength: 1
+ });
+ $( "#uid_shared_with" ).autocomplete({
+ source: "ajax/userautocomplete.php",
+ minLength: 1
+ });
+ $("button.delete").live('click', function( event ) {
+ event.preventDefault();
+// var row=$(this);
+ var source=$(this).attr('data-source');
+ var uid_shared_with=$(this).attr('data-uid_shared_with');
+ var data='source='+encodeURIComponent(source)+'&uid_shared_with='+encodeURIComponent(uid_shared_with);
+ $.ajax({
+ type: 'GET',
+ url: 'ajax/unshare.php',
+ cache: false,
+ data: data
+// success: function(){
+// row.remove();
+// }
+ });
+ });
+ $('#share_item').submit(function( event ){
+ event.preventDefault();
+ var source=$('#source').val();
+ var uid_shared_with=$('#uid_shared_with').val();
+ var permissions=$('#permissions').val()||0;
+ var data='source='+source+'&uid_shared_with='+uid_shared_with+'&permissions='+permissions;
+ $.ajax({
+ type: 'GET',
+ url: 'ajax/share.php',
+ cache: false,
+ data: data,
+// success: function(token){
+// if(token){
+// var html="<tr class='link' id='"+token+"'>";
+// html+="<td class='path'>"+path+"</td>";
+// var expire=($('#expire').val())?$('#expire').val():'Never'
+// html+="<td class='expire'>"+expire+"</td>"
+// html+="<td class='link'><a href='get.php?token="+token+"'>"+$('#baseUrl').val()+"?token="+token+"</a></td>"
+// html+="<td><button class='delete fancybutton' data-token='"+token+"'>Delete</button></td>"
+// html+="</tr>"
+// $(html).insertBefore($('#newlink_row'));
+// $('#expire').val('');
+// $('#expire_time').val('');
+// $('#path').val('');
+// }
+// }
+ });
+ });
+}); \ No newline at end of file
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
new file mode 100644
index 00000000000..32926c6811e
--- /dev/null
+++ b/apps/files_sharing/js/share.js
@@ -0,0 +1,95 @@
+$(document).ready(function() {
+ $('.share').click(function(event) {
+ event.preventDefault();
+ var html = "<div id='dialog' title='Share "+getSelectedFiles('name')+"' align='center'>";
+ html += "<label><input type='radio' name='share_type' value='private' checked='checked' /> Private</label>";
+ html += "<label><input type='radio' name='share_type' value='public' /> Public</label>";
+ html += "<br />";
+ html += "<div id='private'>";
+ html += "<label>Share with <input placeholder='User or Group' class='uid_shared_with' /></label>";
+ html += "<button id='hey' class='add-uid_shared_with fancybutton'>+</button>";
+ html += "<br />";
+ html += "<a id='toggle-private-advanced'>Advanced</a>";
+ html += "<br />";
+ html += "<div id='private-advanced' style='display: none; text-align: left'>";
+ html += "<label><input type='checkbox' name='share_permissions' value='read' checked='checked' disabled='disable' /> Read</label><br />";
+ html += "<label><input type='checkbox' name='share_permissions' value='write' /> Write</label><br />";
+ html += "<label><input type='checkbox' name='share_permissions' value='rename' /> Rename</label><br />";
+ html += "<label><input type='checkbox' name='share_permissions' value='delete' /> Delete</label><br />";
+ html += "</div>";
+ html += "</div>";
+ html += "<div id='public' style='display: none'>";
+ html += "TODO: Construct a public link";
+ html += "<input placeholder='Expires' id='expire' />";
+ html += "</div>";
+ html += "<br />";
+ html += "<button class='submit fancybutton'>Share</button>";
+ html += "<div>";
+ $(html).dialog({
+ close: function(event, ui) {
+ $(this).remove();
+ }
+ });
+ });
+ $("input[name=share_type]").live('change', function() {
+ $('#private').toggle();
+ $('#public').toggle();
+ });
+ $('.uid_shared_with').live('keyup', function() {
+ $(this).autocomplete({
+ source: "../apps/files_sharing/ajax/userautocomplete.php",
+ minLength: 1
+ });
+ });
+ $('button.add-uid_shared_with').live('click', function(event) {
+ event.preventDefault();
+ // TODO Make sure previous textbox has a valid user or group name
+ var html = "<br />";
+ html += "<label>Share with <input placeholder='User or Group' class='uid_shared_with' /></label>";
+ html += "<button class='add-uid_shared_with fancybutton'>+</button>";
+ $(html).insertAfter('.add-uid_shared_with');
+ $(this).html("&nbsp-&nbsp&nbsp");
+ $(this).removeClass("add-uid_shared_with fancybutton");
+ $(this).addClass("remove-uid_shared_with fancybutton");
+ });
+ $('button.remove-uid_shared_with').live('click', function(event) {
+ event.preventDefault();
+ alert("remove");
+ // TODO Remove corresponding row
+ });
+ $('#toggle-private-advanced').live('click', function(event) {
+ event.preventDefault();
+ $('#private-advanced').toggle();
+ });
+ $('#expire').datepicker({
+ dateFormat:'MM d, yy',
+ altField: "#expire_time",
+ altFormat: "yy-mm-dd"
+ });
+ $('button.submit').live('click', function(event) {
+ event.preventDefault();
+ if ($("input[name=share_type]:checked").val() == 'public') {
+ // TODO Construct public link
+ } else {
+ // TODO Check all inputs are valid
+ var sources = "";
+ var files = getSelectedFiles('name');
+ var length = files.length;
+ for (var i = 0; i < length; i++) {
+ sources += "&sources[]=" + $('#dir').val() + "/" + files[i];
+ }
+ var uid_shared_with = $('.uid_shared_with').val();
+ var permissions = 0;
+ var data = sources+'&uid_shared_with[]='+uid_shared_with+'&permissions='+permissions;
+ $.ajax({
+ type: 'GET',
+ url: '../apps/files_sharing/ajax/share.php',
+ cache: false,
+ data: data,
+ success: function() {
+ $('#dialog').dialog('close');
+ }
+ });
+ }
+ });
+}); \ No newline at end of file
diff --git a/apps/files_sharing/lib_share.php b/apps/files_sharing/lib_share.php
new file mode 100644
index 00000000000..b096a956e7d
--- /dev/null
+++ b/apps/files_sharing/lib_share.php
@@ -0,0 +1,314 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Michael Gapczynski
+ * @copyright 2011 Michael Gapczynski GapczynskiM@gmail.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/>.
+ *
+ */
+
+OC_HOOK::connect("OC_FILESYSTEM","post_delete", "OC_SHARE", "deleteItem");
+OC_HOOK::connect("OC_FILESYSTEM","post_rename", "OC_SHARE", "renameItem");
+
+/**
+ * This class manages shared items within the database.
+ */
+class OC_SHARE {
+
+ /**
+ * TODO notify user a file is being shared with them?
+ * Share an item, adds an entry into the database
+ * @param string $item
+ * @param user item shared with $uid_shared_with
+ */
+ public function __construct($source, $uid_shared_with, $permissions, $public = false) {
+ if ($source && OC_FILESYSTEM::file_exists($source) && OC_FILESYSTEM::is_readable($source)) {
+ $source = "/".OC_USER::getUser()."/files".$source;
+ $uid_owner = OC_USER::getUser();
+ if ($public) {
+ // TODO create token for public file
+ $token = sha1("$uid_owner-$item");
+ } else {
+ $query = OC_DB::prepare("INSERT INTO *PREFIX*sharing VALUES(?,?,?,?,?)");
+ $target = "/".$uid_shared_with."/files/Share/".basename($source);
+ $check = OC_DB::prepare("SELECT target FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with = ?");
+ $result = $check->execute(array($target, $uid_shared_with))->fetchAll();
+ // Check if target already exists for the user, if it does append a number to the name
+ if (count($result) > 0) {
+ if ($pos = strrpos($target, ".")) {
+ $name = substr($target, 0, $pos);
+ $ext = substr($target, $pos);
+ } else {
+ $name = $target;
+ $ext = "";
+ }
+ $counter = 1;
+ while (count($result) > 0) {
+ $newTarget = $name."_".$counter.$ext;
+ $result = $check->execute(array($newTarget, $uid_shared_with))->fetchAll();
+ $counter++;
+ }
+ $target = $newTarget;
+ }
+ $query->execute(array($uid_owner, $uid_shared_with, $source, $target, $permissions));
+ }
+ }
+ }
+
+ /**
+ * Remove any duplicate or trailing '/' from the path
+ * @return A clean path
+ */
+ private static function cleanPath($path) {
+ $path = rtrim($path, "/");
+ return preg_replace('{(/)\1+}', "/", $path);
+ }
+
+ /**
+ * Get the user and the user's groups and put them into an array
+ * @return An array to be used by the IN operator in a query for uid_shared_with
+ */
+ private static function getUserAndGroups() {
+ $self = OC_USER::getUser();
+ $groups = OC_GROUP::getUserGroups($self);
+ array_unshift($groups, $self);
+ return $groups;
+ }
+
+ /**
+ * Create a new entry in the database for a file inside a shared folder
+ *
+ * $oldTarget and $newTarget may be the same value. $oldTarget exists in case the file is being moved outside of the folder
+ *
+ * @param $oldTarget The current target location
+ * @param $newTarget The new target location
+ */
+ public static function pullOutOfFolder($oldTarget, $newTarget) {
+ $folders = self::getParentFolders($oldTarget);
+ $source = $folders['source'].substr($oldTarget, strlen($folders['target']));
+ $item = self::getItem($folders['target']);
+ $query = OC_DB::prepare("INSERT INTO *PREFIX*sharing VALUES(?,?,?,?,?)");
+ $query->execute(array($item[0]['uid_owner'], OC_USER::getUser(), $source, $newTarget, $item[0]['is_writeable']));
+ }
+
+ /**
+ * Get the item with the specified target location
+ * @param $target The target location of the item
+ * @return An array with the item
+ */
+ public static function getItem($target) {
+ $target = self::cleanPath($target);
+ $query = OC_DB::prepare("SELECT uid_owner, source, is_writeable FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with = ? LIMIT 1");
+ return $query->execute(array($target, OC_USER::getUser()))->fetchAll();
+ }
+
+ /**
+ * Get all items the current user is sharing
+ * @return An array with all items the user is sharing
+ */
+ public static function getMySharedItems() {
+ $query = OC_DB::prepare("SELECT uid_shared_with, source, is_writeable FROM *PREFIX*sharing WHERE uid_owner = ?");
+ return $query->execute(array(OC_USER::getUser()))->fetchAll();
+ }
+
+ /**
+ * Get the items within a shared folder that have their own entry for the purpose of name, location, or permissions that differ from the folder itself
+ *
+ * Works for both target and source folders. Can be used for getting all items shared with you e.g. pass '/MTGap/files'
+ *
+ * @param $folder The folder of the items to look for
+ * @return An array with all items in the database that are in the folder
+ */
+ public static function getItemsInFolder($folder) {
+ $folder = self::cleanPath($folder);
+ // Append '/' in order to filter out the folder itself if not already there
+ if (substr($folder, -1) !== "/") {
+ $folder .= "/";
+ }
+ $length = strlen($folder);
+ $userAndGroups = self::getUserAndGroups();
+ $query = OC_DB::prepare("SELECT uid_owner, source, target FROM *PREFIX*sharing WHERE SUBSTR(source, 1, ?) = ? OR SUBSTR(target, 1, ?) = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).")");
+ return $query->execute(array_merge(array($length, $folder, $length, $folder), $userAndGroups))->fetchAll();
+ }
+
+ /**
+ * Get the source and target parent folders of the specified target location
+ * @param $target The target location of the item
+ * @return An array with the keys 'source' and 'target' with the values of the source and target parent folders
+ */
+ public static function getParentFolders($target) {
+ $target = self::cleanPath($target);
+ $userAndGroups = self::getUserAndGroups();
+ $query = OC_DB::prepare("SELECT source FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).") LIMIT 1");
+ // Prevent searching for user directory e.g. '/MTGap/files'
+ $userDirectory = substr($target, 0, strpos($target, "files") + 5);
+ while ($target != "" && $target != "/" && $target != "." && $target != $userDirectory) {
+ // Check if the parent directory of this target location is shared
+ $target = dirname($target);
+ $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll();
+ if (count($result) > 0) {
+ break;
+ }
+ }
+ if (count($result) > 0) {
+ // Return both the source folder and the target folder
+ return array("source" => $result[0]['source'], "target" => $target);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the source location of the item at the specified target location
+ * @param $target The target location of the item
+ * @return Source location or false if target location is not valid
+ */
+ public static function getSource($target) {
+ $target = self::cleanPath($target);
+ $userAndGroups = self::getUserAndGroups();
+ $query = OC_DB::prepare("SELECT source FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).") LIMIT 1");
+ $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll();
+ if (count($result) > 0) {
+ return $result[0]['source'];
+ } else {
+ $folders = self::getParentFolders($target);
+ if ($folders == false) {
+ return false;
+ } else {
+ return $folders['source'].substr($target, strlen($folders['target']));
+ }
+ }
+ }
+
+ /**
+ * Check if the user has write permission for the item at the specified target location
+ * @param $target The target location of the item
+ * @return True if the user has write permission or false if read only
+ */
+ public static function isWriteable($target) {
+ $target = self::cleanPath($target);
+ $userAndGroups = self::getUserAndGroups();
+ $query = OC_DB::prepare("SELECT is_writeable FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).") LIMIT 1");
+ $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll();
+ if (count($result) > 0) {
+ return $result[0]['is_writeable'];
+ } else {
+ // Check if the folder is writeable
+ $folders = OC_SHARE::getParentFolders($target);
+ $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll();
+ if (count($result) > 0) {
+ return $result[0]['is_writeable'];
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Set the source location to a new value
+ * @param $oldSource The current source location
+ * @param $newTarget The new source location
+ */
+ public static function setSource($oldSource, $newSource) {
+ $oldSource = self::cleanPath($oldSource);
+ $newSource = self::cleanPath($newSource);
+ $query = OC_DB::prepare("UPDATE *PREFIX*sharing SET source = REPLACE(source, ?, ?) WHERE uid_owner = ?");
+ $query->execute(array($oldSource, $newSource, OC_USER::getUser()));
+ }
+
+ /**
+ * Set the target location to a new value
+ *
+ * You must use the pullOutOfFolder() function to change the target location of a file inside a shared folder if the target location differs from the folder
+ *
+ * @param $oldTarget The current target location
+ * @param $newTarget The new target location
+ */
+ public static function setTarget($oldTarget, $newTarget) {
+ $oldTarget = self::cleanPath($oldTarget);
+ $newTarget = self::cleanPath($newTarget);
+ $query = OC_DB::prepare("UPDATE *PREFIX*sharing SET target = REPLACE(target, ?, ?) WHERE uid_shared_with = ?");
+ $query->execute(array($oldTarget, $newTarget, OC_USER::getUser()));
+ }
+
+ /**
+ * Change write permission for the specified item and user
+ *
+ * You must construct a new shared item to change the write permission of a file inside a shared folder if the write permission differs from the folder
+ *
+ * @param $source The source location of the item
+ * @param $uid_shared_with Array of users to change the write permission for
+ * @param $is_writeable True if the user has write permission or false if read only
+ */
+ public static function setIsWriteable($source, $uid_shared_with, $is_writeable) {
+ $source = self::cleanPath($source);
+ $query = OC_DB::prepare("UPDATE *PREFIX*sharing SET is_writeable = ? WHERE SUBSTR(source, 1, ?) = ? AND uid_shared_with = ? AND uid_owner = ?");
+ $query->execute(array($is_writeable, strlen($source), $source, $uid_shared_with, OC_USER::getUser()));
+ }
+
+ /**
+ * Unshare the item, removes it from all specified users
+ *
+ * You must use the pullOutOfFolder() function to unshare a file inside a shared folder and set $newTarget to nothing
+ *
+ * @param $source The source location of the item
+ * @param $uid_shared_with Array of users to unshare the item from
+ */
+ public static function unshare($source, $uid_shared_with) {
+ $source = self::cleanPath($source);
+ $query = OC_DB::prepare("DELETE FROM *PREFIX*sharing WHERE SUBSTR(source, 1, ?) = ? AND uid_shared_with = ? AND uid_owner = ?");
+ $query->execute(array(strlen($source), $source, $uid_shared_with, OC_USER::getUser()));
+ }
+
+ /**
+ * Unshare the item from the current user, removes it only from the database and doesn't touch the source file
+ *
+ * You must use the pullOutOfFolder() function to unshare a file inside a shared folder and set $newTarget to nothing
+ *
+ * @param $target The target location of the item
+ */
+ public static function unshareFromMySelf($target) {
+ $target = self::cleanPath($target);
+ $query = OC_DB::prepare("DELETE FROM *PREFIX*sharing WHERE SUBSTR(target, 1, ?) = ? AND uid_shared_with = ?");
+ $query->execute(array(strlen($target), $target, OC_USER::getUser()));
+ }
+
+ /**
+ * Remove the item from the database, the owner deleted the file
+ * @param $arguments Array of arguments passed from OC_HOOK
+ */
+ public static function deleteItem($arguments) {
+ $source = "/".OC_USER::getUser()."/files".$arguments['path'];
+ $source = self::cleanPath($source);
+ $query = OC_DB::prepare("DELETE FROM *PREFIX*sharing WHERE SUBSTR(source, 1, ?) = ? AND uid_owner = ?");
+ $query->execute(array(strlen($source), $source, OC_USER::getUser()));
+ }
+
+ /**
+ * Rename the item in the database, the owner renamed the file
+ * @param $arguments Array of arguments passed from OC_HOOK
+ */
+ public static function renameItem($arguments) {
+ $oldSource = "/".OC_USER::getUser()."/files".$arguments['oldpath'];
+ $oldSource = self::cleanPath($oldSource);
+ $newSource = "/".OC_USER::getUser()."/files".$arguments['newpath'];
+ $newSource = self::cleanPath($newSource);
+ self::setSource($oldSource, $newSource);
+ }
+
+}
+
+?>
diff --git a/apps/files_sharing/list.php b/apps/files_sharing/list.php
new file mode 100644
index 00000000000..6c27899369d
--- /dev/null
+++ b/apps/files_sharing/list.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Michael Gapczynski
+ * @copyright 2011 Michael Gapczynski GapczynskiM@gmail.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/>.
+ *
+ */
+
+require_once('../../lib/base.php');
+require_once('lib_share.php');
+require('template.php');
+
+if (!OC_USER::isLoggedIn()){
+ header( "Location: ".OC_HELPER::linkTo( "index.php" ));
+ exit();
+}
+
+OC_APP::setActiveNavigationEntry("files_sharing_list");
+
+OC_UTIL::addScript("files_sharing", "list");
+
+$tmpl = new OC_TEMPLATE("files_sharing", "list", "user");
+$tmpl->assign("shared_items", OC_SHARE::getMySharedItems());
+$tmpl->printPage();
+
+?> \ No newline at end of file
diff --git a/apps/files_sharing/sharedstorage.php b/apps/files_sharing/sharedstorage.php
new file mode 100644
index 00000000000..8efccbc769f
--- /dev/null
+++ b/apps/files_sharing/sharedstorage.php
@@ -0,0 +1,510 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Michael Gapczynski
+ * @copyright 2011 Michael Gapczynski GapczynskiM@gmail.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/>.
+ *
+ */
+
+require_once( 'lib_share.php' );
+
+OC_FILESYSTEM::registerStorageType('shared','OC_FILESTORAGE_SHARED',array('datadir'=>'string'));
+
+/**
+ * Convert target path to source path and pass the function call to the correct storage provider
+ */
+class OC_FILESTORAGE_SHARED extends OC_FILESTORAGE {
+
+ private $datadir;
+ private $sourcePaths = array();
+
+ public function __construct($arguments) {
+ $this->datadir = $arguments['datadir'];
+ }
+
+ public function getInternalPath($path) {
+ $mountPoint = OC_FILESYSTEM::getMountPoint($path);
+ $internalPath = substr($path, strlen($mountPoint));
+ return $internalPath;
+ }
+
+ public function getSource($target) {
+ $target = $this->datadir.$target;
+ if (array_key_exists($target, $this->sourcePaths)) {
+ return $this->sourcePaths[$target];
+ } else {
+ $source = OC_SHARE::getSource($target);
+ $this->sourcePaths[$target] = $source;
+ return $source;
+ }
+ }
+
+ public function mkdir($path) {
+ if ($path == "" || $path == "/") {
+ return false;
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ if (OC_SHARE::isWriteable($this->datadir.$path)) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->mkdir($this->getInternalPath($source));
+ }
+ }
+ }
+ }
+
+ public function rmdir($path) {
+ // The folder will be removed from the database, but won't be deleted from the owner's filesystem
+ OC_SHARE::unshareFromMySelf($this->datadir.$path);
+ }
+
+ public function opendir($path) {
+ if ($path == "" || $path == "/") {
+ global $FAKEDIRS;
+ $path = $this->datadir.$path;
+ $sharedItems = OC_SHARE::getItemsInFolder($path);
+ if (empty($sharedItems)) {
+ return false;
+ }
+ foreach ($sharedItems as $item) {
+ // If item is in the root of the shared storage provider add it to the fakedirs
+ if (dirname($item['target'])."/" == $path) {
+ $files[] = basename($item['target']);
+ }
+ }
+ $FAKEDIRS['shared'] = $files;
+ return opendir('fakedir://shared');
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ $dh = $storage->opendir($this->getInternalPath($source));
+ // Remove any duplicate or trailing '/'
+ $path = rtrim($this->datadir.$path, "/");
+ $path = preg_replace('{(/)\1+}', "/", $path);
+ $modifiedItems = OC_SHARE::getItemsInFolder($source);
+ if ($modifiedItems && $dh) {
+ global $FAKEDIRS;
+ $sources = array();
+ $targets = array();
+ foreach ($modifiedItems as $item) {
+ // If the item is in the current directory and has a different name than the source, add it to the arrays
+ if (dirname($item['target']) == $path && basename($item['source']) != basename($item['target'])) {
+ $sources[] = basename($item['source']);
+ $targets[] = basename($item['target']);
+ // If the item was unshared from self, add it it to the arrays
+ } elseif ($item['target'] == "/") {
+ $sources[] = basename($item['source']);
+ $targets[] = "";
+ }
+ }
+ // Don't waste time if there aren't any modified items in the current directory
+ if (empty($sources)) {
+ return $dh;
+ } else {
+ while (($filename = readdir($dh)) !== false) {
+ if ($filename != "." && $filename != "..") {
+ // If the file isn't in the sources array it isn't modified and can be added as is
+ if (!in_array($filename, $sources)) {
+ $files[] = $filename;
+ // The file has a different name than the source and is added to the fakedirs
+ } else {
+ $target = $targets[array_search($filename, $sources)];
+ // Don't add the file if it was unshared from self by the user
+ if ($target != "") {
+ $files[] = $target;
+ }
+ }
+ }
+ }
+ $FAKEDIRS['shared'] = $files;
+ return opendir('fakedir://shared');
+ }
+ } else {
+ return $dh;
+ }
+ }
+ }
+ }
+
+ public function is_dir($path) {
+ if ($path == "" || $path == "/") {
+ return true;
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->is_dir($this->getInternalPath($source));
+ }
+ }
+ }
+
+ public function is_file($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->is_file($this->getInternalPath($source));
+ }
+ }
+
+ // TODO fill in other components of array
+ public function stat($path) {
+ if ($path == "" || $path == "/") {
+ $stat["dev"] = "";
+ $stat["ino"] = "";
+ $stat["mode"] = "";
+ $stat["nlink"] = "";
+ $stat["uid"] = "";
+ $stat["gid"] = "";
+ $stat["rdev"] = "";
+ $stat["size"] = $this->filesize($path);
+ $stat["atime"] = $this->fileatime($path);
+ $stat["mtime"] = $this->filemtime($path);
+ $stat["ctime"] = $this->filectime($path);
+ $stat["blksize"] = "";
+ $stat["blocks"] = "";
+ return $stat;
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->stat($this->getInternalPath($source));
+ }
+ }
+ }
+
+ public function filetype($path) {
+ if ($path == "" || $path == "/") {
+ return "dir";
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->filetype($this->getInternalPath($source));
+ }
+ }
+
+ }
+
+ public function filesize($path) {
+ if ($path == "" || $path == "/" || $this->is_dir($path)) {
+ return $this->getFolderSize($path);
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->filesize($this->getInternalPath($source));
+ }
+ }
+ }
+
+ public function getFolderSize($path) {
+ if ($path == "" || $path == "/") {
+ $dbpath = OC_USER::getUser()."/files/Share/";
+ } else {
+ $source = $this->getSource($path);
+ $dbpath = $this->getInternalPath($source);
+ }
+ $query = OC_DB::prepare("SELECT size FROM *PREFIX*foldersize WHERE path=?");
+ $size = $query->execute(array($dbpath))->fetchAll();
+ if (count($size) > 0) {
+ return $size[0]['size'];
+ } else {
+ return $this->calculateFolderSize($path);
+ }
+ }
+
+ public function calculateFolderSize($path) {
+ if ($this->is_file($path)) {
+ $path = dirname($path);
+ }
+ $path = str_replace("//", "/", $path);
+ if ($this->is_dir($path) && substr($path, -1) != "/") {
+ $path .= "/";
+ }
+ $size = 0;
+ if ($dh = $this->opendir($path)) {
+ while (($filename = readdir($dh)) !== false) {
+ if ($filename != "." && $filename != "..") {
+ $subFile = $path.$filename;
+ if ($this->is_file($subFile)) {
+ $size += $this->filesize($subFile);
+ } else {
+ $size += $this->getFolderSize($subFile);
+ }
+ }
+ }
+ if ($size > 0) {
+ if ($path == "" || $path == "/") {
+ $dbpath = OC_USER::getUser()."/files/Share/";
+ } else {
+ $source = $this->getSource($path);
+ $dbpath = $this->getInternalPath($source);
+ }
+ $query = OC_DB::prepare("INSERT INTO *PREFIX*foldersize VALUES(?,?)");
+ $result = $query->execute(array($dbpath, $size));
+ }
+ }
+ return $size;
+ }
+
+ public function is_readable($path) {
+ return true;
+ }
+
+ public function is_writeable($path) {
+ if ($path == "" || $path == "/") {
+ return true;
+ } else {
+ return OC_SHARE::isWriteable($this->datadir.$path);
+ }
+ }
+
+ public function file_exists($path) {
+ if ($path == "" || $path == "/") {
+ return true;
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->file_exists($this->getInternalPath($source));
+ }
+ }
+ }
+
+ public function readfile($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->readfile($this->getInternalPath($source));
+ }
+ }
+
+ public function filectime($path) {
+ if ($path == "" || $path == "/") {
+ $ctime = 0;
+ $dir = $this->opendir($path);
+ while (($filename = readdir($dir)) != false) {
+ $tempctime = $this->filectime($filename);
+ if ($tempctime < $ctime) {
+ $ctime = $tempctime;
+ }
+ }
+ return $ctime;
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->filectime($this->getInternalPath($source));
+ }
+ }
+ }
+
+ public function filemtime($path) {
+ if ($path == "" || $path == "/") {
+ $mtime = 0;
+ $dir = $this->opendir($path);
+ while (($filename = readdir($dir)) != false) {
+ $tempmtime = $this->filemtime($filename);
+ if ($tempmtime > $mtime) {
+ $mtime = $tempmtime;
+ }
+ }
+ return $mtime;
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->filemtime($this->getInternalPath($source));
+ }
+ }
+ }
+
+ public function fileatime($path) {
+ if ($path == "" || $path == "/") {
+ $atime = 0;
+ $dir = $this->opendir($path);
+ while (($filename = readdir($dir)) != false) {
+ $tempatime = $this->fileatime($filename);
+ if ($tempatime > $atime) {
+ $atime = $tempatime;
+ }
+ }
+ return $atime;
+ } else {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->fileatime($this->getInternalPath($source));
+ }
+ }
+ }
+
+ public function file_get_contents($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->file_get_contents($this->getInternalPath($source));
+ }
+ }
+
+ // TODO OC_SHARE::getPermissions()
+ public function file_put_contents($path, $data) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->file_put_contents($this->getInternalPath($source), $data);
+ }
+ }
+
+ public function unlink($path) {
+ // The file will be removed from the database, but won't be touched on the owner's filesystem
+ $target = $this->datadir.$path;
+ // If file is inside a shared folder
+ if (OC_SHARE::getParentFolders($target)) {
+ // If entry for file already exists
+ if (OC_SHARE::getItem($target)) {
+ OC_SHARE::setTarget($target, "/");
+ } else {
+ OC_SHARE::pullOutOfFolder($target, "/");
+ }
+ } else {
+ OC_SHARE::unshareFromMySelf($target);
+ }
+ return true;
+ }
+
+ public function rename($path1, $path2) {
+ // The file will be renamed in the database, but won't be touched on the owner's filesystem
+ $oldTarget = $this->datadir.$path1;
+ $newTarget = $this->datadir.$path2;
+ if (OC_SHARE::getItem($oldTarget)) {
+ OC_SHARE::setTarget($oldTarget, $newTarget);
+ } else {
+ OC_SHARE::pullOutOfFolder($oldTarget, $newTarget);
+ if (self::is_dir($path1)) {
+ OC_SHARE::setTarget($oldTarget, $newTarget);
+ }
+ }
+ return true;
+ }
+
+ public function copy($path1, $path2) {
+ if ($path2 == "" || $path2 == "/") {
+ // TODO Construct new shared item or should this not be allowed?
+ } else {
+ if ($this->is_writeable($path)) {
+ $tmpFile = $this->toTmpFile($path1);
+ return $this->fromTmpFile($tmpFile, $path2);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public function fopen($path, $mode) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->fopen($this->getInternalPath($source), $mode);
+ }
+ }
+
+ public function toTmpFile($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->toTmpFile($this->getInternalPath($source));
+ }
+ }
+
+ public function fromTmpFile($tmpFile, $path) {
+ if ($this->is_writeable($path)) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->fromTmpFile($tmpFile, $this->getInternalPath($source));
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public function fromUploadedFile($tmpPath, $path) {
+ $source = $this->getSource($tmpPath);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->fromUploadedFile($this->getInternalPath($source), $path);
+ }
+ }
+
+ public function getMimeType($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->getMimeType($this->getInternalPath($source));
+ }
+ }
+
+ public function delTree($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->delTree($this->getInternalPath($source));
+ }
+ }
+
+ public function find($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->find($this->getInternalPath($source));
+ }
+ }
+
+ public function getTree($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->getTree($this->getInternalPath($source));
+ }
+ }
+
+ public function hash($type, $path, $raw) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->hash($type, $this->getInternalPath($source), $raw);
+ }
+ }
+
+ public function free_space($path) {
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_FILESYSTEM::getStorage($source);
+ return $storage->free_space($this->getInternalPath($source));
+ }
+ }
+
+ // TODO query all shared files?
+ public function search($query) {
+
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/apps/files_sharing/templates/list.php b/apps/files_sharing/templates/list.php
new file mode 100644
index 00000000000..73ffff1ab6b
--- /dev/null
+++ b/apps/files_sharing/templates/list.php
@@ -0,0 +1,30 @@
+<fieldset>
+ <legend>Your Shared Files</legend>
+ <table id='itemlist'>
+ <thead>
+ <tr>
+ <th>Item</th>
+ <th>Shared With</th>
+ <th>Permissions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach($_['shared_items'] as $item):?>
+ <tr class='item'>
+ <td class='source'><?php echo substr($item['source'], strlen("/".$_SESSION['user_id']."/files/"));?></td>
+ <td class='uid_shared_with'><?php echo $item['uid_shared_with'];?></td>
+ <td class='permissions'><?php echo $item['is_writeable'];?></td>
+ <td><button class='delete fancybutton' data-source='<?php echo $item['source'];?>' data-uid_shared_with='<?php echo $item['uid_shared_with'];?>'>Delete</button></td>
+ </tr>
+ <?php endforeach;?>
+ <tr id='share_item_row'>
+ <form action='#' id='share_item'>
+ <td class='source'><input placeholder='Item' id='source'/></td>
+ <td class='uid_shared_with'><input placeholder='Share With' id='uid_shared_with'/></td>
+ <td class='permissions'><input placeholder='Permissions' id='permissions'/></td>
+ <td><input type='submit' value='Share'/></td>
+ </form>
+ </tr>
+ </tbody>
+ </table>
+</fieldset>
diff --git a/lib/base.php b/lib/base.php
index 4636dd703ed..d81479e5a28 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -84,6 +84,7 @@ require_once('appconfig.php');
require_once('files.php');
require_once('filesystem.php');
require_once('filestorage.php');
+require_once('apps/files_sharing/sharedstorage.php');
require_once('l10n.php');
require_once('preferences.php');
require_once('log.php');
@@ -164,6 +165,10 @@ class OC_UTIL {
// }
OC_FILESYSTEM::mount($rootStorage,'/');
+ // TODO add this storage provider in a proper way
+ $sharedStorage = OC_FILESYSTEM::createStorage('shared',array('datadir'=>'/'.OC_USER::getUser().'/files/Share/'));
+ OC_FILESYSTEM::mount($sharedStorage,'/'.OC_USER::getUser().'/files/Share/');
+
$CONFIG_DATADIRECTORY = "$CONFIG_DATADIRECTORY_ROOT/$user/$root";
if( !is_dir( $CONFIG_DATADIRECTORY )){
mkdir( $CONFIG_DATADIRECTORY, 0755, true );
diff --git a/lib/filesystem.php b/lib/filesystem.php
index b82fe2afebf..2c26667bbee 100644
--- a/lib/filesystem.php
+++ b/lib/filesystem.php
@@ -175,7 +175,7 @@ class OC_FILESYSTEM{
* @param string path
* @return OC_FILESTORAGE
*/
- static private function getStorage($path){
+ static public function getStorage($path){
$mountpoint=self::getMountPoint($path);
if($mountpoint){
return self::$storages[$mountpoint];
@@ -189,7 +189,7 @@ class OC_FILESYSTEM{
* @param string path
* @return string
*/
- static private function getMountPoint($path){
+ static public function getMountPoint($path){
if(!$path){
$path='/';
}
@@ -214,6 +214,7 @@ class OC_FILESYSTEM{
}
return $foundMountPoint;
}
+
/**
* return the path to a local version of the file
* we need this because we can't know if a file is stored local or not from outside the filestorage and for some purposes a local file is needed