/**
  * This method handles the {DAV:}sync-collection HTTP REPORT.
  *
  * @param string $uri
  * @param \DOMDocument $report
  * @return void
  */
 function syncCollection($uri, \DOMDocument $report)
 {
     // Getting the sync token of the data requested
     /**
      * @var $node Tinebase_WebDav_Container_Abstract
      */
     $node = $this->server->tree->getNodeForPath($uri);
     if (!$node instanceof Tinebase_WebDav_Container_Abstract || !$node->supportsSyncToken()) {
         throw new Sabre\DAV\Exception\ReportNotSupported('The {DAV:}sync-collection REPORT is not supported on this url.');
     }
     $token = $node->getSyncToken();
     if (!$token) {
         throw new Sabre\DAV\Exception\ReportNotSupported('No sync information is available at this node');
     }
     // getting the sync token send with the request
     $syncToken = '';
     $syncTokenList = $report->getElementsByTagNameNS('urn:DAV', 'sync-token');
     if ($syncTokenList->length == 1) {
         $syncToken = $syncTokenList->item(0)->textContent;
         //?!? //nodeValue;
     }
     if (strlen($syncToken) > 0) {
         // Sync-token must start with our prefix
         if (substr($syncToken, 0, strlen(self::SYNCTOKEN_PREFIX)) !== self::SYNCTOKEN_PREFIX || strlen($syncToken) <= strlen(self::SYNCTOKEN_PREFIX)) {
             throw new Sabre\DAV\Exception\BadRequest('Invalid or unknown sync token');
         }
         $syncToken = substr($syncToken, strlen(self::SYNCTOKEN_PREFIX));
     } else {
         $syncToken = 0;
     }
     // get the list of properties the client requested
     $properties = array_keys(Sabre\DAV\XMLUtil::parseProperties($report->documentElement));
     // get changes since client sync token
     $changeInfo = $node->getChanges($syncToken);
     if (is_null($changeInfo)) {
         throw new Sabre\DAV\Exception\BadRequest('Invalid or unknown sync token');
     }
     // Encoding the response
     $this->sendSyncCollectionResponse($changeInfo['syncToken'], $uri, $changeInfo[Tinebase_Model_ContainerContent::ACTION_CREATE], $changeInfo[Tinebase_Model_ContainerContent::ACTION_UPDATE], $changeInfo[Tinebase_Model_ContainerContent::ACTION_DELETE], $properties);
 }
 /**
  * Does a REPORT request
  *
  * @param string $url
  * @param array $properties List of requested properties must be specified as an array, in clark
  *        notation.
  * @param array $event_urls If specified, a multiget report request will be initiated with the
  *        specified event urls.
  * @param int $depth = 1 Depth should be either 0 or 1. A depth of 1 will cause a request to be
  *        made to the server to also return all child resources.
  * @return array Hash with ics event path as key and a hash array with properties and appropriate values.
  */
 public function prop_report($url, array $properties, array $event_urls = array(), $depth = 1)
 {
     $url = slashify($url);
     // iCloud
     $parent_tag = sizeof($event_urls) > 0 ? "c:calendar-multiget" : "d:propfind";
     $method = sizeof($event_urls) > 0 ? 'REPORT' : 'PROPFIND';
     $body = '<?xml version="1.0"?>' . "\n" . '<' . $parent_tag . ' xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">' . "\n";
     $body .= '  <d:prop>' . "\n";
     foreach ($properties as $property) {
         list($namespace, $elementName) = Sabre\DAV\XMLUtil::parseClarkNotation($property);
         if ($namespace === 'DAV:') {
             $body .= '    <d:' . $elementName . ' />' . "\n";
         } else {
             $body .= '    <x:' . $elementName . ' xmlns:x="' . $namespace . '"/>' . "\n";
         }
     }
     $body .= '  </d:prop>' . "\n";
     // http://tools.ietf.org/html/rfc4791#page-90
     // http://www.bedework.org/trac/bedework/wiki/Bedework/DevDocs/Filters
     /*
     if($start && $end)
     {
     $body.= '  <c:filter>'."\n".
     '    <c:comp-filter name="VCALENDAR">'."\n".
     '      <c:comp-filter name="VEVENT">'."\n".
     '        <c:time-range start="'.$start.'" end="'.$end.'" />'."\n".
     '      </c:comp-filter>'."\n".
     '    </c:comp-filter>'."\n".
     '  </c:filter>' . "\n";
     }
     */
     foreach ($event_urls as $event_url) {
         $body .= '<d:href>' . $event_url . '</d:href>' . "\n";
     }
     $body .= '</' . $parent_tag . '>';
     $response = $this->request($method, $url, $body, array('Depth' => $depth, 'Content-Type' => 'application/xml', 'User-Agent' => $this->user_agent));
     $result = $this->parseMultiStatus($response['body']);
     // If depth was 0, we only return the top item
     if ($depth === 0) {
         reset($result);
         $result = current($result);
         return isset($result[200]) ? $result[200] : array();
     }
     $new_result = array();
     foreach ($result as $href => $status_list) {
         $new_result[$href] = isset($status_list[200]) ? $status_list[200] : array();
     }
     return $new_result;
 }