xref: /plugin/davcal/vendor/sabre/dav/lib/CardDAV/VCFExportPlugin.php (revision a1a3b6794e0e143a4a8b51d3185ce2d339be61ab)
1*a1a3b679SAndreas Boehler<?php
2*a1a3b679SAndreas Boehler
3*a1a3b679SAndreas Boehlernamespace Sabre\CardDAV;
4*a1a3b679SAndreas Boehler
5*a1a3b679SAndreas Boehleruse Sabre\DAV;
6*a1a3b679SAndreas Boehleruse Sabre\VObject;
7*a1a3b679SAndreas Boehleruse Sabre\HTTP\RequestInterface;
8*a1a3b679SAndreas Boehleruse Sabre\HTTP\ResponseInterface;
9*a1a3b679SAndreas Boehler
10*a1a3b679SAndreas Boehler/**
11*a1a3b679SAndreas Boehler * VCF Exporter
12*a1a3b679SAndreas Boehler *
13*a1a3b679SAndreas Boehler * This plugin adds the ability to export entire address books as .vcf files.
14*a1a3b679SAndreas Boehler * This is useful for clients that don't support CardDAV yet. They often do
15*a1a3b679SAndreas Boehler * support vcf files.
16*a1a3b679SAndreas Boehler *
17*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
18*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/)
19*a1a3b679SAndreas Boehler * @author Thomas Tanghus (http://tanghus.net/)
20*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License
21*a1a3b679SAndreas Boehler */
22*a1a3b679SAndreas Boehlerclass VCFExportPlugin extends DAV\ServerPlugin {
23*a1a3b679SAndreas Boehler
24*a1a3b679SAndreas Boehler    /**
25*a1a3b679SAndreas Boehler     * Reference to Server class
26*a1a3b679SAndreas Boehler     *
27*a1a3b679SAndreas Boehler     * @var Sabre\DAV\Server
28*a1a3b679SAndreas Boehler     */
29*a1a3b679SAndreas Boehler    protected $server;
30*a1a3b679SAndreas Boehler
31*a1a3b679SAndreas Boehler    /**
32*a1a3b679SAndreas Boehler     * Initializes the plugin and registers event handlers
33*a1a3b679SAndreas Boehler     *
34*a1a3b679SAndreas Boehler     * @param DAV\Server $server
35*a1a3b679SAndreas Boehler     * @return void
36*a1a3b679SAndreas Boehler     */
37*a1a3b679SAndreas Boehler    function initialize(DAV\Server $server) {
38*a1a3b679SAndreas Boehler
39*a1a3b679SAndreas Boehler        $this->server = $server;
40*a1a3b679SAndreas Boehler        $this->server->on('method:GET', [$this, 'httpGet'], 90);
41*a1a3b679SAndreas Boehler        $server->on('browserButtonActions', function($path, $node, &$actions) {
42*a1a3b679SAndreas Boehler            if ($node instanceof IAddressBook) {
43*a1a3b679SAndreas Boehler                $actions .= '<a href="' . htmlspecialchars($path, ENT_QUOTES, 'UTF-8') . '?export"><span class="oi" data-glyph="book"></span></a>';
44*a1a3b679SAndreas Boehler            }
45*a1a3b679SAndreas Boehler        });
46*a1a3b679SAndreas Boehler    }
47*a1a3b679SAndreas Boehler
48*a1a3b679SAndreas Boehler    /**
49*a1a3b679SAndreas Boehler     * Intercepts GET requests on addressbook urls ending with ?export.
50*a1a3b679SAndreas Boehler     *
51*a1a3b679SAndreas Boehler     * @param RequestInterface $request
52*a1a3b679SAndreas Boehler     * @param ResponseInterface $response
53*a1a3b679SAndreas Boehler     * @return bool
54*a1a3b679SAndreas Boehler     */
55*a1a3b679SAndreas Boehler    function httpGet(RequestInterface $request, ResponseInterface $response) {
56*a1a3b679SAndreas Boehler
57*a1a3b679SAndreas Boehler        $queryParams = $request->getQueryParameters();
58*a1a3b679SAndreas Boehler        if (!array_key_exists('export', $queryParams)) return;
59*a1a3b679SAndreas Boehler
60*a1a3b679SAndreas Boehler        $path = $request->getPath();
61*a1a3b679SAndreas Boehler
62*a1a3b679SAndreas Boehler        $node = $this->server->tree->getNodeForPath($path);
63*a1a3b679SAndreas Boehler
64*a1a3b679SAndreas Boehler        if (!($node instanceof IAddressBook)) return;
65*a1a3b679SAndreas Boehler
66*a1a3b679SAndreas Boehler        $this->server->transactionType = 'get-addressbook-export';
67*a1a3b679SAndreas Boehler
68*a1a3b679SAndreas Boehler        // Checking ACL, if available.
69*a1a3b679SAndreas Boehler        if ($aclPlugin = $this->server->getPlugin('acl')) {
70*a1a3b679SAndreas Boehler            $aclPlugin->checkPrivileges($path, '{DAV:}read');
71*a1a3b679SAndreas Boehler        }
72*a1a3b679SAndreas Boehler
73*a1a3b679SAndreas Boehler        $response->setHeader('Content-Type', 'text/directory');
74*a1a3b679SAndreas Boehler        $response->setStatus(200);
75*a1a3b679SAndreas Boehler
76*a1a3b679SAndreas Boehler        $nodes = $this->server->getPropertiesForPath($path, [
77*a1a3b679SAndreas Boehler            '{' . Plugin::NS_CARDDAV . '}address-data',
78*a1a3b679SAndreas Boehler        ], 1);
79*a1a3b679SAndreas Boehler
80*a1a3b679SAndreas Boehler        $response->setBody($this->generateVCF($nodes));
81*a1a3b679SAndreas Boehler
82*a1a3b679SAndreas Boehler        // Returning false to break the event chain
83*a1a3b679SAndreas Boehler        return false;
84*a1a3b679SAndreas Boehler
85*a1a3b679SAndreas Boehler    }
86*a1a3b679SAndreas Boehler
87*a1a3b679SAndreas Boehler    /**
88*a1a3b679SAndreas Boehler     * Merges all vcard objects, and builds one big vcf export
89*a1a3b679SAndreas Boehler     *
90*a1a3b679SAndreas Boehler     * @param array $nodes
91*a1a3b679SAndreas Boehler     * @return string
92*a1a3b679SAndreas Boehler     */
93*a1a3b679SAndreas Boehler    function generateVCF(array $nodes) {
94*a1a3b679SAndreas Boehler
95*a1a3b679SAndreas Boehler        $output = "";
96*a1a3b679SAndreas Boehler
97*a1a3b679SAndreas Boehler        foreach ($nodes as $node) {
98*a1a3b679SAndreas Boehler
99*a1a3b679SAndreas Boehler            if (!isset($node[200]['{' . Plugin::NS_CARDDAV . '}address-data'])) {
100*a1a3b679SAndreas Boehler                continue;
101*a1a3b679SAndreas Boehler            }
102*a1a3b679SAndreas Boehler            $nodeData = $node[200]['{' . Plugin::NS_CARDDAV . '}address-data'];
103*a1a3b679SAndreas Boehler
104*a1a3b679SAndreas Boehler            // Parsing this node so VObject can clean up the output.
105*a1a3b679SAndreas Boehler            $output .=
106*a1a3b679SAndreas Boehler               VObject\Reader::read($nodeData)->serialize();
107*a1a3b679SAndreas Boehler
108*a1a3b679SAndreas Boehler        }
109*a1a3b679SAndreas Boehler
110*a1a3b679SAndreas Boehler        return $output;
111*a1a3b679SAndreas Boehler
112*a1a3b679SAndreas Boehler    }
113*a1a3b679SAndreas Boehler
114*a1a3b679SAndreas Boehler    /**
115*a1a3b679SAndreas Boehler     * Returns a plugin name.
116*a1a3b679SAndreas Boehler     *
117*a1a3b679SAndreas Boehler     * Using this name other plugins will be able to access other plugins
118*a1a3b679SAndreas Boehler     * using \Sabre\DAV\Server::getPlugin
119*a1a3b679SAndreas Boehler     *
120*a1a3b679SAndreas Boehler     * @return string
121*a1a3b679SAndreas Boehler     */
122*a1a3b679SAndreas Boehler    function getPluginName() {
123*a1a3b679SAndreas Boehler
124*a1a3b679SAndreas Boehler        return 'vcf-export';
125*a1a3b679SAndreas Boehler
126*a1a3b679SAndreas Boehler    }
127*a1a3b679SAndreas Boehler
128*a1a3b679SAndreas Boehler    /**
129*a1a3b679SAndreas Boehler     * Returns a bunch of meta-data about the plugin.
130*a1a3b679SAndreas Boehler     *
131*a1a3b679SAndreas Boehler     * Providing this information is optional, and is mainly displayed by the
132*a1a3b679SAndreas Boehler     * Browser plugin.
133*a1a3b679SAndreas Boehler     *
134*a1a3b679SAndreas Boehler     * The description key in the returned array may contain html and will not
135*a1a3b679SAndreas Boehler     * be sanitized.
136*a1a3b679SAndreas Boehler     *
137*a1a3b679SAndreas Boehler     * @return array
138*a1a3b679SAndreas Boehler     */
139*a1a3b679SAndreas Boehler    function getPluginInfo() {
140*a1a3b679SAndreas Boehler
141*a1a3b679SAndreas Boehler        return [
142*a1a3b679SAndreas Boehler            'name'        => $this->getPluginName(),
143*a1a3b679SAndreas Boehler            'description' => 'Adds the ability to export CardDAV addressbooks as a single vCard file.',
144*a1a3b679SAndreas Boehler            'link'        => 'http://sabre.io/dav/vcf-export-plugin/',
145*a1a3b679SAndreas Boehler        ];
146*a1a3b679SAndreas Boehler
147*a1a3b679SAndreas Boehler    }
148*a1a3b679SAndreas Boehler
149*a1a3b679SAndreas Boehler}
150