1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* ownCloud - Utility class for VObject properties |
4
|
|
|
* |
5
|
|
|
* @author Thomas Tanghus |
6
|
|
|
* @copyright 2013-2014 Thomas Tanghus ([email protected]) |
7
|
|
|
* |
8
|
|
|
* This library is free software; you can redistribute it and/or |
9
|
|
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE |
10
|
|
|
* License as published by the Free Software Foundation; either |
11
|
|
|
* version 3 of the License, or any later version. |
12
|
|
|
* |
13
|
|
|
* This library is distributed in the hope that it will be useful, |
14
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16
|
|
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. |
17
|
|
|
* |
18
|
|
|
* You should have received a copy of the GNU Affero General Public |
19
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>. |
20
|
|
|
* |
21
|
|
|
*/ |
22
|
|
|
|
23
|
|
|
namespace OCA\Contacts\Utils; |
24
|
|
|
|
25
|
|
|
use OCA\Contacts\App; |
26
|
|
|
use OCA\Contacts\VObject\VCard; |
27
|
|
|
use Sabre\VObject\UUIDUtil; |
28
|
|
|
|
29
|
1 |
|
Properties::$l10n = \OCP\Util::getL10N('contacts'); |
30
|
|
|
|
31
|
|
|
Class Properties { |
32
|
|
|
|
33
|
|
|
const THUMBNAIL_PREFIX = 'contact-thumbnail-'; |
34
|
|
|
const THUMBNAIL_SIZE = 32; |
35
|
|
|
|
36
|
|
|
private static $deleteindexstmt; |
37
|
|
|
private static $updateindexstmt; |
38
|
|
|
protected static $cardsTableName = '*PREFIX*contacts_cards'; |
39
|
|
|
protected static $indexTableName = '*PREFIX*contacts_cards_properties'; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @brief language object for calendar app |
43
|
|
|
* |
44
|
|
|
* @var \OCP\IL10N |
45
|
|
|
*/ |
46
|
|
|
public static $l10n; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Properties there can be more than one of. |
50
|
|
|
* |
51
|
|
|
* @var array |
52
|
|
|
*/ |
53
|
|
|
public static $multiProperties = array('EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'CLOUD'); |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Properties to index. |
57
|
|
|
* |
58
|
|
|
* @var array |
59
|
|
|
*/ |
60
|
|
|
public static $indexProperties = array( |
61
|
|
|
'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME', |
62
|
|
|
'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'CLOUD'); |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Get options for IMPP properties |
66
|
|
|
* @param string $im |
67
|
|
|
* @return array of vcard prop => label |
68
|
|
|
*/ |
69
|
1 |
|
public static function getIMOptions($im = null) { |
70
|
1 |
|
$l10n = self::$l10n; |
71
|
|
|
$ims = array( |
72
|
|
|
'jabber' => array( |
73
|
1 |
|
'displayname' => (string)$l10n->t('Jabber'), |
74
|
1 |
|
'xname' => 'X-JABBER', |
75
|
1 |
|
'protocol' => 'xmpp', |
76
|
1 |
|
), |
77
|
|
|
'sip' => array( |
78
|
1 |
|
'displayname' => (string)$l10n->t('Internet call'), |
79
|
1 |
|
'xname' => 'X-SIP', |
80
|
1 |
|
'protocol' => 'sip', |
81
|
1 |
|
), |
82
|
|
|
'aim' => array( |
83
|
1 |
|
'displayname' => (string)$l10n->t('AIM'), |
84
|
1 |
|
'xname' => 'X-AIM', |
85
|
1 |
|
'protocol' => 'aim', |
86
|
1 |
|
), |
87
|
|
|
'msn' => array( |
88
|
1 |
|
'displayname' => (string)$l10n->t('MSN'), |
89
|
1 |
|
'xname' => 'X-MSN', |
90
|
1 |
|
'protocol' => 'msn', |
91
|
1 |
|
), |
92
|
|
|
'twitter' => array( |
93
|
1 |
|
'displayname' => (string)$l10n->t('Twitter'), |
94
|
1 |
|
'xname' => 'X-TWITTER', |
95
|
1 |
|
'protocol' => 'twitter', |
96
|
1 |
|
), |
97
|
|
|
'googletalk' => array( |
98
|
1 |
|
'displayname' => (string)$l10n->t('GoogleTalk'), |
99
|
1 |
|
'xname' => null, |
100
|
1 |
|
'protocol' => 'xmpp', |
101
|
1 |
|
), |
102
|
|
|
'facebook' => array( |
103
|
1 |
|
'displayname' => (string)$l10n->t('Facebook'), |
104
|
1 |
|
'xname' => null, |
105
|
1 |
|
'protocol' => 'xmpp', |
106
|
1 |
|
), |
107
|
|
|
'xmpp' => array( |
108
|
1 |
|
'displayname' => (string)$l10n->t('XMPP'), |
109
|
1 |
|
'xname' => null, |
110
|
1 |
|
'protocol' => 'xmpp', |
111
|
1 |
|
), |
112
|
|
|
'icq' => array( |
113
|
1 |
|
'displayname' => (string)$l10n->t('ICQ'), |
114
|
1 |
|
'xname' => 'X-ICQ', |
115
|
1 |
|
'protocol' => 'icq', |
116
|
1 |
|
), |
117
|
|
|
'yahoo' => array( |
118
|
1 |
|
'displayname' => (string)$l10n->t('Yahoo'), |
119
|
1 |
|
'xname' => 'X-YAHOO', |
120
|
1 |
|
'protocol' => 'ymsgr', |
121
|
1 |
|
), |
122
|
|
|
'skype' => array( |
123
|
1 |
|
'displayname' => (string)$l10n->t('Skype'), |
124
|
1 |
|
'xname' => 'X-SKYPE', |
125
|
1 |
|
'protocol' => 'skype', |
126
|
1 |
|
), |
127
|
|
|
'qq' => array( |
128
|
1 |
|
'displayname' => (string)$l10n->t('QQ'), |
129
|
1 |
|
'xname' => 'X-SKYPE', |
130
|
1 |
|
'protocol' => 'x-apple', |
131
|
1 |
|
), |
132
|
|
|
'gadugadu' => array( |
133
|
1 |
|
'displayname' => (string)$l10n->t('GaduGadu'), |
134
|
1 |
|
'xname' => 'X-SKYPE', |
135
|
1 |
|
'protocol' => 'x-apple', |
136
|
1 |
|
), |
137
|
|
|
'owncloud-handle' => array( |
138
|
1 |
|
'displayname' => (string)$l10n->t('ownCloud'), |
139
|
1 |
|
'xname' => null, |
140
|
|
|
'protocol' => 'x-owncloud-handle' |
141
|
1 |
|
), |
142
|
1 |
|
); |
143
|
1 |
|
if(is_null($im)) { |
144
|
1 |
|
return $ims; |
145
|
|
|
} else { |
146
|
|
|
$ims['ymsgr'] = $ims['yahoo']; |
147
|
|
|
$ims['gtalk'] = $ims['googletalk']; |
148
|
|
|
return isset($ims[$im]) ? $ims[$im] : null; |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Get standard set of TYPE values for different properties. |
154
|
|
|
* |
155
|
|
|
* @param string $prop |
156
|
|
|
* @return array Type values for property $prop |
157
|
|
|
*/ |
158
|
1 |
|
public static function getTypesForProperty($prop) { |
159
|
1 |
|
$l = self::$l10n; |
160
|
|
|
switch($prop) { |
161
|
1 |
|
case 'LABEL': |
162
|
1 |
|
case 'ADR': |
163
|
1 |
View Code Duplication |
case 'IMPP': |
|
|
|
|
164
|
|
|
return array( |
165
|
1 |
|
'HOME' => (string)$l->t('Home'), |
166
|
1 |
|
'WORK' => (string)$l->t('Work'), |
167
|
1 |
|
'OTHER' => (string)$l->t('Other'), |
168
|
1 |
|
); |
169
|
1 |
|
case 'TEL': |
170
|
|
|
return array( |
171
|
1 |
|
'HOME' => (string)$l->t('Home'), |
172
|
1 |
|
'CELL' => (string)$l->t('Mobile'), |
173
|
1 |
|
'WORK' => (string)$l->t('Work'), |
174
|
1 |
|
'TEXT' => (string)$l->t('Text'), |
175
|
1 |
|
'VOICE' => (string)$l->t('Voice'), |
176
|
1 |
|
'MSG' => (string)$l->t('Message'), |
177
|
1 |
|
'FAX' => (string)$l->t('Fax'), |
178
|
1 |
|
'VIDEO' => (string)$l->t('Video'), |
179
|
1 |
|
'PAGER' => (string)$l->t('Pager'), |
180
|
1 |
|
'OTHER' => (string)$l->t('Other'), |
181
|
1 |
|
); |
182
|
1 |
View Code Duplication |
case 'EMAIL': |
|
|
|
|
183
|
|
|
return array( |
184
|
1 |
|
'HOME' => (string)$l->t('Home'), |
185
|
1 |
|
'WORK' => (string)$l->t('Work'), |
186
|
1 |
|
'INTERNET' => (string)$l->t('Internet'), |
187
|
1 |
|
'OTHER' => (string)$l->t('Other'), |
188
|
1 |
|
); |
189
|
1 |
View Code Duplication |
case 'CLOUD': |
|
|
|
|
190
|
|
|
return array( |
191
|
1 |
|
'HOME' => (string)$l->t('Home'), |
192
|
1 |
|
'WORK' => (string)$l->t('Work'), |
193
|
1 |
|
'OTHER' => (string)$l->t('Other'), |
194
|
1 |
|
); |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @brief returns the default categories of ownCloud |
200
|
|
|
* @return string[] $categories |
201
|
|
|
*/ |
202
|
|
|
public static function getDefaultCategories() { |
203
|
|
|
$l10n = self::$l10n; |
204
|
|
|
return array( |
205
|
|
|
(string)$l10n->t('Friends'), |
206
|
|
|
(string)$l10n->t('Family'), |
207
|
|
|
(string)$l10n->t('Work'), |
208
|
|
|
(string)$l10n->t('Other'), |
209
|
|
|
); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* @return string |
214
|
|
|
*/ |
215
|
1 |
|
public static function generateUID() { |
216
|
1 |
|
return UUIDUtil::getUUID(); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Purge indexed properties. |
221
|
|
|
* |
222
|
|
|
* @param string[] $ids |
223
|
|
|
*/ |
224
|
2 |
|
public static function purgeIndexes($ids) { |
225
|
2 |
|
\OCP\Util::writeLog('contacts', __METHOD__.', ids: ' . print_r($ids, true), \OCP\Util::DEBUG); |
226
|
2 |
|
if(!is_array($ids) || count($ids) === 0) { |
227
|
|
|
throw new \Exception(__METHOD__ . ' takes only arrays with at least one value.'); |
228
|
|
|
} |
229
|
2 |
|
\OCP\Util::writeLog('contacts', __METHOD__.', ids: ' . print_r($ids, true), \OCP\Util::DEBUG); |
230
|
2 |
|
if(!isset(self::$deleteindexstmt)) { |
231
|
|
|
self::$deleteindexstmt |
232
|
1 |
|
= \OCP\DB::prepare('DELETE FROM `' . self::$indexTableName . '`' |
233
|
1 |
|
. ' WHERE `contactid` IN (' . str_repeat('?,', count($ids)-1) . '?) '); |
234
|
1 |
|
} |
235
|
|
|
try { |
236
|
2 |
|
self::$deleteindexstmt->execute($ids); |
237
|
2 |
|
} catch(\Exception $e) { |
238
|
2 |
|
\OCP\Util::writeLog('contacts', __METHOD__. |
239
|
2 |
|
', exception: ' . $e->getMessage(), \OCP\Util::ERROR); |
240
|
2 |
|
\OCP\Util::writeLog('contacts', __METHOD__.', ids: ' |
241
|
2 |
|
. print_r($ids, true), \OCP\Util::DEBUG); |
242
|
2 |
|
return false; |
243
|
|
|
} |
244
|
2 |
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Update the contact property index. |
248
|
|
|
* |
249
|
|
|
* If vcard is null the properties for that contact will be purged. |
250
|
|
|
* If it is a valid object the old properties will first be purged |
251
|
|
|
* and the current properties indexed. |
252
|
|
|
* |
253
|
|
|
* @param string $contactId |
254
|
|
|
* @param VCard|null $vCard |
255
|
|
|
* @param string|null $owner |
|
|
|
|
256
|
|
|
*/ |
257
|
2 |
|
public static function updateIndex($contactId, $vCard = null, $owner = null) { |
258
|
2 |
|
self::purgeIndexes(array($contactId)); |
259
|
|
|
|
260
|
2 |
|
if(is_null($vCard)) { |
261
|
|
|
return; |
262
|
|
|
} |
263
|
|
|
|
264
|
2 |
|
if(is_null($owner) || empty($owner) ) { |
265
|
2 |
|
$owner = \OC::$server->getUserSession()->getUser()->getUId(); |
266
|
2 |
|
} |
267
|
|
|
|
268
|
2 |
|
if(!isset(self::$updateindexstmt)) { |
269
|
1 |
|
self::$updateindexstmt = \OCP\DB::prepare( 'INSERT INTO `' . self::$indexTableName . '` ' |
270
|
1 |
|
. '(`userid`, `contactid`,`name`,`value`,`preferred`) VALUES(?,?,?,?,?)' ); |
271
|
1 |
|
} |
272
|
2 |
|
foreach($vCard->children as $property) { |
273
|
2 |
|
if(!in_array($property->name, self::$indexProperties)) { |
274
|
2 |
|
continue; |
275
|
|
|
} |
276
|
2 |
|
$preferred = 0; |
277
|
2 |
|
foreach($property->parameters as $parameter) { |
278
|
|
|
if($parameter->name == 'TYPE' && strtoupper($parameter->getValue()) == 'PREF') { |
279
|
|
|
$preferred = 1; |
280
|
|
|
break; |
281
|
|
|
} |
282
|
2 |
|
} |
283
|
|
|
try { |
284
|
2 |
|
$result = self::$updateindexstmt->execute( |
285
|
|
|
array( |
286
|
2 |
|
$owner, |
287
|
2 |
|
$contactId, |
288
|
2 |
|
$property->name, |
289
|
2 |
|
substr($property->getValue(), 0, 254), |
290
|
2 |
|
$preferred, |
291
|
|
|
) |
292
|
2 |
|
); |
293
|
2 |
View Code Duplication |
if (\OCP\DB::isError($result)) { |
|
|
|
|
294
|
|
|
\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' |
295
|
|
|
. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR); |
296
|
|
|
return false; |
297
|
|
|
} |
298
|
2 |
|
} catch(\Exception $e) { |
299
|
|
|
\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR); |
300
|
|
|
return false; |
301
|
|
|
} |
302
|
2 |
|
} |
303
|
2 |
|
} |
304
|
|
|
|
305
|
|
|
public static function cacheThumbnail($backendName, $addressBookId, $contactId, |
306
|
|
|
\OCP\Image $image = null, $vCard = null, $options = array() |
307
|
|
|
) { |
308
|
|
|
$cache = \OC::$server->getCache(); |
309
|
|
|
$key = self::THUMBNAIL_PREFIX . $backendName . '::' . $addressBookId . '::' . $contactId; |
310
|
|
|
//$cache->remove($key); |
311
|
|
|
$haskey = $cache->hasKey($key); |
|
|
|
|
312
|
|
|
|
313
|
|
|
if (!array_key_exists('remove', $options) && !array_key_exists('update', $options)){ |
314
|
|
|
if ($cache->hasKey($key) && $image === null){ |
315
|
|
|
return $cache->get($key); |
316
|
|
|
} |
317
|
|
|
} else { |
318
|
|
|
if ( (isset($options['remove']) && $options['remove'] === false) |
319
|
|
|
&& (isset($options['update']) && $options['update'] === false) ){ |
320
|
|
|
return $cache->get($key); |
321
|
|
|
} |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
if (isset($options['remove']) && $options['remove']) { |
325
|
|
|
$cache->remove($key); |
326
|
|
|
if(!isset($options['update']) || !$options['update']) { |
327
|
|
|
return false; |
328
|
|
|
} |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
if (is_null($image)) { |
332
|
|
|
if (is_null($vCard)) { |
333
|
|
|
$app = new App(); |
334
|
|
|
$vCard = $app->getContact($backendName, $addressBookId, $contactId); |
335
|
|
|
} |
336
|
|
|
if (!isset($vCard->PHOTO)) { |
337
|
|
|
return false; |
338
|
|
|
} |
339
|
|
|
$image = new \OCP\Image(); |
340
|
|
|
$photostring = (string) $vCard->PHOTO; |
341
|
|
|
|
342
|
|
|
if ( $vCard->PHOTO instanceof \Sabre\VObject\Property\Uri && substr($photostring, 0, 5) === 'data:' ) { |
|
|
|
|
343
|
|
|
$mimeType = substr($photostring, 5, strpos($photostring, ',')-5); |
344
|
|
|
if (strpos($mimeType, ';')) { |
345
|
|
|
$mimeType = substr($mimeType,0,strpos($mimeType, ';')); |
|
|
|
|
346
|
|
|
} |
347
|
|
|
$photostring = substr($photostring, strpos($photostring,',')+1); |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
if (!$image->loadFromBase64($photostring)) { |
351
|
|
|
#\OCP\Util::writeLog('contacts', __METHOD__.', photo: ' . print_r($photostring, true), \OCP\Util::DEBUG); |
352
|
|
|
return false; |
353
|
|
|
} |
354
|
|
|
} |
355
|
|
|
|
356
|
|
View Code Duplication |
if (!$image->centerCrop()) { |
|
|
|
|
357
|
|
|
\OCP\Util::writeLog('contacts', |
358
|
|
|
__METHOD__ .'. Couldn\'t crop thumbnail for ID ' . $key, |
359
|
|
|
\OCP\Util::ERROR); |
360
|
|
|
return false; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
View Code Duplication |
if (!$image->resize(self::THUMBNAIL_SIZE)) { |
|
|
|
|
364
|
|
|
\OCP\Util::writeLog('contacts', |
365
|
|
|
__METHOD__ . '. Couldn\'t resize thumbnail for ID ' . $key, |
366
|
|
|
\OCP\Util::ERROR); |
367
|
|
|
return false; |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
// Cache as base64 for around a month |
371
|
|
|
$cache->set($key, strval($image), 3000000); |
372
|
|
|
return $cache->get($key); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
} |
376
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.