1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\CalDAV; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse Sabre\DAV; 6*a1a3b679SAndreas Boehleruse Sabre\DAV\Xml\Property\Href; 7*a1a3b679SAndreas Boehleruse Sabre\HTTP\RequestInterface; 8*a1a3b679SAndreas Boehleruse Sabre\HTTP\ResponseInterface; 9*a1a3b679SAndreas Boehler 10*a1a3b679SAndreas Boehler/** 11*a1a3b679SAndreas Boehler * This plugin implements support for caldav sharing. 12*a1a3b679SAndreas Boehler * 13*a1a3b679SAndreas Boehler * This spec is defined at: 14*a1a3b679SAndreas Boehler * http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk/doc/Extensions/caldav-sharing.txt 15*a1a3b679SAndreas Boehler * 16*a1a3b679SAndreas Boehler * See: 17*a1a3b679SAndreas Boehler * Sabre\CalDAV\Backend\SharingSupport for all the documentation. 18*a1a3b679SAndreas Boehler * 19*a1a3b679SAndreas Boehler * Note: This feature is experimental, and may change in between different 20*a1a3b679SAndreas Boehler * SabreDAV versions. 21*a1a3b679SAndreas Boehler * 22*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 23*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 24*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 25*a1a3b679SAndreas Boehler */ 26*a1a3b679SAndreas Boehlerclass SharingPlugin extends DAV\ServerPlugin { 27*a1a3b679SAndreas Boehler 28*a1a3b679SAndreas Boehler /** 29*a1a3b679SAndreas Boehler * These are the various status constants used by sharing-messages. 30*a1a3b679SAndreas Boehler */ 31*a1a3b679SAndreas Boehler const STATUS_ACCEPTED = 1; 32*a1a3b679SAndreas Boehler const STATUS_DECLINED = 2; 33*a1a3b679SAndreas Boehler const STATUS_DELETED = 3; 34*a1a3b679SAndreas Boehler const STATUS_NORESPONSE = 4; 35*a1a3b679SAndreas Boehler const STATUS_INVALID = 5; 36*a1a3b679SAndreas Boehler 37*a1a3b679SAndreas Boehler /** 38*a1a3b679SAndreas Boehler * Reference to SabreDAV server object. 39*a1a3b679SAndreas Boehler * 40*a1a3b679SAndreas Boehler * @var Sabre\DAV\Server 41*a1a3b679SAndreas Boehler */ 42*a1a3b679SAndreas Boehler protected $server; 43*a1a3b679SAndreas Boehler 44*a1a3b679SAndreas Boehler /** 45*a1a3b679SAndreas Boehler * This method should return a list of server-features. 46*a1a3b679SAndreas Boehler * 47*a1a3b679SAndreas Boehler * This is for example 'versioning' and is added to the DAV: header 48*a1a3b679SAndreas Boehler * in an OPTIONS response. 49*a1a3b679SAndreas Boehler * 50*a1a3b679SAndreas Boehler * @return array 51*a1a3b679SAndreas Boehler */ 52*a1a3b679SAndreas Boehler function getFeatures() { 53*a1a3b679SAndreas Boehler 54*a1a3b679SAndreas Boehler return ['calendarserver-sharing']; 55*a1a3b679SAndreas Boehler 56*a1a3b679SAndreas Boehler } 57*a1a3b679SAndreas Boehler 58*a1a3b679SAndreas Boehler /** 59*a1a3b679SAndreas Boehler * Returns a plugin name. 60*a1a3b679SAndreas Boehler * 61*a1a3b679SAndreas Boehler * Using this name other plugins will be able to access other plugins 62*a1a3b679SAndreas Boehler * using Sabre\DAV\Server::getPlugin 63*a1a3b679SAndreas Boehler * 64*a1a3b679SAndreas Boehler * @return string 65*a1a3b679SAndreas Boehler */ 66*a1a3b679SAndreas Boehler function getPluginName() { 67*a1a3b679SAndreas Boehler 68*a1a3b679SAndreas Boehler return 'caldav-sharing'; 69*a1a3b679SAndreas Boehler 70*a1a3b679SAndreas Boehler } 71*a1a3b679SAndreas Boehler 72*a1a3b679SAndreas Boehler /** 73*a1a3b679SAndreas Boehler * This initializes the plugin. 74*a1a3b679SAndreas Boehler * 75*a1a3b679SAndreas Boehler * This function is called by Sabre\DAV\Server, after 76*a1a3b679SAndreas Boehler * addPlugin is called. 77*a1a3b679SAndreas Boehler * 78*a1a3b679SAndreas Boehler * This method should set up the required event subscriptions. 79*a1a3b679SAndreas Boehler * 80*a1a3b679SAndreas Boehler * @param DAV\Server $server 81*a1a3b679SAndreas Boehler * @return void 82*a1a3b679SAndreas Boehler */ 83*a1a3b679SAndreas Boehler function initialize(DAV\Server $server) { 84*a1a3b679SAndreas Boehler 85*a1a3b679SAndreas Boehler $this->server = $server; 86*a1a3b679SAndreas Boehler $server->resourceTypeMapping['Sabre\\CalDAV\\ISharedCalendar'] = '{' . Plugin::NS_CALENDARSERVER . '}shared'; 87*a1a3b679SAndreas Boehler 88*a1a3b679SAndreas Boehler array_push( 89*a1a3b679SAndreas Boehler $this->server->protectedProperties, 90*a1a3b679SAndreas Boehler '{' . Plugin::NS_CALENDARSERVER . '}invite', 91*a1a3b679SAndreas Boehler '{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes', 92*a1a3b679SAndreas Boehler '{' . Plugin::NS_CALENDARSERVER . '}shared-url' 93*a1a3b679SAndreas Boehler ); 94*a1a3b679SAndreas Boehler 95*a1a3b679SAndreas Boehler $this->server->xml->elementMap['{' . Plugin::NS_CALENDARSERVER . '}share'] = 'Sabre\\CalDAV\\Xml\\Request\\Share'; 96*a1a3b679SAndreas Boehler $this->server->xml->elementMap['{' . Plugin::NS_CALENDARSERVER . '}invite-reply'] = 'Sabre\\CalDAV\\Xml\\Request\\InviteReply'; 97*a1a3b679SAndreas Boehler 98*a1a3b679SAndreas Boehler $this->server->on('propFind', [$this, 'propFindEarly']); 99*a1a3b679SAndreas Boehler $this->server->on('propFind', [$this, 'propFindLate'], 150); 100*a1a3b679SAndreas Boehler $this->server->on('propPatch', [$this, 'propPatch'], 40); 101*a1a3b679SAndreas Boehler $this->server->on('method:POST', [$this, 'httpPost']); 102*a1a3b679SAndreas Boehler 103*a1a3b679SAndreas Boehler } 104*a1a3b679SAndreas Boehler 105*a1a3b679SAndreas Boehler /** 106*a1a3b679SAndreas Boehler * This event is triggered when properties are requested for a certain 107*a1a3b679SAndreas Boehler * node. 108*a1a3b679SAndreas Boehler * 109*a1a3b679SAndreas Boehler * This allows us to inject any properties early. 110*a1a3b679SAndreas Boehler * 111*a1a3b679SAndreas Boehler * @param DAV\PropFind $propFind 112*a1a3b679SAndreas Boehler * @param DAV\INode $node 113*a1a3b679SAndreas Boehler * @return void 114*a1a3b679SAndreas Boehler */ 115*a1a3b679SAndreas Boehler function propFindEarly(DAV\PropFind $propFind, DAV\INode $node) { 116*a1a3b679SAndreas Boehler 117*a1a3b679SAndreas Boehler if ($node instanceof IShareableCalendar) { 118*a1a3b679SAndreas Boehler 119*a1a3b679SAndreas Boehler $propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}invite', function() use ($node) { 120*a1a3b679SAndreas Boehler return new Xml\Property\Invite( 121*a1a3b679SAndreas Boehler $node->getShares() 122*a1a3b679SAndreas Boehler ); 123*a1a3b679SAndreas Boehler }); 124*a1a3b679SAndreas Boehler 125*a1a3b679SAndreas Boehler } 126*a1a3b679SAndreas Boehler 127*a1a3b679SAndreas Boehler if ($node instanceof ISharedCalendar) { 128*a1a3b679SAndreas Boehler 129*a1a3b679SAndreas Boehler $propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}shared-url', function() use ($node) { 130*a1a3b679SAndreas Boehler return new Href( 131*a1a3b679SAndreas Boehler $node->getSharedUrl() 132*a1a3b679SAndreas Boehler ); 133*a1a3b679SAndreas Boehler }); 134*a1a3b679SAndreas Boehler 135*a1a3b679SAndreas Boehler $propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}invite', function() use ($node) { 136*a1a3b679SAndreas Boehler 137*a1a3b679SAndreas Boehler // Fetching owner information 138*a1a3b679SAndreas Boehler $props = $this->server->getPropertiesForPath($node->getOwner(), [ 139*a1a3b679SAndreas Boehler '{http://sabredav.org/ns}email-address', 140*a1a3b679SAndreas Boehler '{DAV:}displayname', 141*a1a3b679SAndreas Boehler ], 0); 142*a1a3b679SAndreas Boehler 143*a1a3b679SAndreas Boehler $ownerInfo = [ 144*a1a3b679SAndreas Boehler 'href' => $node->getOwner(), 145*a1a3b679SAndreas Boehler ]; 146*a1a3b679SAndreas Boehler 147*a1a3b679SAndreas Boehler if (isset($props[0][200])) { 148*a1a3b679SAndreas Boehler 149*a1a3b679SAndreas Boehler // We're mapping the internal webdav properties to the 150*a1a3b679SAndreas Boehler // elements caldav-sharing expects. 151*a1a3b679SAndreas Boehler if (isset($props[0][200]['{http://sabredav.org/ns}email-address'])) { 152*a1a3b679SAndreas Boehler $ownerInfo['href'] = 'mailto:' . $props[0][200]['{http://sabredav.org/ns}email-address']; 153*a1a3b679SAndreas Boehler } 154*a1a3b679SAndreas Boehler if (isset($props[0][200]['{DAV:}displayname'])) { 155*a1a3b679SAndreas Boehler $ownerInfo['commonName'] = $props[0][200]['{DAV:}displayname']; 156*a1a3b679SAndreas Boehler } 157*a1a3b679SAndreas Boehler 158*a1a3b679SAndreas Boehler } 159*a1a3b679SAndreas Boehler 160*a1a3b679SAndreas Boehler return new Xml\Property\Invite( 161*a1a3b679SAndreas Boehler $node->getShares(), 162*a1a3b679SAndreas Boehler $ownerInfo 163*a1a3b679SAndreas Boehler ); 164*a1a3b679SAndreas Boehler 165*a1a3b679SAndreas Boehler }); 166*a1a3b679SAndreas Boehler 167*a1a3b679SAndreas Boehler } 168*a1a3b679SAndreas Boehler 169*a1a3b679SAndreas Boehler } 170*a1a3b679SAndreas Boehler 171*a1a3b679SAndreas Boehler /** 172*a1a3b679SAndreas Boehler * This method is triggered *after* all properties have been retrieved. 173*a1a3b679SAndreas Boehler * This allows us to inject the correct resourcetype for calendars that 174*a1a3b679SAndreas Boehler * have been shared. 175*a1a3b679SAndreas Boehler * 176*a1a3b679SAndreas Boehler * @param DAV\PropFind $propFind 177*a1a3b679SAndreas Boehler * @param DAV\INode $node 178*a1a3b679SAndreas Boehler * @return void 179*a1a3b679SAndreas Boehler */ 180*a1a3b679SAndreas Boehler function propFindLate(DAV\PropFind $propFind, DAV\INode $node) { 181*a1a3b679SAndreas Boehler 182*a1a3b679SAndreas Boehler if ($node instanceof IShareableCalendar) { 183*a1a3b679SAndreas Boehler if ($rt = $propFind->get('{DAV:}resourcetype')) { 184*a1a3b679SAndreas Boehler if (count($node->getShares()) > 0) { 185*a1a3b679SAndreas Boehler $rt->add('{' . Plugin::NS_CALENDARSERVER . '}shared-owner'); 186*a1a3b679SAndreas Boehler } 187*a1a3b679SAndreas Boehler } 188*a1a3b679SAndreas Boehler $propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes', function() { 189*a1a3b679SAndreas Boehler return new Xml\Property\AllowedSharingModes(true, false); 190*a1a3b679SAndreas Boehler }); 191*a1a3b679SAndreas Boehler 192*a1a3b679SAndreas Boehler } 193*a1a3b679SAndreas Boehler 194*a1a3b679SAndreas Boehler } 195*a1a3b679SAndreas Boehler 196*a1a3b679SAndreas Boehler /** 197*a1a3b679SAndreas Boehler * This method is trigged when a user attempts to update a node's 198*a1a3b679SAndreas Boehler * properties. 199*a1a3b679SAndreas Boehler * 200*a1a3b679SAndreas Boehler * A previous draft of the sharing spec stated that it was possible to use 201*a1a3b679SAndreas Boehler * PROPPATCH to remove 'shared-owner' from the resourcetype, thus unsharing 202*a1a3b679SAndreas Boehler * the calendar. 203*a1a3b679SAndreas Boehler * 204*a1a3b679SAndreas Boehler * Even though this is no longer in the current spec, we keep this around 205*a1a3b679SAndreas Boehler * because OS X 10.7 may still make use of this feature. 206*a1a3b679SAndreas Boehler * 207*a1a3b679SAndreas Boehler * @param string $path 208*a1a3b679SAndreas Boehler * @param DAV\PropPatch $propPatch 209*a1a3b679SAndreas Boehler * @return void 210*a1a3b679SAndreas Boehler */ 211*a1a3b679SAndreas Boehler function propPatch($path, DAV\PropPatch $propPatch) { 212*a1a3b679SAndreas Boehler 213*a1a3b679SAndreas Boehler $node = $this->server->tree->getNodeForPath($path); 214*a1a3b679SAndreas Boehler if (!$node instanceof IShareableCalendar) 215*a1a3b679SAndreas Boehler return; 216*a1a3b679SAndreas Boehler 217*a1a3b679SAndreas Boehler $propPatch->handle('{DAV:}resourcetype', function($value) use ($node) { 218*a1a3b679SAndreas Boehler if ($value->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return false; 219*a1a3b679SAndreas Boehler $shares = $node->getShares(); 220*a1a3b679SAndreas Boehler $remove = []; 221*a1a3b679SAndreas Boehler foreach ($shares as $share) { 222*a1a3b679SAndreas Boehler $remove[] = $share['href']; 223*a1a3b679SAndreas Boehler } 224*a1a3b679SAndreas Boehler $node->updateShares([], $remove); 225*a1a3b679SAndreas Boehler 226*a1a3b679SAndreas Boehler return true; 227*a1a3b679SAndreas Boehler 228*a1a3b679SAndreas Boehler }); 229*a1a3b679SAndreas Boehler 230*a1a3b679SAndreas Boehler } 231*a1a3b679SAndreas Boehler 232*a1a3b679SAndreas Boehler /** 233*a1a3b679SAndreas Boehler * We intercept this to handle POST requests on calendars. 234*a1a3b679SAndreas Boehler * 235*a1a3b679SAndreas Boehler * @param RequestInterface $request 236*a1a3b679SAndreas Boehler * @param ResponseInterface $response 237*a1a3b679SAndreas Boehler * @return null|bool 238*a1a3b679SAndreas Boehler */ 239*a1a3b679SAndreas Boehler function httpPost(RequestInterface $request, ResponseInterface $response) { 240*a1a3b679SAndreas Boehler 241*a1a3b679SAndreas Boehler $path = $request->getPath(); 242*a1a3b679SAndreas Boehler 243*a1a3b679SAndreas Boehler // Only handling xml 244*a1a3b679SAndreas Boehler $contentType = $request->getHeader('Content-Type'); 245*a1a3b679SAndreas Boehler if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false) 246*a1a3b679SAndreas Boehler return; 247*a1a3b679SAndreas Boehler 248*a1a3b679SAndreas Boehler // Making sure the node exists 249*a1a3b679SAndreas Boehler try { 250*a1a3b679SAndreas Boehler $node = $this->server->tree->getNodeForPath($path); 251*a1a3b679SAndreas Boehler } catch (DAV\Exception\NotFound $e) { 252*a1a3b679SAndreas Boehler return; 253*a1a3b679SAndreas Boehler } 254*a1a3b679SAndreas Boehler 255*a1a3b679SAndreas Boehler $requestBody = $request->getBodyAsString(); 256*a1a3b679SAndreas Boehler 257*a1a3b679SAndreas Boehler // If this request handler could not deal with this POST request, it 258*a1a3b679SAndreas Boehler // will return 'null' and other plugins get a chance to handle the 259*a1a3b679SAndreas Boehler // request. 260*a1a3b679SAndreas Boehler // 261*a1a3b679SAndreas Boehler // However, we already requested the full body. This is a problem, 262*a1a3b679SAndreas Boehler // because a body can only be read once. This is why we preemptively 263*a1a3b679SAndreas Boehler // re-populated the request body with the existing data. 264*a1a3b679SAndreas Boehler $request->setBody($requestBody); 265*a1a3b679SAndreas Boehler 266*a1a3b679SAndreas Boehler $message = $this->server->xml->parse($requestBody, $request->getUrl(), $documentType); 267*a1a3b679SAndreas Boehler 268*a1a3b679SAndreas Boehler switch ($documentType) { 269*a1a3b679SAndreas Boehler 270*a1a3b679SAndreas Boehler // Dealing with the 'share' document, which modified invitees on a 271*a1a3b679SAndreas Boehler // calendar. 272*a1a3b679SAndreas Boehler case '{' . Plugin::NS_CALENDARSERVER . '}share' : 273*a1a3b679SAndreas Boehler 274*a1a3b679SAndreas Boehler // We can only deal with IShareableCalendar objects 275*a1a3b679SAndreas Boehler if (!$node instanceof IShareableCalendar) { 276*a1a3b679SAndreas Boehler return; 277*a1a3b679SAndreas Boehler } 278*a1a3b679SAndreas Boehler 279*a1a3b679SAndreas Boehler $this->server->transactionType = 'post-calendar-share'; 280*a1a3b679SAndreas Boehler 281*a1a3b679SAndreas Boehler // Getting ACL info 282*a1a3b679SAndreas Boehler $acl = $this->server->getPlugin('acl'); 283*a1a3b679SAndreas Boehler 284*a1a3b679SAndreas Boehler // If there's no ACL support, we allow everything 285*a1a3b679SAndreas Boehler if ($acl) { 286*a1a3b679SAndreas Boehler $acl->checkPrivileges($path, '{DAV:}write'); 287*a1a3b679SAndreas Boehler } 288*a1a3b679SAndreas Boehler 289*a1a3b679SAndreas Boehler $node->updateShares($message->set, $message->remove); 290*a1a3b679SAndreas Boehler 291*a1a3b679SAndreas Boehler $response->setStatus(200); 292*a1a3b679SAndreas Boehler // Adding this because sending a response body may cause issues, 293*a1a3b679SAndreas Boehler // and I wanted some type of indicator the response was handled. 294*a1a3b679SAndreas Boehler $response->setHeader('X-Sabre-Status', 'everything-went-well'); 295*a1a3b679SAndreas Boehler 296*a1a3b679SAndreas Boehler // Breaking the event chain 297*a1a3b679SAndreas Boehler return false; 298*a1a3b679SAndreas Boehler 299*a1a3b679SAndreas Boehler // The invite-reply document is sent when the user replies to an 300*a1a3b679SAndreas Boehler // invitation of a calendar share. 301*a1a3b679SAndreas Boehler case '{' . Plugin::NS_CALENDARSERVER . '}invite-reply' : 302*a1a3b679SAndreas Boehler 303*a1a3b679SAndreas Boehler // This only works on the calendar-home-root node. 304*a1a3b679SAndreas Boehler if (!$node instanceof CalendarHome) { 305*a1a3b679SAndreas Boehler return; 306*a1a3b679SAndreas Boehler } 307*a1a3b679SAndreas Boehler $this->server->transactionType = 'post-invite-reply'; 308*a1a3b679SAndreas Boehler 309*a1a3b679SAndreas Boehler // Getting ACL info 310*a1a3b679SAndreas Boehler $acl = $this->server->getPlugin('acl'); 311*a1a3b679SAndreas Boehler 312*a1a3b679SAndreas Boehler // If there's no ACL support, we allow everything 313*a1a3b679SAndreas Boehler if ($acl) { 314*a1a3b679SAndreas Boehler $acl->checkPrivileges($path, '{DAV:}write'); 315*a1a3b679SAndreas Boehler } 316*a1a3b679SAndreas Boehler 317*a1a3b679SAndreas Boehler $url = $node->shareReply( 318*a1a3b679SAndreas Boehler $message->href, 319*a1a3b679SAndreas Boehler $message->status, 320*a1a3b679SAndreas Boehler $message->calendarUri, 321*a1a3b679SAndreas Boehler $message->inReplyTo, 322*a1a3b679SAndreas Boehler $message->summary 323*a1a3b679SAndreas Boehler ); 324*a1a3b679SAndreas Boehler 325*a1a3b679SAndreas Boehler $response->setStatus(200); 326*a1a3b679SAndreas Boehler // Adding this because sending a response body may cause issues, 327*a1a3b679SAndreas Boehler // and I wanted some type of indicator the response was handled. 328*a1a3b679SAndreas Boehler $response->setHeader('X-Sabre-Status', 'everything-went-well'); 329*a1a3b679SAndreas Boehler 330*a1a3b679SAndreas Boehler if ($url) { 331*a1a3b679SAndreas Boehler $writer = $this->server->xml->getWriter($this->server->getBaseUri()); 332*a1a3b679SAndreas Boehler $writer->openMemory(); 333*a1a3b679SAndreas Boehler $writer->startDocument(); 334*a1a3b679SAndreas Boehler $writer->startElement('{' . Plugin::NS_CALENDARSERVER . '}shared-as'); 335*a1a3b679SAndreas Boehler $writer->write(new Href($url)); 336*a1a3b679SAndreas Boehler $writer->endElement(); 337*a1a3b679SAndreas Boehler $response->setHeader('Content-Type', 'application/xml'); 338*a1a3b679SAndreas Boehler $response->setBody($writer->outputMemory()); 339*a1a3b679SAndreas Boehler 340*a1a3b679SAndreas Boehler } 341*a1a3b679SAndreas Boehler 342*a1a3b679SAndreas Boehler // Breaking the event chain 343*a1a3b679SAndreas Boehler return false; 344*a1a3b679SAndreas Boehler 345*a1a3b679SAndreas Boehler case '{' . Plugin::NS_CALENDARSERVER . '}publish-calendar' : 346*a1a3b679SAndreas Boehler 347*a1a3b679SAndreas Boehler // We can only deal with IShareableCalendar objects 348*a1a3b679SAndreas Boehler if (!$node instanceof IShareableCalendar) { 349*a1a3b679SAndreas Boehler return; 350*a1a3b679SAndreas Boehler } 351*a1a3b679SAndreas Boehler $this->server->transactionType = 'post-publish-calendar'; 352*a1a3b679SAndreas Boehler 353*a1a3b679SAndreas Boehler // Getting ACL info 354*a1a3b679SAndreas Boehler $acl = $this->server->getPlugin('acl'); 355*a1a3b679SAndreas Boehler 356*a1a3b679SAndreas Boehler // If there's no ACL support, we allow everything 357*a1a3b679SAndreas Boehler if ($acl) { 358*a1a3b679SAndreas Boehler $acl->checkPrivileges($path, '{DAV:}write'); 359*a1a3b679SAndreas Boehler } 360*a1a3b679SAndreas Boehler 361*a1a3b679SAndreas Boehler $node->setPublishStatus(true); 362*a1a3b679SAndreas Boehler 363*a1a3b679SAndreas Boehler // iCloud sends back the 202, so we will too. 364*a1a3b679SAndreas Boehler $response->setStatus(202); 365*a1a3b679SAndreas Boehler 366*a1a3b679SAndreas Boehler // Adding this because sending a response body may cause issues, 367*a1a3b679SAndreas Boehler // and I wanted some type of indicator the response was handled. 368*a1a3b679SAndreas Boehler $response->setHeader('X-Sabre-Status', 'everything-went-well'); 369*a1a3b679SAndreas Boehler 370*a1a3b679SAndreas Boehler // Breaking the event chain 371*a1a3b679SAndreas Boehler return false; 372*a1a3b679SAndreas Boehler 373*a1a3b679SAndreas Boehler case '{' . Plugin::NS_CALENDARSERVER . '}unpublish-calendar' : 374*a1a3b679SAndreas Boehler 375*a1a3b679SAndreas Boehler // We can only deal with IShareableCalendar objects 376*a1a3b679SAndreas Boehler if (!$node instanceof IShareableCalendar) { 377*a1a3b679SAndreas Boehler return; 378*a1a3b679SAndreas Boehler } 379*a1a3b679SAndreas Boehler $this->server->transactionType = 'post-unpublish-calendar'; 380*a1a3b679SAndreas Boehler 381*a1a3b679SAndreas Boehler // Getting ACL info 382*a1a3b679SAndreas Boehler $acl = $this->server->getPlugin('acl'); 383*a1a3b679SAndreas Boehler 384*a1a3b679SAndreas Boehler // If there's no ACL support, we allow everything 385*a1a3b679SAndreas Boehler if ($acl) { 386*a1a3b679SAndreas Boehler $acl->checkPrivileges($path, '{DAV:}write'); 387*a1a3b679SAndreas Boehler } 388*a1a3b679SAndreas Boehler 389*a1a3b679SAndreas Boehler $node->setPublishStatus(false); 390*a1a3b679SAndreas Boehler 391*a1a3b679SAndreas Boehler $response->setStatus(200); 392*a1a3b679SAndreas Boehler 393*a1a3b679SAndreas Boehler // Adding this because sending a response body may cause issues, 394*a1a3b679SAndreas Boehler // and I wanted some type of indicator the response was handled. 395*a1a3b679SAndreas Boehler $response->setHeader('X-Sabre-Status', 'everything-went-well'); 396*a1a3b679SAndreas Boehler 397*a1a3b679SAndreas Boehler // Breaking the event chain 398*a1a3b679SAndreas Boehler return false; 399*a1a3b679SAndreas Boehler 400*a1a3b679SAndreas Boehler } 401*a1a3b679SAndreas Boehler 402*a1a3b679SAndreas Boehler 403*a1a3b679SAndreas Boehler 404*a1a3b679SAndreas Boehler } 405*a1a3b679SAndreas Boehler 406*a1a3b679SAndreas Boehler /** 407*a1a3b679SAndreas Boehler * Returns a bunch of meta-data about the plugin. 408*a1a3b679SAndreas Boehler * 409*a1a3b679SAndreas Boehler * Providing this information is optional, and is mainly displayed by the 410*a1a3b679SAndreas Boehler * Browser plugin. 411*a1a3b679SAndreas Boehler * 412*a1a3b679SAndreas Boehler * The description key in the returned array may contain html and will not 413*a1a3b679SAndreas Boehler * be sanitized. 414*a1a3b679SAndreas Boehler * 415*a1a3b679SAndreas Boehler * @return array 416*a1a3b679SAndreas Boehler */ 417*a1a3b679SAndreas Boehler function getPluginInfo() { 418*a1a3b679SAndreas Boehler 419*a1a3b679SAndreas Boehler return [ 420*a1a3b679SAndreas Boehler 'name' => $this->getPluginName(), 421*a1a3b679SAndreas Boehler 'description' => 'Adds support for caldav-sharing.', 422*a1a3b679SAndreas Boehler 'link' => 'http://sabre.io/dav/caldav-sharing/', 423*a1a3b679SAndreas Boehler ]; 424*a1a3b679SAndreas Boehler 425*a1a3b679SAndreas Boehler } 426*a1a3b679SAndreas Boehler} 427