1<?php
2
3namespace Sabre\CalDAV\Notifications;
4
5use Sabre\DAV;
6use Sabre\DAV\INode as BaseINode;
7use Sabre\DAV\PropFind;
8use Sabre\DAV\Server;
9use Sabre\DAV\ServerPlugin;
10use Sabre\DAVACL;
11use Sabre\HTTP\RequestInterface;
12use Sabre\HTTP\ResponseInterface;
13
14/**
15 * Notifications plugin
16 *
17 * This plugin implements several features required by the caldav-notification
18 * draft specification.
19 *
20 * Before version 2.1.0 this functionality was part of Sabre\CalDAV\Plugin but
21 * this has since been split up.
22 *
23 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
24 * @author Evert Pot (http://evertpot.com/)
25 * @license http://sabre.io/license/ Modified BSD License
26 */
27class Plugin extends ServerPlugin {
28
29    /**
30     * This is the namespace for the proprietary calendarserver extensions
31     */
32    const NS_CALENDARSERVER = 'http://calendarserver.org/ns/';
33
34    /**
35     * Reference to the main server object.
36     *
37     * @var Server
38     */
39    protected $server;
40
41    /**
42     * Returns a plugin name.
43     *
44     * Using this name other plugins will be able to access other plugins
45     * using \Sabre\DAV\Server::getPlugin
46     *
47     * @return string
48     */
49    function getPluginName() {
50
51        return 'notifications';
52
53    }
54
55    /**
56     * This initializes the plugin.
57     *
58     * This function is called by Sabre\DAV\Server, after
59     * addPlugin is called.
60     *
61     * This method should set up the required event subscriptions.
62     *
63     * @param Server $server
64     * @return void
65     */
66    function initialize(Server $server) {
67
68        $this->server = $server;
69        $server->on('method:GET', [$this, 'httpGet'], 90);
70        $server->on('propFind',   [$this, 'propFind']);
71
72        $server->xml->namespaceMap[self::NS_CALENDARSERVER] = 'cs';
73        $server->resourceTypeMapping['\\Sabre\\CalDAV\\Notifications\\ICollection'] = '{' . self::NS_CALENDARSERVER . '}notification';
74
75        array_push($server->protectedProperties,
76            '{' . self::NS_CALENDARSERVER . '}notification-URL',
77            '{' . self::NS_CALENDARSERVER . '}notificationtype'
78        );
79
80    }
81
82    /**
83     * PropFind
84     *
85     * @param PropFind $propFind
86     * @param BaseINode $node
87     * @return void
88     */
89    function propFind(PropFind $propFind, BaseINode $node) {
90
91        $caldavPlugin = $this->server->getPlugin('caldav');
92
93        if ($node instanceof DAVACL\IPrincipal) {
94
95            $principalUrl = $node->getPrincipalUrl();
96
97            // notification-URL property
98            $propFind->handle('{' . self::NS_CALENDARSERVER . '}notification-URL', function() use ($principalUrl, $caldavPlugin) {
99
100                $notificationPath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl) . '/notifications/';
101                return new DAV\Xml\Property\Href($notificationPath);
102
103            });
104
105        }
106
107        if ($node instanceof INode) {
108
109            $propFind->handle(
110                '{' . self::NS_CALENDARSERVER . '}notificationtype',
111                [$node, 'getNotificationType']
112            );
113
114        }
115
116    }
117
118    /**
119     * This event is triggered before the usual GET request handler.
120     *
121     * We use this to intercept GET calls to notification nodes, and return the
122     * proper response.
123     *
124     * @param RequestInterface $request
125     * @param ResponseInterface $response
126     * @return void
127     */
128    function httpGet(RequestInterface $request, ResponseInterface $response) {
129
130        $path = $request->getPath();
131
132        try {
133            $node = $this->server->tree->getNodeForPath($path);
134        } catch (DAV\Exception\NotFound $e) {
135            return;
136        }
137
138        if (!$node instanceof INode)
139            return;
140
141        $writer = $this->server->xml->getWriter();
142        $writer->contextUri = $this->server->getBaseUri();
143        $writer->openMemory();
144        $writer->startDocument('1.0', 'UTF-8');
145        $writer->startElement('{http://calendarserver.org/ns/}notification');
146        $node->getNotificationType()->xmlSerializeFull($writer);
147        $writer->endElement();
148
149        $response->setHeader('Content-Type', 'application/xml');
150        $response->setHeader('ETag', $node->getETag());
151        $response->setStatus(200);
152        $response->setBody($writer->outputMemory());
153
154        // Return false to break the event chain.
155        return false;
156
157    }
158
159    /**
160     * Returns a bunch of meta-data about the plugin.
161     *
162     * Providing this information is optional, and is mainly displayed by the
163     * Browser plugin.
164     *
165     * The description key in the returned array may contain html and will not
166     * be sanitized.
167     *
168     * @return array
169     */
170    function getPluginInfo() {
171
172        return [
173            'name'        => $this->getPluginName(),
174            'description' => 'Adds support for caldav-notifications, which is required to enable caldav-sharing.',
175            'link'        => 'http://sabre.io/dav/caldav-sharing/',
176        ];
177
178    }
179
180}
181