1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\CardDAV; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse Sabre\DAVACL; 6*a1a3b679SAndreas Boehleruse Sabre\DAV; 7*a1a3b679SAndreas Boehler 8*a1a3b679SAndreas Boehler/** 9*a1a3b679SAndreas Boehler * The Card object represents a single Card from an addressbook 10*a1a3b679SAndreas Boehler * 11*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 12*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 13*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 14*a1a3b679SAndreas Boehler */ 15*a1a3b679SAndreas Boehlerclass Card extends DAV\File implements ICard, DAVACL\IACL { 16*a1a3b679SAndreas Boehler 17*a1a3b679SAndreas Boehler /** 18*a1a3b679SAndreas Boehler * CardDAV backend 19*a1a3b679SAndreas Boehler * 20*a1a3b679SAndreas Boehler * @var Backend\BackendInterface 21*a1a3b679SAndreas Boehler */ 22*a1a3b679SAndreas Boehler protected $carddavBackend; 23*a1a3b679SAndreas Boehler 24*a1a3b679SAndreas Boehler /** 25*a1a3b679SAndreas Boehler * Array with information about this Card 26*a1a3b679SAndreas Boehler * 27*a1a3b679SAndreas Boehler * @var array 28*a1a3b679SAndreas Boehler */ 29*a1a3b679SAndreas Boehler protected $cardData; 30*a1a3b679SAndreas Boehler 31*a1a3b679SAndreas Boehler /** 32*a1a3b679SAndreas Boehler * Array with information about the containing addressbook 33*a1a3b679SAndreas Boehler * 34*a1a3b679SAndreas Boehler * @var array 35*a1a3b679SAndreas Boehler */ 36*a1a3b679SAndreas Boehler protected $addressBookInfo; 37*a1a3b679SAndreas Boehler 38*a1a3b679SAndreas Boehler /** 39*a1a3b679SAndreas Boehler * Constructor 40*a1a3b679SAndreas Boehler * 41*a1a3b679SAndreas Boehler * @param Backend\BackendInterface $carddavBackend 42*a1a3b679SAndreas Boehler * @param array $addressBookInfo 43*a1a3b679SAndreas Boehler * @param array $cardData 44*a1a3b679SAndreas Boehler */ 45*a1a3b679SAndreas Boehler function __construct(Backend\BackendInterface $carddavBackend, array $addressBookInfo, array $cardData) { 46*a1a3b679SAndreas Boehler 47*a1a3b679SAndreas Boehler $this->carddavBackend = $carddavBackend; 48*a1a3b679SAndreas Boehler $this->addressBookInfo = $addressBookInfo; 49*a1a3b679SAndreas Boehler $this->cardData = $cardData; 50*a1a3b679SAndreas Boehler 51*a1a3b679SAndreas Boehler } 52*a1a3b679SAndreas Boehler 53*a1a3b679SAndreas Boehler /** 54*a1a3b679SAndreas Boehler * Returns the uri for this object 55*a1a3b679SAndreas Boehler * 56*a1a3b679SAndreas Boehler * @return string 57*a1a3b679SAndreas Boehler */ 58*a1a3b679SAndreas Boehler function getName() { 59*a1a3b679SAndreas Boehler 60*a1a3b679SAndreas Boehler return $this->cardData['uri']; 61*a1a3b679SAndreas Boehler 62*a1a3b679SAndreas Boehler } 63*a1a3b679SAndreas Boehler 64*a1a3b679SAndreas Boehler /** 65*a1a3b679SAndreas Boehler * Returns the VCard-formatted object 66*a1a3b679SAndreas Boehler * 67*a1a3b679SAndreas Boehler * @return string 68*a1a3b679SAndreas Boehler */ 69*a1a3b679SAndreas Boehler function get() { 70*a1a3b679SAndreas Boehler 71*a1a3b679SAndreas Boehler // Pre-populating 'carddata' is optional. If we don't yet have it 72*a1a3b679SAndreas Boehler // already, we fetch it from the backend. 73*a1a3b679SAndreas Boehler if (!isset($this->cardData['carddata'])) { 74*a1a3b679SAndreas Boehler $this->cardData = $this->carddavBackend->getCard($this->addressBookInfo['id'], $this->cardData['uri']); 75*a1a3b679SAndreas Boehler } 76*a1a3b679SAndreas Boehler return $this->cardData['carddata']; 77*a1a3b679SAndreas Boehler 78*a1a3b679SAndreas Boehler } 79*a1a3b679SAndreas Boehler 80*a1a3b679SAndreas Boehler /** 81*a1a3b679SAndreas Boehler * Updates the VCard-formatted object 82*a1a3b679SAndreas Boehler * 83*a1a3b679SAndreas Boehler * @param string $cardData 84*a1a3b679SAndreas Boehler * @return string|null 85*a1a3b679SAndreas Boehler */ 86*a1a3b679SAndreas Boehler function put($cardData) { 87*a1a3b679SAndreas Boehler 88*a1a3b679SAndreas Boehler if (is_resource($cardData)) 89*a1a3b679SAndreas Boehler $cardData = stream_get_contents($cardData); 90*a1a3b679SAndreas Boehler 91*a1a3b679SAndreas Boehler // Converting to UTF-8, if needed 92*a1a3b679SAndreas Boehler $cardData = DAV\StringUtil::ensureUTF8($cardData); 93*a1a3b679SAndreas Boehler 94*a1a3b679SAndreas Boehler $etag = $this->carddavBackend->updateCard($this->addressBookInfo['id'], $this->cardData['uri'], $cardData); 95*a1a3b679SAndreas Boehler $this->cardData['carddata'] = $cardData; 96*a1a3b679SAndreas Boehler $this->cardData['etag'] = $etag; 97*a1a3b679SAndreas Boehler 98*a1a3b679SAndreas Boehler return $etag; 99*a1a3b679SAndreas Boehler 100*a1a3b679SAndreas Boehler } 101*a1a3b679SAndreas Boehler 102*a1a3b679SAndreas Boehler /** 103*a1a3b679SAndreas Boehler * Deletes the card 104*a1a3b679SAndreas Boehler * 105*a1a3b679SAndreas Boehler * @return void 106*a1a3b679SAndreas Boehler */ 107*a1a3b679SAndreas Boehler function delete() { 108*a1a3b679SAndreas Boehler 109*a1a3b679SAndreas Boehler $this->carddavBackend->deleteCard($this->addressBookInfo['id'], $this->cardData['uri']); 110*a1a3b679SAndreas Boehler 111*a1a3b679SAndreas Boehler } 112*a1a3b679SAndreas Boehler 113*a1a3b679SAndreas Boehler /** 114*a1a3b679SAndreas Boehler * Returns the mime content-type 115*a1a3b679SAndreas Boehler * 116*a1a3b679SAndreas Boehler * @return string 117*a1a3b679SAndreas Boehler */ 118*a1a3b679SAndreas Boehler function getContentType() { 119*a1a3b679SAndreas Boehler 120*a1a3b679SAndreas Boehler return 'text/vcard; charset=utf-8'; 121*a1a3b679SAndreas Boehler 122*a1a3b679SAndreas Boehler } 123*a1a3b679SAndreas Boehler 124*a1a3b679SAndreas Boehler /** 125*a1a3b679SAndreas Boehler * Returns an ETag for this object 126*a1a3b679SAndreas Boehler * 127*a1a3b679SAndreas Boehler * @return string 128*a1a3b679SAndreas Boehler */ 129*a1a3b679SAndreas Boehler function getETag() { 130*a1a3b679SAndreas Boehler 131*a1a3b679SAndreas Boehler if (isset($this->cardData['etag'])) { 132*a1a3b679SAndreas Boehler return $this->cardData['etag']; 133*a1a3b679SAndreas Boehler } else { 134*a1a3b679SAndreas Boehler $data = $this->get(); 135*a1a3b679SAndreas Boehler if (is_string($data)) { 136*a1a3b679SAndreas Boehler return '"' . md5($data) . '"'; 137*a1a3b679SAndreas Boehler } else { 138*a1a3b679SAndreas Boehler // We refuse to calculate the md5 if it's a stream. 139*a1a3b679SAndreas Boehler return null; 140*a1a3b679SAndreas Boehler } 141*a1a3b679SAndreas Boehler } 142*a1a3b679SAndreas Boehler 143*a1a3b679SAndreas Boehler } 144*a1a3b679SAndreas Boehler 145*a1a3b679SAndreas Boehler /** 146*a1a3b679SAndreas Boehler * Returns the last modification date as a unix timestamp 147*a1a3b679SAndreas Boehler * 148*a1a3b679SAndreas Boehler * @return int 149*a1a3b679SAndreas Boehler */ 150*a1a3b679SAndreas Boehler function getLastModified() { 151*a1a3b679SAndreas Boehler 152*a1a3b679SAndreas Boehler return isset($this->cardData['lastmodified']) ? $this->cardData['lastmodified'] : null; 153*a1a3b679SAndreas Boehler 154*a1a3b679SAndreas Boehler } 155*a1a3b679SAndreas Boehler 156*a1a3b679SAndreas Boehler /** 157*a1a3b679SAndreas Boehler * Returns the size of this object in bytes 158*a1a3b679SAndreas Boehler * 159*a1a3b679SAndreas Boehler * @return int 160*a1a3b679SAndreas Boehler */ 161*a1a3b679SAndreas Boehler function getSize() { 162*a1a3b679SAndreas Boehler 163*a1a3b679SAndreas Boehler if (array_key_exists('size', $this->cardData)) { 164*a1a3b679SAndreas Boehler return $this->cardData['size']; 165*a1a3b679SAndreas Boehler } else { 166*a1a3b679SAndreas Boehler return strlen($this->get()); 167*a1a3b679SAndreas Boehler } 168*a1a3b679SAndreas Boehler 169*a1a3b679SAndreas Boehler } 170*a1a3b679SAndreas Boehler 171*a1a3b679SAndreas Boehler /** 172*a1a3b679SAndreas Boehler * Returns the owner principal 173*a1a3b679SAndreas Boehler * 174*a1a3b679SAndreas Boehler * This must be a url to a principal, or null if there's no owner 175*a1a3b679SAndreas Boehler * 176*a1a3b679SAndreas Boehler * @return string|null 177*a1a3b679SAndreas Boehler */ 178*a1a3b679SAndreas Boehler function getOwner() { 179*a1a3b679SAndreas Boehler 180*a1a3b679SAndreas Boehler return $this->addressBookInfo['principaluri']; 181*a1a3b679SAndreas Boehler 182*a1a3b679SAndreas Boehler } 183*a1a3b679SAndreas Boehler 184*a1a3b679SAndreas Boehler /** 185*a1a3b679SAndreas Boehler * Returns a group principal 186*a1a3b679SAndreas Boehler * 187*a1a3b679SAndreas Boehler * This must be a url to a principal, or null if there's no owner 188*a1a3b679SAndreas Boehler * 189*a1a3b679SAndreas Boehler * @return string|null 190*a1a3b679SAndreas Boehler */ 191*a1a3b679SAndreas Boehler function getGroup() { 192*a1a3b679SAndreas Boehler 193*a1a3b679SAndreas Boehler return null; 194*a1a3b679SAndreas Boehler 195*a1a3b679SAndreas Boehler } 196*a1a3b679SAndreas Boehler 197*a1a3b679SAndreas Boehler /** 198*a1a3b679SAndreas Boehler * Returns a list of ACE's for this node. 199*a1a3b679SAndreas Boehler * 200*a1a3b679SAndreas Boehler * Each ACE has the following properties: 201*a1a3b679SAndreas Boehler * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are 202*a1a3b679SAndreas Boehler * currently the only supported privileges 203*a1a3b679SAndreas Boehler * * 'principal', a url to the principal who owns the node 204*a1a3b679SAndreas Boehler * * 'protected' (optional), indicating that this ACE is not allowed to 205*a1a3b679SAndreas Boehler * be updated. 206*a1a3b679SAndreas Boehler * 207*a1a3b679SAndreas Boehler * @return array 208*a1a3b679SAndreas Boehler */ 209*a1a3b679SAndreas Boehler function getACL() { 210*a1a3b679SAndreas Boehler 211*a1a3b679SAndreas Boehler // An alternative acl may be specified through the cardData array. 212*a1a3b679SAndreas Boehler if (isset($this->cardData['acl'])) { 213*a1a3b679SAndreas Boehler return $this->cardData['acl']; 214*a1a3b679SAndreas Boehler } 215*a1a3b679SAndreas Boehler 216*a1a3b679SAndreas Boehler return [ 217*a1a3b679SAndreas Boehler [ 218*a1a3b679SAndreas Boehler 'privilege' => '{DAV:}read', 219*a1a3b679SAndreas Boehler 'principal' => $this->addressBookInfo['principaluri'], 220*a1a3b679SAndreas Boehler 'protected' => true, 221*a1a3b679SAndreas Boehler ], 222*a1a3b679SAndreas Boehler [ 223*a1a3b679SAndreas Boehler 'privilege' => '{DAV:}write', 224*a1a3b679SAndreas Boehler 'principal' => $this->addressBookInfo['principaluri'], 225*a1a3b679SAndreas Boehler 'protected' => true, 226*a1a3b679SAndreas Boehler ], 227*a1a3b679SAndreas Boehler ]; 228*a1a3b679SAndreas Boehler 229*a1a3b679SAndreas Boehler } 230*a1a3b679SAndreas Boehler 231*a1a3b679SAndreas Boehler /** 232*a1a3b679SAndreas Boehler * Updates the ACL 233*a1a3b679SAndreas Boehler * 234*a1a3b679SAndreas Boehler * This method will receive a list of new ACE's. 235*a1a3b679SAndreas Boehler * 236*a1a3b679SAndreas Boehler * @param array $acl 237*a1a3b679SAndreas Boehler * @return void 238*a1a3b679SAndreas Boehler */ 239*a1a3b679SAndreas Boehler function setACL(array $acl) { 240*a1a3b679SAndreas Boehler 241*a1a3b679SAndreas Boehler throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); 242*a1a3b679SAndreas Boehler 243*a1a3b679SAndreas Boehler } 244*a1a3b679SAndreas Boehler 245*a1a3b679SAndreas Boehler /** 246*a1a3b679SAndreas Boehler * Returns the list of supported privileges for this node. 247*a1a3b679SAndreas Boehler * 248*a1a3b679SAndreas Boehler * The returned data structure is a list of nested privileges. 249*a1a3b679SAndreas Boehler * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple 250*a1a3b679SAndreas Boehler * standard structure. 251*a1a3b679SAndreas Boehler * 252*a1a3b679SAndreas Boehler * If null is returned from this method, the default privilege set is used, 253*a1a3b679SAndreas Boehler * which is fine for most common usecases. 254*a1a3b679SAndreas Boehler * 255*a1a3b679SAndreas Boehler * @return array|null 256*a1a3b679SAndreas Boehler */ 257*a1a3b679SAndreas Boehler function getSupportedPrivilegeSet() { 258*a1a3b679SAndreas Boehler 259*a1a3b679SAndreas Boehler return null; 260*a1a3b679SAndreas Boehler 261*a1a3b679SAndreas Boehler } 262*a1a3b679SAndreas Boehler 263*a1a3b679SAndreas Boehler} 264