]> git.mxchange.org Git - friendica-addons.git/blob - dav/dav_carddav_backend_virtual_friendica.inc.php
Merge branch 'master' of git://github.com/friendica/friendica-addons
[friendica-addons.git] / dav / dav_carddav_backend_virtual_friendica.inc.php
1 <?php
2
3 class Sabre_CardDAV_Backend_FriendicaCommunity extends Sabre_CardDAV_Backend_Abstract
4 {
5
6         /**
7          * @var null|Sabre_CardDAV_Backend_FriendicaCommunity
8          */
9         private static $instance = null;
10
11         /**
12          * @static
13          * @return Sabre_CardDAV_Backend_FriendicaCommunity
14          */
15         public static function getInstance() {
16                 if (self::$instance == null) {
17                         self::$instance = new Sabre_CardDAV_Backend_FriendicaCommunity();
18                 }
19                 return self::$instance;
20         }
21
22         /**
23          * Sets up the object
24          */
25         public function __construct()
26         {
27
28         }
29
30         /**
31          * Returns the list of addressbooks for a specific user.
32          *
33          * @param string $principalUri
34          * @return array
35          */
36         public function getAddressBooksForUser($principalUri)
37         {
38                 $uid = dav_compat_principal2uid($principalUri);
39
40                 $addressBooks = array();
41
42                 $books = q("SELECT ctag FROM %s%saddressbooks_community WHERE uid = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid));
43                 if (count($books) == 0) {
44                         q("INSERT INTO %s%saddressbooks_community (uid, ctag) VALUES (%d, 1)", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid));
45                         $ctag = 1;
46                 } else {
47                         $ctag = $books[0]["ctag"];
48                 }
49                 $addressBooks[] = array(
50                         'id'                                                                => CARDDAV_NAMESPACE_COMMUNITYCONTACTS . "-" . $uid,
51                         'uri'                                                               => "friendica",
52                         'principaluri'                                                      => $principalUri,
53                         '{DAV:}displayname'                                                 => t("Friendica-Contacts"),
54                         '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => t("Your Friendica-Contacts"),
55                         '{http://calendarserver.org/ns/}getctag'                            => $ctag,
56                         '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}supported-address-data'  =>
57                         new Sabre_CardDAV_Property_SupportedAddressData(),
58                 );
59
60                 return $addressBooks;
61
62         }
63
64
65         /**
66          * Updates an addressbook's properties
67          *
68          * See Sabre_DAV_IProperties for a description of the mutations array, as
69          * well as the return value.
70          *
71          * @param string $addressBookId
72          * @param array $mutations
73          * @throws Sabre_DAV_Exception_Forbidden
74          * @see Sabre_DAV_IProperties::updateProperties
75          * @return bool|array
76          */
77         public function updateAddressBook($addressBookId, array $mutations)
78         {
79                 throw new Sabre_DAV_Exception_Forbidden();
80         }
81
82         /**
83          * Creates a new address book
84          *
85          * @param string $principalUri
86          * @param string $url Just the 'basename' of the url.
87          * @param array $properties
88          * @throws Sabre_DAV_Exception_Forbidden
89          * @return void
90          */
91         public function createAddressBook($principalUri, $url, array $properties)
92         {
93                 throw new Sabre_DAV_Exception_Forbidden();
94         }
95
96         /**
97          * Deletes an entire addressbook and all its contents
98          *
99          * @param int $addressBookId
100          * @throws Sabre_DAV_Exception_Forbidden
101          * @return void
102          */
103         public function deleteAddressBook($addressBookId)
104         {
105                 throw new Sabre_DAV_Exception_Forbidden();
106         }
107
108
109         /**
110          * @param array $contact
111          * @return array
112          */
113         private function dav_contactarr2vcardsource($contact)
114         {
115                 $name        = explode(" ", $contact["name"]);
116                 $first_name  = $last_name = "";
117                 $middle_name = array();
118                 $num         = count($name);
119                 for ($i = 0; $i < $num && $first_name == ""; $i++) if ($name[$i] != "") {
120                         $first_name = $name[$i];
121                         unset($name[$i]);
122                 }
123                 for ($i = $num - 1; $i >= 0 && $last_name == ""; $i--) if (isset($name[$i]) && $name[$i] != "") {
124                         $last_name = $name[$i];
125                         unset($name[$i]);
126                 }
127                 foreach ($name as $n) if ($n != "") $middle_name[] = $n;
128                 $vcarddata              = new vcard_source_data($first_name, implode(" ", $middle_name), $last_name);
129                 $vcarddata->homepages[] = new vcard_source_data_homepage("pref", $contact["url"]);
130                 $vcarddata->last_update = ($contact["last-update"] > 0 ? $contact["last-update"] : $contact["created"]);
131
132                 $photo = q("SELECT * FROM photo WHERE `contact-id` = %d ORDER BY scale DESC", $contact["id"]); //prefer size 80x80
133                 if ($photo && count($photo) > 0) {
134                         $photodata             = new vcard_source_data_photo();
135                         $photodata->width      = $photo[0]["width"];
136                         $photodata->height     = $photo[0]["height"];
137                         $photodata->type       = "JPEG";
138                         $photodata->binarydata = $photo[0]["data"];
139                         $vcarddata->photo      = $photodata;
140                 }
141
142                 switch ($contact["network"]) {
143                         case "face":
144                                 $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("facebook", $contact["notify"], "http://www.facebook.com/" . $contact["notify"]);
145                                 break;
146                         case "dfrn":
147                                 $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("dfrn", $contact["nick"], $contact["url"]);
148                                 break;
149                         case "twitter":
150                                 $vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("twitter", $contact["nick"], "http://twitter.com/" . $contact["nick"]); // @TODO Stimmt das?
151                                 break;
152                 }
153
154                 $vcard = vcard_source_compile($vcarddata);
155                 return array(
156                         "id"           => $contact["id"],
157                         "carddata"     => $vcard,
158                         "uri"          => $contact["id"] . ".vcf",
159                         "lastmodified" => wdcal_mySql2PhpTime($vcarddata->last_update),
160                         "etag"         => md5($vcard),
161                         "size"         => strlen($vcard),
162                 );
163
164         }
165
166         /**
167          * @param int $uid
168          * @param array|int[] $exclude_ids
169          * @return array
170          */
171         private function dav_getCommunityContactsVCards($uid = 0, $exclude_ids = array())
172         {
173                 $notin    = (count($exclude_ids) > 0 ? " AND id NOT IN (" . implode(", ", $exclude_ids) . ") " : "");
174                 $uid      = IntVal($uid);
175                 $contacts = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0 $notin ORDER BY `name` ASC", $uid);
176
177                 $retdata = array();
178                 foreach ($contacts as $contact) {
179                         $x            = $this->dav_contactarr2vcardsource($contact);
180                         $x["contact"] = $contact["id"];
181                         $retdata[]    = $x;
182                 }
183                 return $retdata;
184         }
185
186
187         /**
188          * Returns all cards for a specific addressbook id.
189          *
190          * This method should return the following properties for each card:
191          *   * carddata - raw vcard data
192          *   * uri - Some unique url
193          *   * lastmodified - A unix timestamp
194          *
195          * It's recommended to also return the following properties:
196          *   * etag - A unique etag. This must change every time the card changes.
197          *   * size - The size of the card in bytes.
198          *
199          * If these last two properties are provided, less time will be spent
200          * calculating them. If they are specified, you can also ommit carddata.
201          * This may speed up certain requests, especially with large cards.
202          *
203          * @param string $addressbookId
204          * @return array
205          */
206         public function getCards($addressbookId)
207         {
208                 $add = explode("-", $addressbookId);
209
210                 $indb           = q('SELECT id, carddata, uri, lastmodified, etag, size, contact, manually_deleted FROM %s%scards WHERE namespace = %d AND namespace_id = %d',
211                         CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($add[0]), IntVal($add[1])
212                 );
213                 $found_contacts = array();
214                 $contacts       = array();
215                 foreach ($indb as $x) {
216                         if ($x["manually_deleted"] == 0) $contacts[] = $x;
217                         $found_contacts[] = IntVal($x["contact"]);
218                 }
219                 $new_found = $this->dav_getCommunityContactsVCards($add[1], $found_contacts);
220                 foreach ($new_found as $new) {
221                         q("INSERT INTO %s%scards (namespace, namespace_id, contact, carddata, uri, lastmodified, manually_edited, manually_deleted, etag, size)
222                                         VALUES (%d, %d, %d, '%s', '%s', %d, 0, 0, '%s', %d)", CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
223                                 IntVal($add[0]), IntVal($add[1]), IntVal($new["contact"]), dbesc($new["carddata"]), dbesc($new["uri"]), time(), md5($new["carddata"]), strlen($new["carddata"])
224                         );
225                 }
226                 return array_merge($contacts, $new_found);
227         }
228
229         /**
230          * Returns a specfic card.
231          *
232          * The same set of properties must be returned as with getCards. The only
233          * exception is that 'carddata' is absolutely required.
234          *
235          * @param mixed $addressBookId
236          * @param string $cardUri
237          * @throws Sabre_DAV_Exception_NotFound
238          * @return array
239          */
240         public function getCard($addressBookId, $cardUri)
241         {
242                 $x = explode("-", $addressBookId);
243                 $x = q("SELECT id, carddata, uri, lastmodified, etag, size FROM %s%scards WHERE namespace = %d AND namespace_id = %d AND uri = '%s'",
244                         CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($cardUri));
245                 if (count($x) == 0) throw new Sabre_DAV_Exception_NotFound();
246                 return $x[0];
247         }
248
249         /**
250          * Creates a new card.
251          *
252          * The addressbook id will be passed as the first argument. This is the
253          * same id as it is returned from the getAddressbooksForUser method.
254          *
255          * The cardUri is a base uri, and doesn't include the full path. The
256          * cardData argument is the vcard body, and is passed as a string.
257          *
258          * It is possible to return an ETag from this method. This ETag is for the
259          * newly created resource, and must be enclosed with double quotes (that
260          * is, the string itself must contain the double quotes).
261          *
262          * You should only return the ETag if you store the carddata as-is. If a
263          * subsequent GET request on the same card does not have the same body,
264          * byte-by-byte and you did return an ETag here, clients tend to get
265          * confused.
266          *
267          * If you don't return an ETag, you can just return null.
268          *
269          * @param string $addressBookId
270          * @param string $cardUri
271          * @param string $cardData
272          * @throws Sabre_DAV_Exception_Forbidden
273          * @return string
274          */
275         public function createCard($addressBookId, $cardUri, $cardData)
276         {
277                 throw new Sabre_DAV_Exception_Forbidden();
278         }
279
280         /**
281          * Updates a card.
282          *
283          * The addressbook id will be passed as the first argument. This is the
284          * same id as it is returned from the getAddressbooksForUser method.
285          *
286          * The cardUri is a base uri, and doesn't include the full path. The
287          * cardData argument is the vcard body, and is passed as a string.
288          *
289          * It is possible to return an ETag from this method. This ETag should
290          * match that of the updated resource, and must be enclosed with double
291          * quotes (that is: the string itself must contain the actual quotes).
292          *
293          * You should only return the ETag if you store the carddata as-is. If a
294          * subsequent GET request on the same card does not have the same body,
295          * byte-by-byte and you did return an ETag here, clients tend to get
296          * confused.
297          *
298          * If you don't return an ETag, you can just return null.
299          *
300          * @param string $addressBookId
301          * @param string $cardUri
302          * @param string $cardData
303          * @throws Sabre_DAV_Exception_Forbidden
304          * @return string|null
305          */
306         public function updateCard($addressBookId, $cardUri, $cardData)
307         {
308                 $x = explode("-", $addressBookId);
309
310                 $etag = md5($cardData);
311                 q("UPDATE %s%scards SET carddata = '%s', lastmodified = %d, etag = '%s', size = %d, manually_edited = 1 WHERE uri = '%s' AND namespace = %d AND namespace_id =%d",
312                         CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($cardData), time(), $etag, strlen($cardData), dbesc($cardUri), IntVal($x[10]), IntVal($x[1])
313                 );
314                 q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1]));
315
316                 return '"' . $etag . '"';
317         }
318
319         /**
320          * Deletes a card
321          *
322          * @param string $addressBookId
323          * @param string $cardUri
324          * @throws Sabre_DAV_Exception_Forbidden
325          * @return bool
326          */
327         public function deleteCard($addressBookId, $cardUri)
328         {
329                 $x = explode("-", $addressBookId);
330
331                 q("UPDATE %s%scards SET manually_deleted = 1 WHERE namespace = %d AND namespace_id = %d AND uri = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($cardUri));
332                 q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1]));
333
334                 return true;
335         }
336 }