Example #1
0
 public function method_POST(&$headers)
 {
     $displayname = $_POST['displayname'];
     $description = $_POST['description'];
     $group_name = $_POST['group_name'];
     $user_sponsor = BeeHub::getAuth()->current_user()->user_prop(BeeHub::PROP_SPONSOR);
     // If you don't have a (default) sponsor, you're not allowed to add a group
     if (empty($user_sponsor)) {
         throw DAV::forbidden("Only users with a sponsor are allowed to create groups");
     }
     // Group name must be one of the following characters a-zA-Z0-9_-., starting with an alphanumeric character and must be between 1 and 255 characters long and can't be one of the forbidden names
     if (empty($displayname) || in_array(strtolower($group_name), BeeHub::$FORBIDDEN_GROUP_NAMES) || !preg_match('/^[a-zA-Z0-9]{1}[a-zA-Z0-9_\\-\\.]{0,254}$/D', $group_name)) {
         throw new DAV_Status(DAV::HTTP_BAD_REQUEST, 'Group name has the wrong format. The name can be a maximum of 255 characters long and should start with an alphanumeric character, followed by alphanumeric characters or one of the following: _-.');
     }
     // Check if the group name doesn't exist
     $collection = BeeHub::getNoSQL()->groups;
     $result = $collection->findOne(array('name' => $group_name), array('name' => true));
     if (!is_null($result)) {
         // Duplicate key: bad request!
         throw new DAV_Status(DAV::HTTP_CONFLICT, "Group name already exists, please choose a different group name!");
     }
     $groupdir = DAV::unslashify(BeeHub::$CONFIG['environment']['datadir']) . DIRECTORY_SEPARATOR . $group_name;
     // Check for existing groupdir
     if (file_exists($groupdir)) {
         throw new DAV_Status(DAV::HTTP_INTERNAL_SERVER_ERROR);
     }
     // Store in the database
     $collection->insert(array('name' => $group_name));
     // Fetch the group and store extra properties
     $group = DAV::$REGISTRY->resource(BeeHub::GROUPS_PATH . $group_name);
     $group->user_set(DAV::PROP_DISPLAYNAME, $displayname);
     if (!empty($description)) {
         $group->user_set(BeeHub::PROP_DESCRIPTION, $description);
     }
     $group->storeProperties();
     // Add the current user as admin of the group
     $group->change_memberships(basename($this->user_prop_current_user_principal()), BeeHub_Group::USER_ACCEPT);
     $group->change_memberships(basename($this->user_prop_current_user_principal()), BeeHub_Group::ADMIN_ACCEPT);
     $group->change_memberships(basename($this->user_prop_current_user_principal()), BeeHub_Group::SET_ADMIN);
     // And create a group directory
     if (!mkdir($groupdir)) {
         throw new DAV_Status(DAV::HTTP_INTERNAL_SERVER_ERROR);
     }
     // And create the directory in the database
     $document = array('path' => $group_name, 'depth' => 1, 'collection' => true);
     $filesCollection = BeeHub::getNoSQL()->files;
     $filesCollection->save($document);
     $groupdir_resource = DAV::$REGISTRY->resource('/' . $group_name);
     $groupdir_resource->user_set(BeeHub::PROP_SPONSOR, $user_sponsor);
     $groupdir_resource->user_set(DAV::PROP_ACL, '[["' . BeeHub::GROUPS_PATH . $group->name . '",false,["DAV: read", "DAV: write"],false]]');
     $groupdir_resource->storeProperties();
     // Group created, redirect to the group page
     DAV::redirect(DAV::HTTP_SEE_OTHER, BeeHub::GROUPS_PATH . $group->name);
 }
Example #2
0
/**
 * Traverse over the files and subdirectories
 * 
 * @global  MongoCollection    $collection  The MongoDB collection
 * @global  Array              $CONFIG      The configuration parameters
 * @param   DirectoryIterator  $iterator    The DirectoryIterator to iterate over
 * @return  void
 */
function traverse($iterator)
{
    global $collection, $CONFIG;
    foreach ($iterator as $fileinfo) {
        $file = $fileinfo->getPathname();
        if ($fileinfo->isDot()) {
            continue;
        } elseif ($fileinfo->isDir()) {
            traverse(new DirectoryIterator($file));
        }
        $attributes = xattr_list($file);
        $stored_props = array();
        if (!$fileinfo->isDir()) {
            $encodedKey = str_replace(array('%', '$', '.'), array('%25', '%24', '%2E'), DAV::PROP_GETCONTENTLENGTH);
            $stored_props[$encodedKey] = $fileinfo->getSize();
        }
        foreach ($attributes as $attribute) {
            $decodedKey = rawurldecode($attribute);
            $value = xattr_get($file, $attribute);
            // Transform the value of the owner and sponsor properties (but only if necessary)
            if (($decodedKey === 'DAV: owner' || $decodedKey === 'http://beehub.nl/ sponsor') && substr($value, 0, 1) === '/') {
                $value = rawurldecode(basename($value));
            }
            // Property names are already stored url encoded in extended attributes, but we just need it a few characters to be encoded.
            // This url encodes only the characters needed to create valid mongoDB keys. You can just run rawurldecode to decode it.
            $encodedKey = str_replace(array('%', '$', '.'), array('%25', '%24', '%2E'), $decodedKey);
            $stored_props[$encodedKey] = mb_convert_encoding($value, 'UTF-8');
        }
        $unslashifiedPath = \DAV::unslashify(substr($file, strlen($CONFIG['environment']['datadir'])));
        if (substr($unslashifiedPath, 0, 1) === '/') {
            $unslashifiedPath = substr($unslashifiedPath, 1);
        }
        if ($unslashifiedPath === '') {
            $depth = 0;
        } else {
            $depth = substr_count($unslashifiedPath, '/') + 1;
        }
        $document = array('path' => mb_convert_encoding($unslashifiedPath, 'UTF-8'), 'depth' => $depth, 'props' => $stored_props);
        if ($fileinfo->isDir()) {
            $document['collection'] = true;
        }
        $collection->save($document);
    }
}
Example #3
0
 /**
  * @param string $path
  */
 public function resource($path)
 {
     if (is_array($path)) {
         $document = $path;
         $path = '/' . $document['path'];
     } else {
         $document = null;
     }
     $path = DAV::unslashify($path);
     $systemPath = DAV::unslashify(BeeHub::SYSTEM_PATH);
     $usersPath = DAV::unslashify(BeeHub::USERS_PATH);
     $groupsPath = DAV::unslashify(BeeHub::GROUPS_PATH);
     $sponsorsPath = DAV::unslashify(BeeHub::SPONSORS_PATH);
     if (isset($this->resourceCache[$path])) {
         return $this->resourceCache[$path];
     }
     $localPath = BeeHub::localPath($path);
     $retval = null;
     if ($path === '/') {
         $retval = new BeeHub_Directory($path);
     } elseif ($path === $systemPath) {
         $retval = new BeeHub_System_Collection($path);
     } elseif (substr($path, 0, strlen($usersPath)) === $usersPath) {
         if ($path === $usersPath) {
             $retval = new BeeHub_Users($path);
         } else {
             try {
                 $retval = new BeeHub_User($path);
             } catch (Exception $e) {
             }
         }
     } elseif (substr($path, 0, strlen($groupsPath)) === $groupsPath) {
         if ($path === $groupsPath) {
             $retval = new BeeHub_Groups($path);
         } else {
             try {
                 $retval = new BeeHub_Group($path);
             } catch (Exception $e) {
             }
         }
     } elseif (substr($path, 0, strlen($sponsorsPath)) === $sponsorsPath) {
         if ($path === $sponsorsPath) {
             $retval = new BeeHub_Sponsors($path);
         } else {
             try {
                 $retval = new BeeHub_Sponsor($path);
             } catch (Exception $e) {
             }
         }
     } else {
         $unslashifiedPath = $path;
         if (substr($unslashifiedPath, 0, 1) === '/') {
             $unslashifiedPath = substr($unslashifiedPath, 1);
         }
         $collection = BeeHub::getNoSQL()->files;
         if (!is_array($document)) {
             $document = $collection->findOne(array('path' => $unslashifiedPath));
         }
         if (!is_null($document)) {
             if (isset($document['collection']) && $document['collection']) {
                 $retval = new BeeHub_Directory($document);
             } else {
                 $retval = new BeeHub_File($document);
             }
         } else {
             return null;
         }
     }
     return $this->resourceCache[$path] = $retval;
 }
Example #4
0
            $sysDir = substr($sysDir, 1);
        }
        $fileDocument = array('path' => $sysDir, 'depth' => substr_count($sysDir, '/') + 1, 'collection' => true, 'props' => array());
        $filesCollection->insert($fileDocument);
    }
    // Add the user's home directory with different properties
    $fileDocument = array('path' => \DAV::unslashify($userdir), 'collection' => true, 'props' => array(\DAV::PROP_OWNER => $username));
    if (substr($fileDocument['path'], 0, 1) === '/') {
        $fileDocument['path'] = substr($fileDocument['path'], 1);
    }
    $fileDocument['depth'] = substr_count($fileDocument['path'], '/') + 1;
    $encodedKey = str_replace(array('%', '$', '.'), array('%25', '%24', '%2E'), \BeeHub::PROP_SPONSOR);
    $fileDocument['props'][$encodedKey] = DEFAULT_SPONSOR_NAME;
    $filesCollection->insert($fileDocument);
    // Add the group directory with different properties
    $fileDocument = array('path' => \DAV::unslashify(\basename($config['namespace']['admin_group'])), 'collection' => true, 'props' => array(\DAV::PROP_ACL => '[["' . $config['namespace']['admin_group'] . '",false,["DAV: read", "DAV: write"],false]]'));
    if (substr($fileDocument['path'], 0, 1) === '/') {
        $fileDocument['path'] = substr($fileDocument['path'], 1);
    }
    $fileDocument['depth'] = substr_count($fileDocument['path'], '/') + 1;
    $encodedKey = str_replace(array('%', '$', '.'), array('%25', '%24', '%2E'), \BeeHub::PROP_SPONSOR);
    $fileDocument['props'][$encodedKey] = DEFAULT_SPONSOR_NAME;
    $filesCollection->insert($fileDocument);
} else {
    \header('HTTP/1.1 500 Internal Server Error');
    \ob_end_flush();
    print "\nUnable to create the system directories\n";
    exit;
}
print "ok\n";
// Then import the database structure
Example #5
0
 public function testUnslashify()
 {
     $this->assertSame('/something/with/a/slash/at/the/end', DAV::unslashify('/something/with/a/slash/at/the/end/'), 'DAV::slashify() should remove the trailing slash from a string which ends with a slash');
     $this->assertSame('/something/with/no/slash/at/the/end', DAV::unslashify('/something/with/no/slash/at/the/end'), 'DAV::slashify() should not do anything to a string which doesn\'t end with a slash');
 }
Example #6
0
 /**
  * Check any HTTP If-* header applicable with the current request method
  * 
  * @return boolean TRUE if shallowLock() was called;
  */
 private function check_if_headers()
 {
     $write_locks = $read_locks = array();
     switch ($_SERVER['REQUEST_METHOD']) {
         case 'ACL':
         case 'DELETE':
         case 'LOCK':
         case 'MKCOL':
         case 'POST':
         case 'PROPPATCH':
         case 'PUT':
         case 'UNLOCK':
             // For all actions above you need a write lock for the path/resource
             $write_locks[DAV::unslashify(DAV::getPath())] = 1;
             break;
         case 'COPY':
         case 'MOVE':
             // Here, things get a bit more complicated
             if (!$this->destination()) {
                 throw new DAV_Status(DAV::HTTP_BAD_REQUEST, 'Missing required Destination: header');
             }
             if ('/' === substr($this->destination(), 0, 1)) {
                 // For destinations as absolute paths, you'll need a write lock on the destination
                 $write_locks[DAV::unslashify($this->destination())] = 1;
             }
             if ('COPY' === $_SERVER['REQUEST_METHOD']) {
                 // If you want to copy, you'll just need a read lock on the source
                 $read_locks[DAV::unslashify(DAV::getPath())] = 1;
             } else {
                 // But if you want to move, you'll need a write lock on the source (as it will be deleted)
                 $write_locks[DAV::unslashify(DAV::getPath())] = 1;
             }
             break;
     }
     // If there are write locks, you'll also need read locks on all parents
     if (!empty($write_locks)) {
         foreach (array_keys($write_locks) as $p) {
             while ($p !== '/') {
                 $p = dirname($p);
                 $read_locks[$p] = 1;
             }
         }
     }
     foreach (array('MATCH', 'UNMODIFIED_SINCE') as $value) {
         // Conditions 'NONE_MATCH', 'MODIFIED_SINCE' are not relevant
         if (isset($_SERVER['HTTP_IF_' . $value])) {
             $read_locks[DAV::unslashify(DAV::getPath())] = 1;
             break;
         }
     }
     foreach (array_keys($this->if_header) as $path) {
         $read_locks[DAV::unslashify($path)] = 1;
     }
     // If we already want a write lock, we should not also want a read lock
     foreach (array_keys($write_locks) as $path) {
         unset($read_locks[$path]);
     }
     // No locks required? Than just return false so the caller knows that there are no (shallow) locks set
     if (empty($write_locks) && empty($read_locks)) {
         return false;
     }
     // Get the (shallow) locks
     DAV::$REGISTRY->shallowLock(array_keys($write_locks), array_keys($read_locks));
     try {
         // to guarantee unlocking i.c.o. exceptions
         $this->check_if_match_header();
         $this->check_if_modified_since_header();
         $this->check_if_header();
     } catch (Exception $e) {
         DAV::$REGISTRY->shallowUnlock();
         throw $e;
     }
     return true;
 }
 /**
  * Gets all members who have a certain property set
  * @param   string  $prop  The property which should be set on the member
  * @return  array          An array with all paths to members who have the property set
  */
 public function get_members_with_prop($prop)
 {
     $collection = BeeHub::getNoSQL()->files;
     $unslashifiedPath = DAV::unslashify($this->path);
     while (substr($unslashifiedPath, 0, 1) === '/') {
         $unslashifiedPath = substr($unslashifiedPath, 1);
     }
     if ($unslashifiedPath === '') {
         $queryArray = array('depth' => array('$gt' => 0), 'props.' . $prop => array('$exists' => true));
     } else {
         $queryArray = array('depth' => array('$gt' => substr_count($unslashifiedPath, '/') + 1), 'path' => array('$regex' => '^' . preg_quote(DAV::slashify($unslashifiedPath)) . '.*'), 'props.' . $prop => array('$exists' => true));
     }
     $results = $collection->find($queryArray, array('path' => 1, 'props.' . $prop => 1));
     $returnVal = array();
     foreach ($results as $result) {
         $returnVal[$result['path']] = $result['props'][$prop];
     }
     return $returnVal;
 }
Example #8
0
 /**
  * Determine the local path in the storage backend
  *
  * @param   string  $path  The path in the webDAV namespace
  * @return  string         The location where the data is stored in the storage backend
  */
 public static function localPath($path)
 {
     if (substr($path, 0, 1) === '/') {
         $path = substr($path, 1);
     }
     return DAV::unslashify(self::$CONFIG['environment']['datadir'] . $path);
 }
Example #9
0
 /**
  * @return DirectoryIterator
  */
 private function dir()
 {
     if (is_null($this->dir)) {
         $collection = BeeHub::getNoSQL()->files;
         $unslashifiedPath = DAV::unslashify($this->path);
         while (substr($unslashifiedPath, 0, 1) === '/') {
             $unslashifiedPath = substr($unslashifiedPath, 1);
         }
         if (!empty($unslashifiedPath)) {
             $query = array('depth' => substr_count($unslashifiedPath, '/') + 2, 'path' => array('$regex' => '^' . preg_quote($unslashifiedPath) . '/[^/]*$'));
         } else {
             $query = array('depth' => 1);
         }
         $allChildren = $collection->find($query);
         $this->dir = array();
         foreach ($allChildren as $document) {
             $child = basename($document['path']);
             if (isset($document['collection']) && $document['collection']) {
                 $child .= '/';
             }
             if (!DAV::$REGISTRY->resource($document)->isVisible()) {
                 DAV::$REGISTRY->forget($this->path . $child);
             } else {
                 $this->dir[] = $child;
             }
         }
     }
     return $this->dir;
 }
Example #10
0
 /**
  * Determines whether you need to authenticate based on the method and URL of the request
  * @return  boolean  True if authentication is required, false otherwise
  */
 public static function is_authentication_required()
 {
     $path = DAV::unslashify(DAV::getPath());
     /**
      * You don't need to authenticate when:
      * - GET (or HEAD) or POST on the users collection (required to create a new user)
      * - GET (or HEAD) on the system collection (required to read the 'homepage')
      * In other cases you do need to authenticate
      */
     $noRequireAuth = $path === DAV::unslashify(BeeHub::USERS_PATH) && in_array($_SERVER['REQUEST_METHOD'], array('GET', 'POST', 'HEAD')) || $path === DAV::unslashify(BeeHub::SYSTEM_PATH) && in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD'));
     return !$noRequireAuth;
 }
Example #11
0
 /**
  * Handles the form to register a new user. No authentication required.
  * @see DAV_Resource::method_POST()
  */
 public function method_POST(&$headers)
 {
     $displayname = $_POST['displayname'];
     $email = $_POST['email'];
     $password = !empty($_POST['password']) ? $_POST['password'] : null;
     $user_name = $_POST['user_name'];
     // User name must be one of the following characters a-zA-Z0-9_-., starting with an alphanumeric character and must be between 1 and 255 characters long
     if (empty($displayname) || !preg_match('/^[a-zA-Z0-9]{1}[a-zA-Z0-9_\\-\\.]{0,254}$/D', $user_name)) {
         throw new DAV_Status(DAV::HTTP_BAD_REQUEST, 'User name has the wrong format. The name can be a maximum of 255 characters long and should start with an alphanumeric character, followed by alphanumeric character, followed by alphanumeric characters or one of the following: _-.');
     }
     // Check if the username doesn't exist
     $collection = BeeHub::getNoSQL()->users;
     $result = $collection->findOne(array('name' => $user_name), array('name' => true));
     if (!is_null($result)) {
         // Duplicate key: bad request!
         throw new DAV_Status(DAV::HTTP_CONFLICT, "User name already exists, please choose a different user name!");
     }
     $userdir = DAV::unslashify(BeeHub::$CONFIG['environment']['datadir']) . DIRECTORY_SEPARATOR . 'home' . DIRECTORY_SEPARATOR . $user_name;
     // Check for existing userdir
     if (file_exists($userdir)) {
         throw new DAV_Status(DAV::HTTP_INTERNAL_SERVER_ERROR);
     }
     // Store in the database
     $collection->insert(array('name' => $user_name));
     // Fetch the user and store extra properties
     $user = DAV::$REGISTRY->resource(BeeHub::USERS_PATH . $user_name);
     $user->set_password($password);
     $user->user_set(DAV::PROP_DISPLAYNAME, $displayname);
     $user->user_set(BeeHub::PROP_EMAIL, $email);
     // Just to be clear: the above lines will have to be deleted somewhere in the future, but the lines below should stay
     $auth = BeeHub::getAuth();
     if ($auth->simpleSaml()->isAuthenticated()) {
         $surfId = $auth->simpleSaml()->getAuthData("saml:sp:NameID");
         $surfId = $surfId['Value'];
         $attributes = $auth->simpleSaml()->getAttributes();
         $surfconext_description = @$attributes['urn:mace:terena.org:attribute-def:schacHomeOrganization'][0];
         if (empty($surfconext_description)) {
             $surfconext_description = 'Unknown account';
         }
         $user->user_set(BeeHub::PROP_SURFCONEXT, $surfId);
         $user->user_set(BeeHub::PROP_SURFCONEXT_DESCRIPTION, $surfconext_description);
     }
     $user->storeProperties();
     // TODO: This should not be hard coded, a new user should not have a sponsor but request one after his account is created, but I want to inform the user about his through the not-yet-existing notification system
     $sponsor = DAV::$REGISTRY->resource('/system/sponsors/e-infra');
     $sponsor->change_memberships($user_name, BeeHub_Sponsor::USER_ACCEPT);
     $sponsor->change_memberships($user_name, BeeHub_Sponsor::ADMIN_ACCEPT);
     // And create a user directory
     if (!mkdir($userdir)) {
         throw new DAV_Status(DAV::HTTP_INTERNAL_SERVER_ERROR);
     }
     // And create the directory in the database
     $document = array('path' => 'home/' . $user_name, 'depth' => 2, 'collection' => true);
     $filesCollection = BeeHub::getNoSQL()->files;
     $filesCollection->save($document);
     $userdir_resource = DAV::$REGISTRY->resource('/home/' . $user_name);
     $userdir_resource->user_set(DAV::PROP_OWNER, $user->path);
     // TODO: this should not be hard coded. When a users is accepted by his/her first sponsor, this should automatically be set.
     $userdir_resource->user_set(BeeHub::PROP_SPONSOR, '/system/sponsors/e-infra');
     $userdir_resource->storeProperties();
     // Show the confirmation
     $this->include_view('new_user_confirmation', array('email_address' => $email));
 }
Example #12
0
	        <tr>
	          <th>Principal</th>
	          <th>Permissions</th>
	          <!-- Hidden dropdown column -->
	          <th hidden="hidden"></th>
	          <th>Comment</th>
	          <!-- Move up -->
	          <th class="bh-dir-small-column"></th>
	          <!-- Move down -->
	          <th class="bh-dir-small-column"></th>
	          <!-- Delete row -->
	          <th class="bh-dir-small-column"></th>
	        </tr>
	      </thead>
	      <tbody class="bh-dir-acl-contents" data-value="<?php 
echo DAV::xmlescape(DAV::unslashify($this->path));
?>
">
	        <?php 
$acl = $this->user_prop_acl();
$acl_length = count($acl);
for ($key = 0; $key < $acl_length; $key++) {
    $ace = $acl[$key];
    // The protected property which grants everybody the 'DAV: unbind' privilege will be omitted from the list
    if ($ace->protected && $ace->principal === DAVACL::PRINCIPAL_ALL && !$ace->deny && count($ace->privileges) === 1 && in_array(DAVACL::PRIV_UNBIND, $ace->privileges)) {
        continue;
    }
    ?>
	          <tr class="bh-dir-acl-row <?php 
    echo $ace->protected || $ace->inherited ? 'info' : '';
    ?>
Example #13
0
 /**
  * Determines whether the copy request is valid and if so, copies the resources
  * 
  * @param DAV_Resource $resource
  * @return void
  * @throws DAV_Status
  */
 protected function handle($resource)
 {
     $destination = $this->destination();
     if ($resource instanceof DAV_Collection) {
         $destination = DAV::slashify($destination);
     } else {
         // The next line is here to make the litmus test succeed. The author of
         // litmus had eir own doubts wether this is actually desirable behaviour,
         // but chose to require this behaviour anyway:
         $destination = DAV::unslashify($destination);
     }
     // Can't move the root collection:
     if ($this instanceof DAV_Request_MOVE && '/' === DAV::getPath()) {
         throw new DAV_Status(DAV::HTTP_FORBIDDEN);
     }
     // Assert proper Depth: header value:
     if (DAV::DEPTH_1 === $this->depth() or $this instanceof DAV_Request_MOVE && DAV::DEPTH_INF !== $this->depth()) {
         throw new DAV_Status(DAV::HTTP_BAD_REQUEST, 'Illegal value for Depth: header.');
     }
     // Check: Can't move a collection to one of its members.
     if ($this instanceof DAV_Request_MOVE && '/' === substr(DAV::getPath(), -1) && 0 === strpos($destination, DAV::getPath())) {
         throw new DAV_Status(DAV::HTTP_FORBIDDEN, "Can't move a collection to itself or one of its members.");
     }
     $resourceCollection = $resource->collection();
     if ($this instanceof DAV_Request_MOVE) {
         $resourceCollection->assertLock();
         $resource->assertLock();
         $resource->assertMemberLocks();
     }
     if ('/' !== $destination[0]) {
         // Copy to an external URI?
         $isCreated = $resource->method_COPY_external($destination, $this->overwrite());
         if ($this instanceof DAV_Request_MOVE && !DAV_Multistatus::active()) {
             DAV_Request_DELETE::delete($resource);
         }
         if (DAV_Multistatus::active()) {
             DAV_Multistatus::inst()->close();
         } elseif ($isCreated) {
             DAV::redirect(DAV::HTTP_CREATED, $destination);
         } else {
             DAV::header(array('status' => DAV::HTTP_NO_CONTENT));
         }
         return;
     }
     // Check: Won't move a resource to one of its parents.
     if (0 === strpos(DAV::slashify(DAV::getPath()), DAV::slashify($destination))) {
         throw new DAV_Status(DAV::HTTP_NOT_IMPLEMENTED, "Won't move or copy a resource to one of its parents.");
     }
     $destinationResource = DAV::$REGISTRY->resource($destination);
     $destinationCollection = DAV::$REGISTRY->resource(dirname($destination));
     if (!$destinationCollection) {
         throw new DAV_Status(DAV::HTTP_CONFLICT, 'Unable to COPY to unexisting destination collection');
     }
     if ($destinationResource) {
         if (!$this->overwrite()) {
             throw new DAV_Status(DAV::HTTP_PRECONDITION_FAILED);
         } else {
             $destinationResource->assertLock();
         }
     } else {
         $destinationCollection->assertLock();
     }
     if ($this instanceof DAV_Request_MOVE) {
         if (DAV::$LOCKPROVIDER) {
             foreach (DAV::$LOCKPROVIDER->memberLocks(DAV::getPath()) as $lock) {
                 DAV::$LOCKPROVIDER->unlock($lock->lockroot);
             }
             if ($lock = DAV::$LOCKPROVIDER->getlock(DAV::getPath())) {
                 DAV::$LOCKPROVIDER->unlock($lock->lockroot);
             }
         }
         $resourceCollection->method_MOVE(basename($resource->path), $destination);
     } else {
         $this->copy_recursively($resource, $destination);
     }
     #<<<<<<<<
     #// This version always returns a 207 Multistatus wrapper:
     #if (!DAV_Multistatus::active())
     #  if ( $destinationResource )
     #    DAV_Multistatus::inst()->addStatus(
     #      $resource->path,
     #      new DAV_Status( DAV::HTTP_NO_CONTENT )
     #    );
     #  else
     #    DAV_Multistatus::inst()->addStatus(
     #      $resource->path,
     #      new DAV_Status(
     #        DAV::HTTP_CREATED, DAV::path2uri($destination)
     #      )
     #    );
     #DAV_Multistatus::inst()->close();
     #========
     if (DAV_Multistatus::active()) {
         DAV_Multistatus::inst()->close();
     } elseif ($destinationResource) {
         DAV::header(array('status' => DAV::HTTP_NO_CONTENT));
     } else {
         DAV::redirect(DAV::HTTP_CREATED, $destination);
     }
     #>>>>>>>>
 }