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