diff --git a/apps/dav/lib/CardDAV/VCFMultiExportPlugin.php b/apps/dav/lib/CardDAV/VCFMultiExportPlugin.php index 0364a25f38bfc..b3d45963795c2 100644 --- a/apps/dav/lib/CardDAV/VCFMultiExportPlugin.php +++ b/apps/dav/lib/CardDAV/VCFMultiExportPlugin.php @@ -24,12 +24,10 @@ namespace OCA\DAV\CardDAV; -use OCA\DAV\CardDAV\AddressBook; use Sabre\DAV; use Sabre\DAV\Server; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; -use Sabre\VObject; class VCFMultiExportPlugin extends DAV\ServerPlugin { @@ -44,11 +42,11 @@ class VCFMultiExportPlugin extends DAV\ServerPlugin { */ public function initialize(Server $server) { $this->server = $server; - $this->server->on('method:GET', [$this, 'httpGet'], 90); + $this->server->on('afterMethod:REPORT', [$this, 'httpGet'], 90); } /** - * Intercepts GET requests + * Intercepts REPORT requests * * @param RequestInterface $request * @param ResponseInterface $response @@ -57,103 +55,35 @@ public function initialize(Server $server) { public function httpGet(RequestInterface $request, ResponseInterface $response) { $queryParams = $request->getQueryParameters(); - - // check for post data validity - if (!array_key_exists('vcards', $queryParams) - || !is_array($queryParams['vcards'])) { - return true; + if (!array_key_exists('export', $queryParams)) { + return; } - // user addressbooks home - $path = $request->getPath(); - $paths = $queryParams['vcards']; - - // extract unique addressbooks from all the paths - $addressbookIDs = array_unique(array_map(function($path) { - return explode('/', $path)[0]; - }, $paths)); - - // valid addressbooks and the requested vcards - $addressbooks = []; - foreach ($addressbookIDs as $addressbook) { - $node = $this->server->tree->getNodeForPath("$path/$addressbook/"); - - // Checking ACL, if available. - if ($aclPlugin = $this->server->getPlugin('acl')) { - $aclPlugin->checkPrivileges("$path/$addressbook/", '{DAV:}read'); - } - - // checking that the path is a valid addressbook - if ($node instanceof AddressBook) { - $addressbooks = array_merge($addressbooks, [$addressbook => $vcards]); - } + // Only handling xml + $contentType = $response->getHeader('Content-Type'); + if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false) { + return; } - // array of vcard paths - $absolutePaths = array_map(function ($vcard) use ($path) { - return "$path/$vcard"; - }, $paths); - - $this->server->transactionType = 'vcf-multi-export'; - - // We do not need to check for other paths - // If one of the path is incorrect, it either - // 1. would have been thrown if the ab doesn't exists - // 2. will be ignored by the getMultipleNodes method - $nodes = $this->server->tree->getMultipleNodes($absolutePaths); - - $format = 'text/directory'; - - $output = null; - $filenameExtension = null; + $this->server->transactionType = 'vcf-multi-get-intercept-and-export'; - switch ($format) { - case 'text/directory': - $output = $this->generateVCF($nodes); - $filenameExtension = '.vcf'; - break; - } + // Get the xml response + $responseBody = $response->getBodyAsString(); + $responseXml = $this->server->xml->parse($responseBody); - $filename = preg_replace( - '/[^a-zA-Z0-9-_ ]/um', - '', - $node->getName() - ); - $filename .= '-' . date('Y-m-d') . $filenameExtension; + // Reduce the vcards into one string + $output = array_reduce($responseXml->getResponses(), function ($vcf, $card) { + $vcf .= $card->getResponseProperties()[200]['{urn:ietf:params:xml:ns:carddav}address-data']; + return $vcf; + }, ''); + // Build and override the response + $filename = 'vcfexport-' . date('Y-m-d') . $filenameExtension; $response->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"'); - $response->setHeader('Content-Type', $format); - - $response->setStatus(200); + $response->setHeader('Content-Type', 'text/directory'); $response->setBody($output); - // Returning false to break the event chain - return false; - } - - /** - * Merges all vcard objects, and builds one big vcf export - * - * @param array $nodes - * @return string - */ - private function generateVCF(array $nodes) { - $output = ''; - - foreach ($nodes as $node) { - - $nodeData = $node->get(); - - // Parsing this node so VObject can clean up the output. - $vcard = VObject\Reader::read($nodeData); - $output .= $vcard->serialize(); - - // Destroy circular references to PHP will GC the object. - $vcard->destroy(); - - } - - return $output; + return true; } /** @@ -165,7 +95,7 @@ private function generateVCF(array $nodes) { * @return string */ public function getPluginName() { - return 'vcf-multi-export'; + return 'vcf-multi-get-intercept-and-export'; } /** @@ -182,7 +112,7 @@ public function getPluginName() { public function getPluginInfo() { return [ 'name' => $this->getPluginName(), - 'description' => 'Adds the ability to export multiple vCard as a single vCard file.' + 'description' => 'Intercept a multi-get request and return a single vcf file instead.' ]; }