Blame view

sources/apps/contacts/lib/backend/database.php 28.9 KB
d1bafeea1   Kload   [fix] Upgrade to ...
1
2
3
4
5
  <?php
  /**
   * ownCloud - Database backend for Contacts
   *
   * @author Thomas Tanghus
6d9380f96   Cédric Dupont   Update sources OC...
6
   * @copyright 2013-2014 Thomas Tanghus (thomas@tanghus.net)
d1bafeea1   Kload   [fix] Upgrade to ...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
   * License as published by the Free Software Foundation; either
   * version 3 of the License, or any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
   *
   * You should have received a copy of the GNU Affero General Public
   * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
   *
   */
  
  namespace OCA\Contacts\Backend;
  
  use OCA\Contacts\Contact,
  	OCA\Contacts\VObject\VCard,
  	OCA\Contacts\Utils\Properties,
  	Sabre\VObject\Reader;
  
  /**
6d9380f96   Cédric Dupont   Update sources OC...
31
   * Backend class for a users own contacts.
d1bafeea1   Kload   [fix] Upgrade to ...
32
33
34
   */
  
  class Database extends AbstractBackend {
d1bafeea1   Kload   [fix] Upgrade to ...
35
36
37
  	static private $preparedQueries = array();
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  	 * The name of the backend.
  	 *
  	 * @var string
  	 */
  	public $name = 'local';
  
  	/**
  	 * The cached address books.
  	 *
  	 * @var array[]
  	 */
  	public $addressBooks;
  
  	/**
  	 * The table that holds the address books.
  	 *
  	 * @var string
  	 */
  	public $addressBooksTableName;
  
  	/**
  	 * The table that holds the contact vCards.
  	 *
  	 * @var string
  	 */
  	public $cardsTableName;
  
  	/**
  	 * The table that holds the indexed vCard properties.
  	 *
  	 * @var string
  	 */
  	public $indexTableName;
  
  	/**
d1bafeea1   Kload   [fix] Upgrade to ...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  	* Sets up the backend
  	*
  	* @param string $addressBooksTableName
  	* @param string $cardsTableName
  	*/
  	public function __construct(
  		$userid = null,
  		$options = array(
  			'addressBooksTableName' => '*PREFIX*contacts_addressbooks',
  			'cardsTableName' => '*PREFIX*contacts_cards',
  			'indexTableName' => '*PREFIX*contacts_cards_properties'
  		)
  	) {
  		$this->userid = $userid ? $userid : \OCP\User::getUser();
  		$this->addressBooksTableName = $options['addressBooksTableName'];
  		$this->cardsTableName = $options['cardsTableName'];
  		$this->indexTableName = $options['indexTableName'];
6d9380f96   Cédric Dupont   Update sources OC...
90
  		$this->addressBooks = array();
d1bafeea1   Kload   [fix] Upgrade to ...
91
92
93
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
94
95
  	* {@inheritdoc}
  	*/
d1bafeea1   Kload   [fix] Upgrade to ...
96
97
98
  	public function getAddressBooksForUser(array $options = array()) {
  
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
99
100
  			$result = $this->getPreparedQuery('getaddressbooksforuser')
  				->execute(array($this->userid));
d1bafeea1   Kload   [fix] Upgrade to ...
101
  			if (\OCP\DB::isError($result)) {
6d9380f96   Cédric Dupont   Update sources OC...
102
103
104
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
  					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return $this->addressBooks;
d1bafeea1   Kload   [fix] Upgrade to ...
105
  			}
6d9380f96   Cédric Dupont   Update sources OC...
106

d1bafeea1   Kload   [fix] Upgrade to ...
107
  		} catch(\Exception $e) {
6d9380f96   Cédric Dupont   Update sources OC...
108
109
110
  			\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
  				. $e->getMessage(), \OCP\Util::ERROR);
  			return $this->addressBooks;
d1bafeea1   Kload   [fix] Upgrade to ...
111
  		}
6d9380f96   Cédric Dupont   Update sources OC...
112
  		while ($row = $result->fetchRow()) {
d1bafeea1   Kload   [fix] Upgrade to ...
113
  			$row['permissions'] = \OCP\PERMISSION_ALL;
6d9380f96   Cédric Dupont   Update sources OC...
114
  			$this->addressBooks[$row['id']] = $row;
d1bafeea1   Kload   [fix] Upgrade to ...
115
  		}
6d9380f96   Cédric Dupont   Update sources OC...
116
117
  
  		return $this->addressBooks;
d1bafeea1   Kload   [fix] Upgrade to ...
118
  	}
6d9380f96   Cédric Dupont   Update sources OC...
119
120
121
122
  	/**
  	* {@inheritdoc}
  	*/
  	public function getAddressBook($addressBookId, array $options = array()) {
d1bafeea1   Kload   [fix] Upgrade to ...
123
  		$owner = isset($options['shared_by']) ? $options['shared_by'] : $this->userid;
6d9380f96   Cédric Dupont   Update sources OC...
124
125
126
127
128
  		//\OCP\Util::writeLog('contacts', __METHOD__.' id: '
  		//	. $addressBookId, \OCP\Util::DEBUG);
  		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
  			//print(__METHOD__ . ' ' . __LINE__ .' addressBookInfo: ' . print_r($this->addressBooks[$addressBookId], true));
  			return $this->addressBooks[$addressBookId];
d1bafeea1   Kload   [fix] Upgrade to ...
129
  		}
6d9380f96   Cédric Dupont   Update sources OC...
130

d1bafeea1   Kload   [fix] Upgrade to ...
131
132
  		// Hmm, not found. Lets query the db.
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
133
  			$result = $this->getPreparedQuery('getaddressbook')->execute(array($addressBookId, $owner));
d1bafeea1   Kload   [fix] Upgrade to ...
134
135
136
137
138
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
  					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return null;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
139
140
141
142
  
  			$row = $result->fetchRow();
  
  			if (!$row) {
d1bafeea1   Kload   [fix] Upgrade to ...
143
144
  				return null;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
145

d1bafeea1   Kload   [fix] Upgrade to ...
146
147
  			$row['permissions'] = \OCP\PERMISSION_ALL;
  			$row['backend'] = $this->name;
6d9380f96   Cédric Dupont   Update sources OC...
148
  			$this->addressBooks[$addressBookId] = $row;
d1bafeea1   Kload   [fix] Upgrade to ...
149
  			return $row;
6d9380f96   Cédric Dupont   Update sources OC...
150

d1bafeea1   Kload   [fix] Upgrade to ...
151
152
153
154
155
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
  				. $e->getMessage(), \OCP\Util::ERROR);
  			return null;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
156

d1bafeea1   Kload   [fix] Upgrade to ...
157
  	}
6d9380f96   Cédric Dupont   Update sources OC...
158
159
160
161
  	/**
  	* {@inheritdoc}
  	*/
  	public function hasAddressBook($addressBookId) {
d1bafeea1   Kload   [fix] Upgrade to ...
162
  		// First check if it's already cached
6d9380f96   Cédric Dupont   Update sources OC...
163
  		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
d1bafeea1   Kload   [fix] Upgrade to ...
164
165
  			return true;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
166
167
  
  		return count($this->getAddressBook($addressBookId)) > 0;
d1bafeea1   Kload   [fix] Upgrade to ...
168
169
170
171
172
  	}
  
  	/**
  	 * Updates an addressbook's properties
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
173
  	 * @param string $addressBookId
d1bafeea1   Kload   [fix] Upgrade to ...
174
175
176
  	 * @param array $changes
  	 * @return bool
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
177
178
179
  	public function updateAddressBook($addressBookId, array $changes) {
  
  		if (count($changes) === 0) {
d1bafeea1   Kload   [fix] Upgrade to ...
180
181
182
183
184
185
  			return false;
  		}
  
  		$query = 'UPDATE `' . $this->addressBooksTableName . '` SET ';
  
  		$updates = array();
6d9380f96   Cédric Dupont   Update sources OC...
186
  		if (isset($changes['displayname'])) {
d1bafeea1   Kload   [fix] Upgrade to ...
187
188
  			$query .= '`displayname` = ?, ';
  			$updates[] = $changes['displayname'];
6d9380f96   Cédric Dupont   Update sources OC...
189
190
191
  
  			if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
  				$this->addressBooks[$addressBookId]['displayname'] = $changes['displayname'];
d1bafeea1   Kload   [fix] Upgrade to ...
192
  			}
6d9380f96   Cédric Dupont   Update sources OC...
193

d1bafeea1   Kload   [fix] Upgrade to ...
194
  		}
6d9380f96   Cédric Dupont   Update sources OC...
195
  		if (isset($changes['description'])) {
d1bafeea1   Kload   [fix] Upgrade to ...
196
197
  			$query .= '`description` = ?, ';
  			$updates[] = $changes['description'];
6d9380f96   Cédric Dupont   Update sources OC...
198
199
200
  
  			if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
  				$this->addressBooks[$addressBookId]['description'] = $changes['description'];
d1bafeea1   Kload   [fix] Upgrade to ...
201
  			}
6d9380f96   Cédric Dupont   Update sources OC...
202

d1bafeea1   Kload   [fix] Upgrade to ...
203
204
205
  		}
  
  		$query .= '`ctag` = ? + 1 WHERE `id` = ?';
6d9380f96   Cédric Dupont   Update sources OC...
206
207
208
209
210
211
212
  		$now = time();
  		$updates[] = $now;
  		$updates[] = $addressBookId;
  
  		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
  			$this->addressBooks[$addressBookId]['lastmodified'] = $now;
  		}
d1bafeea1   Kload   [fix] Upgrade to ...
213
214
  
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
215

d1bafeea1   Kload   [fix] Upgrade to ...
216
217
  			$stmt = \OCP\DB::prepare($query);
  			$result = $stmt->execute($updates);
6d9380f96   Cédric Dupont   Update sources OC...
218

d1bafeea1   Kload   [fix] Upgrade to ...
219
220
221
222
223
224
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts',
  					__METHOD__. 'DB error: '
  					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
225

d1bafeea1   Kload   [fix] Upgrade to ...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts',
  				__METHOD__ . ', exception: '
  				. $e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
  
  		return true;
  	}
  
  	/**
  	 * Creates a new address book
  	 *
  	 * Supported properties are 'displayname', 'description' and 'uri'.
  	 * 'uri' is supported to allow to add from CardDAV requests, and MUST
  	 * be used for the 'uri' database field if present.
  	 * 'displayname' MUST be present.
  	 *
  	 * @param array $properties
  	 * @param array $options - Optional (backend specific options)
  	 * @return string|false The ID if the newly created AddressBook or false on error.
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
248
  	public function createAddressBook(array $properties) {
d1bafeea1   Kload   [fix] Upgrade to ...
249

6d9380f96   Cédric Dupont   Update sources OC...
250
  		if (count($properties) === 0 || !isset($properties['displayname'])) {
d1bafeea1   Kload   [fix] Upgrade to ...
251
252
  			return false;
  		}
d1bafeea1   Kload   [fix] Upgrade to ...
253
254
255
256
257
258
259
260
261
  		$updates = array($this->userid, $properties['displayname']);
  		$updates[] = isset($properties['uri'])
  			? $properties['uri']
  			: $this->createAddressBookURI($properties['displayname']);
  		$updates[] = isset($properties['description']) ? $properties['description'] : '';
  		$ctag = time();
  		$updates[] = $ctag;
  
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
262
  			$result = $this->getPreparedQuery('createaddressbook')->execute($updates);
d1bafeea1   Kload   [fix] Upgrade to ...
263
264
265
266
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
267

d1bafeea1   Kload   [fix] Upgrade to ...
268
269
270
271
272
273
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__ . ', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
  
  		$newid = \OCP\DB::insertid($this->addressBooksTableName);
6d9380f96   Cédric Dupont   Update sources OC...
274
275
  
  		if ($this->addressBooks) {
d1bafeea1   Kload   [fix] Upgrade to ...
276
277
278
279
  			$updates['id'] = $newid;
  			$updates['ctag'] = $ctag;
  			$updates['lastmodified'] = $ctag;
  			$updates['permissions'] = \OCP\PERMISSION_ALL;
6d9380f96   Cédric Dupont   Update sources OC...
280
  			$this->addressBooks[$newid] = $updates;
d1bafeea1   Kload   [fix] Upgrade to ...
281
  		}
6d9380f96   Cédric Dupont   Update sources OC...
282

d1bafeea1   Kload   [fix] Upgrade to ...
283
284
285
286
  		return $newid;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
287
  	 * Get all contact ids from the address book to run pre_deleteAddressBook hook
d1bafeea1   Kload   [fix] Upgrade to ...
288
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
289
  	 * @param string $addressBookId
d1bafeea1   Kload   [fix] Upgrade to ...
290
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
291
  	protected function preDeleteAddressBook($addressBookId) {
d1bafeea1   Kload   [fix] Upgrade to ...
292
293
294
  		// Get all contact ids for this address book
  		$ids = array();
  		$result = null;
6d9380f96   Cédric Dupont   Update sources OC...
295

d1bafeea1   Kload   [fix] Upgrade to ...
296
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
297
298
299
  
  			$result = $this->getPreparedQuery('getcontactids')
  				->execute(array($addressBookId));
d1bafeea1   Kload   [fix] Upgrade to ...
300
301
302
303
304
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
  					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
305

d1bafeea1   Kload   [fix] Upgrade to ...
306
307
308
309
310
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.
  				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
311
312
  		if (!is_null($result)) {
  			while ($id = $result->fetchOne()) {
d1bafeea1   Kload   [fix] Upgrade to ...
313
314
  				$ids[] = $id;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
315
316
317
318
  
  			\OCP\Util::emitHook('OCA\Contacts', 'pre_deleteAddressBook',
  				array('addressbookid' => $addressBookId, 'contactids' => $ids)
  			);
d1bafeea1   Kload   [fix] Upgrade to ...
319
  		}
6d9380f96   Cédric Dupont   Update sources OC...
320
  	}
d1bafeea1   Kload   [fix] Upgrade to ...
321

6d9380f96   Cédric Dupont   Update sources OC...
322
323
324
325
326
327
328
329
330
331
332
333
334
  	/**
  	 * Deletes an entire addressbook and all its contents
  	 *
  	 * NOTE: For efficience this method bypasses the cleanup hooks and deletes
  	 * property indexes and category/group relations by itself.
  	 *
  	 * @param string $addressBookId
  	 * @param array $options - Optional (backend specific options)
  	 * @return bool
  	 */
  	public function deleteAddressBook($addressBookId) {
  
  		$this->preDeleteAddressBook($addressBookId);
d1bafeea1   Kload   [fix] Upgrade to ...
335

d1bafeea1   Kload   [fix] Upgrade to ...
336
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
337
338
  			$this->getPreparedQuery('deleteaddressbookcontacts')
  				->execute(array($addressBookId));
d1bafeea1   Kload   [fix] Upgrade to ...
339
340
341
342
343
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.
  				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
d1bafeea1   Kload   [fix] Upgrade to ...
344
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
345
346
  			$this->getPreparedQuery('deleteaddressbook')
  				->execute(array($addressBookId));
d1bafeea1   Kload   [fix] Upgrade to ...
347
348
349
350
351
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.
  				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
352
353
  		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
  			unset($this->addressBooks[$addressBookId]);
d1bafeea1   Kload   [fix] Upgrade to ...
354
355
356
357
358
359
360
361
362
363
364
  		}
  
  		return true;
  	}
  
  	/**
  	 * @brief Updates ctag for addressbook
  	 * @param integer $id
  	 * @return boolean
  	 */
  	public function setModifiedAddressBook($id) {
d1bafeea1   Kload   [fix] Upgrade to ...
365
  		$ctag = time();
6d9380f96   Cédric Dupont   Update sources OC...
366
  		$this->getPreparedQuery('touchaddressbook')->execute(array($ctag, $id));
d1bafeea1   Kload   [fix] Upgrade to ...
367
368
369
  
  		return true;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
370
371
372
373
374
375
376
377
378
379
380
381
  	/**
  	* {@inheritdoc}
  	*/
  	public function lastModifiedAddressBook($addressBookId) {
  
  		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
  			return $this->addressBooks[$addressBookId]['lastmodified'];
  		}
  
  		$addressBook = $this->getAddressBook($addressBookId);
  		if($addressBook) {
  			$this->addressBooks[$addressBookId] = $addressBook;
d1bafeea1   Kload   [fix] Upgrade to ...
382
  		}
d1bafeea1   Kload   [fix] Upgrade to ...
383
384
385
386
387
388
  		return $addressBook ? $addressBook['lastmodified'] : null;
  	}
  
  	/**
  	 * Returns the number of contacts in a specific address book.
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
389
  	 * @param string $addressBookId
d1bafeea1   Kload   [fix] Upgrade to ...
390
391
392
  	 * @param bool $omitdata Don't fetch the entire carddata or vcard.
  	 * @return array
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
393
394
395
  	public function numContacts($addressBookId) {
  
  		$result = $this->getPreparedQuery('numcontacts')->execute(array($addressBookId));
d1bafeea1   Kload   [fix] Upgrade to ...
396

d1bafeea1   Kload   [fix] Upgrade to ...
397
398
399
400
  		if (\OCP\DB::isError($result)) {
  			\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  			return null;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
401

d1bafeea1   Kload   [fix] Upgrade to ...
402
403
404
405
  		return (int)$result->fetchOne();
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
406
407
408
409
  	* {@inheritdoc}
  	*/
  	public function getContacts($addressBookId, array $options = array()) {
  		//\OCP\Util::writeLog('contacts', __METHOD__.' addressbookid: ' . $addressBookId, \OCP\Util::DEBUG);
d1bafeea1   Kload   [fix] Upgrade to ...
410
411
  		$cards = array();
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
412
413
414
415
416
  			$queryIdentifier = (isset($options['omitdata']) && $options['omitdata'] === true)
  				? 'getcontactsomitdata'
  				: 'getcontacts';
  
  			$result = $this->getPreparedQuery($queryIdentifier, $options)->execute(array($addressBookId));
d1bafeea1   Kload   [fix] Upgrade to ...
417
418
419
420
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return $cards;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
421

d1bafeea1   Kload   [fix] Upgrade to ...
422
423
424
425
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
  			return $cards;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
426
427
428
  		if (!is_null($result)) {
  
  			while ($row = $result->fetchRow()) {
d1bafeea1   Kload   [fix] Upgrade to ...
429
430
431
  				$row['permissions'] = \OCP\PERMISSION_ALL;
  				$cards[] = $row;
  			}
d1bafeea1   Kload   [fix] Upgrade to ...
432

6d9380f96   Cédric Dupont   Update sources OC...
433
434
  		}
  		
d1bafeea1   Kload   [fix] Upgrade to ...
435
436
437
438
439
440
  		return $cards;
  	}
  
  	/**
  	 * Returns a specific contact.
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
441
  	 * NOTE: The contact $id for Database and Shared backends can be an array containing
d1bafeea1   Kload   [fix] Upgrade to ...
442
443
  	 * either 'id' or 'uri' to be able to play seamlessly with the
  	 * CardDAV backend.
6d9380f96   Cédric Dupont   Update sources OC...
444
445
446
  	 * NOTE: $addressbookid isn't always used in the query, so there's no access control.
  	 * 	This is because the groups backend - \OCP\Tags - doesn't no about parent collections
  	 * 	only object IDs. Hence a hack is made with an optional 'noCollection'.
d1bafeea1   Kload   [fix] Upgrade to ...
447
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
448
449
  	 * @param string $addressBookId
  	 * @param string|array $id Contact ID
d1bafeea1   Kload   [fix] Upgrade to ...
450
451
452
  	 * @param array $options - Optional (backend specific options)
  	 * @return array|null
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
453
454
  	public function getContact($addressBookId, $id, array $options = array()) {
  		//\OCP\Util::writeLog('contacts', __METHOD__.' identifier: ' . $addressBookId . ' / ' . $id, \OCP\Util::DEBUG);
d1bafeea1   Kload   [fix] Upgrade to ...
455

6d9380f96   Cédric Dupont   Update sources OC...
456
457
  		// When dealing with tags we have no idea if which address book it's in
  		// but since they're all in the same table they have unique IDs anyway
d1bafeea1   Kload   [fix] Upgrade to ...
458
  		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
6d9380f96   Cédric Dupont   Update sources OC...
459
460
461
462
463
464
465
466
467
468
469
  		$queryIdentifier = 'getcontact';
  		$queries = array();
  
  		// When querying from CardDAV we don't have the ID, only the uri
  		if (is_array($id)) {
  			if (isset($id['id'])) {
  				$queries[] = $id['id'];
  				$queryIdentifier .= 'byid';
  			} elseif (isset($id['uri'])) {
  				$queries[] = $id['uri'];
  				$queryIdentifier .= 'byuri';
d1bafeea1   Kload   [fix] Upgrade to ...
470
471
472
473
  			} else {
  				throw new \Exception(
  					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
  				);
d1bafeea1   Kload   [fix] Upgrade to ...
474
  			}
6d9380f96   Cédric Dupont   Update sources OC...
475
476
477
478
479
480
481
482
  		} else {
  			if (!trim($id)) {
  				throw new \Exception(
  					__METHOD__ . ' Missing or empty second argument \'$id\'.'
  				);
  			}
  			$queries[] = $id;
  			$queryIdentifier .= 'byid';
d1bafeea1   Kload   [fix] Upgrade to ...
483
  		}
d1bafeea1   Kload   [fix] Upgrade to ...
484

6d9380f96   Cédric Dupont   Update sources OC...
485
486
487
488
  		if ($noCollection) {
  			$queryIdentifier .= 'nocollection';
  		} else {
  			$queries[] = $addressBookId;
d1bafeea1   Kload   [fix] Upgrade to ...
489
490
491
  		}
  
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
492
493
  			//\OCP\Util::writeLog('contacts', __METHOD__.', identifier: '. $queryIdentifier . ', queries: ' . implode(',', $queries), \OCP\Util::DEBUG);
  			$result = $this->getPreparedQuery($queryIdentifier)->execute($queries);
d1bafeea1   Kload   [fix] Upgrade to ...
494
495
496
497
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return null;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
498
499
  
  		} catch (\Exception $e) {
d1bafeea1   Kload   [fix] Upgrade to ...
500
501
502
503
504
505
  			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
  			\OCP\Util::writeLog('contacts', __METHOD__.', id: '. $id, \OCP\Util::DEBUG);
  			return null;
  		}
  
  		$row = $result->fetchRow();
6d9380f96   Cédric Dupont   Update sources OC...
506
507
  
  		if (!$row) {
d1bafeea1   Kload   [fix] Upgrade to ...
508
509
510
  			\OCP\Util::writeLog('contacts', __METHOD__.', Not found, id: '. $id, \OCP\Util::DEBUG);
  			return null;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
511

d1bafeea1   Kload   [fix] Upgrade to ...
512
513
514
  		$row['permissions'] = \OCP\PERMISSION_ALL;
  		return $row;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
515
516
517
518
519
520
521
  	public function hasContact($addressBookId, $id) {
  		try {
  			return $this->getContact($addressBookId, $id) !== null;
  		} catch (\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
d1bafeea1   Kload   [fix] Upgrade to ...
522
523
524
525
526
527
528
529
530
531
532
533
  	}
  
  	/**
  	 * Creates a new contact
  	 *
  	 * In the Database and Shared backends contact be either a Contact object or a string
  	 * with carddata to be able to play seamlessly with the CardDAV backend.
  	 * If this method is called by the CardDAV backend, the carddata is already validated.
  	 * NOTE: It's assumed that this method is called either from the CardDAV backend, the
  	 * import script, or from the ownCloud web UI in which case either the uri parameter is
  	 * set, or the contact has a UID. If neither is set, it will fail.
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
534
  	 * @param string $addressBookId
d1bafeea1   Kload   [fix] Upgrade to ...
535
536
537
538
  	 * @param VCard|string $contact
  	 * @param array $options - Optional (backend specific options)
  	 * @return string|bool The identifier for the new contact or false on error.
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
539
540
  	public function createContact($addressBookId, $contact, array $options = array()) {
  		//\OCP\Util::writeLog('contacts', __METHOD__.' addressBookId: ' . $addressBookId, \OCP\Util::DEBUG);
d1bafeea1   Kload   [fix] Upgrade to ...
541

d1bafeea1   Kload   [fix] Upgrade to ...
542
  		$uri = isset($options['uri']) ? $options['uri'] : null;
6d9380f96   Cédric Dupont   Update sources OC...
543
  		if (!$contact instanceof VCard) {
d1bafeea1   Kload   [fix] Upgrade to ...
544
545
546
547
548
549
550
551
552
553
554
  			try {
  				$contact = Reader::read($contact);
  			} catch(\Exception $e) {
  				\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
  				return false;
  			}
  		}
  
  		try {
  			$contact->validate(VCard::REPAIR|VCard::UPGRADE);
  		} catch (\Exception $e) {
6d9380f96   Cédric Dupont   Update sources OC...
555
  			\OCP\Util::writeLog('contacts', __METHOD__ . ' ' .
d1bafeea1   Kload   [fix] Upgrade to ...
556
557
558
  				'Error validating vcard: ' . $e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
559
  		$uri = is_null($uri) ? $this->uniqueURI($addressBookId, $contact->UID . '.vcf') : $uri;
d1bafeea1   Kload   [fix] Upgrade to ...
560
561
562
563
564
  		$now = new \DateTime;
  		$contact->REV = $now->format(\DateTime::W3C);
  
  		$appinfo = \OCP\App::getAppInfo('contacts');
  		$appversion = \OCP\App::getAppVersion('contacts');
6d9380f96   Cédric Dupont   Update sources OC...
565
  		$prodid = '-//ownCloud//NONSGML ' . $appinfo['name'] . ' ' . $appversion.'//EN';
d1bafeea1   Kload   [fix] Upgrade to ...
566
  		$contact->PRODID = $prodid;
d1bafeea1   Kload   [fix] Upgrade to ...
567
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
568
  			$result = $this->getPreparedQuery('createcontact')
d1bafeea1   Kload   [fix] Upgrade to ...
569
570
  				->execute(
  					array(
6d9380f96   Cédric Dupont   Update sources OC...
571
  						$addressBookId,
d1bafeea1   Kload   [fix] Upgrade to ...
572
573
574
575
576
577
  						(string)$contact->FN,
  						$contact->serialize(),
  						$uri,
  						time()
  					)
  				);
6d9380f96   Cédric Dupont   Update sources OC...
578

d1bafeea1   Kload   [fix] Upgrade to ...
579
580
581
582
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
583

d1bafeea1   Kload   [fix] Upgrade to ...
584
585
586
587
588
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
  			return false;
  		}
  		$newid = \OCP\DB::insertid($this->cardsTableName);
6d9380f96   Cédric Dupont   Update sources OC...
589
  		$this->setModifiedAddressBook($addressBookId);
d1bafeea1   Kload   [fix] Upgrade to ...
590
  		\OCP\Util::emitHook('OCA\Contacts', 'post_createContact',
6d9380f96   Cédric Dupont   Update sources OC...
591
  			array('id' => $newid, 'parent' => $addressBookId, 'backend' => $this->name, 'contact' => $contact)
d1bafeea1   Kload   [fix] Upgrade to ...
592
593
594
595
596
597
598
  		);
  		return (string)$newid;
  	}
  
  	/**
  	 * Updates a contact
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
599
600
  	 * @param string $addressBookId
  	 * @param string|array $id Contact ID
d1bafeea1   Kload   [fix] Upgrade to ...
601
602
603
604
  	 * @param VCard|string $contact
  	 * @param array $options - Optional (backend specific options)
  	 * @see getContact
  	 * @return bool
6d9380f96   Cédric Dupont   Update sources OC...
605
606
  	 * @throws \Exception if $contact is a string but can't be parsed as a VCard
  	 * @throws \Exception if the Contact to update couldn't be found
d1bafeea1   Kload   [fix] Upgrade to ...
607
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
608
609
  	public function updateContact($addressBookId, $id, $contact, array $options = array()) {
  		//\OCP\Util::writeLog('contacts', __METHOD__.' identifier: ' . $addressBookId . ' / ' . $id, \OCP\Util::DEBUG);
d1bafeea1   Kload   [fix] Upgrade to ...
610
611
  		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
  		$isBatch = isset($options['isBatch']) ? $options['isBatch'] : false;
d1bafeea1   Kload   [fix] Upgrade to ...
612
613
614
  
  		$updateRevision = true;
  		$isCardDAV = false;
6d9380f96   Cédric Dupont   Update sources OC...
615
616
  
  		if (!$contact instanceof VCard) {
d1bafeea1   Kload   [fix] Upgrade to ...
617
618
619
620
621
622
623
  			try {
  				$contact = Reader::read($contact);
  			} catch(\Exception $e) {
  				\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
  				return false;
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
624
625
626
  		if (is_array($id)) {
  
  			if (isset($id['id'])) {
d1bafeea1   Kload   [fix] Upgrade to ...
627
  				$id = $id['id'];
6d9380f96   Cédric Dupont   Update sources OC...
628
  			} elseif (isset($id['uri'])) {
d1bafeea1   Kload   [fix] Upgrade to ...
629
630
631
  				$updateRevision = false;
  				$isCardDAV = true;
  				$id = $this->getIdFromUri($id['uri']);
6d9380f96   Cédric Dupont   Update sources OC...
632
633
  
  				if (is_null($id)) {
d1bafeea1   Kload   [fix] Upgrade to ...
634
635
636
  					\OCP\Util::writeLog('contacts', __METHOD__ . ' Couldn\'t find contact', \OCP\Util::ERROR);
  					return false;
  				}
6d9380f96   Cédric Dupont   Update sources OC...
637

d1bafeea1   Kload   [fix] Upgrade to ...
638
639
640
641
642
643
  			} else {
  				throw new \Exception(
  					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
  				);
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
644
  		if ($updateRevision || !isset($contact->REV)) {
d1bafeea1   Kload   [fix] Upgrade to ...
645
646
647
648
649
  			$now = new \DateTime;
  			$contact->REV = $now->format(\DateTime::W3C);
  		}
  
  		$data = $contact->serialize();
6d9380f96   Cédric Dupont   Update sources OC...
650
  		if ($noCollection) {
d1bafeea1   Kload   [fix] Upgrade to ...
651
  			$me = $this->getContact(null, $id, $options);
6d9380f96   Cédric Dupont   Update sources OC...
652
  			$addressBookId = $me['parent'];
d1bafeea1   Kload   [fix] Upgrade to ...
653
  		}
6d9380f96   Cédric Dupont   Update sources OC...
654
  		$updates = array($contact->FN, $data, time(), $id, $addressBookId);
d1bafeea1   Kload   [fix] Upgrade to ...
655

d1bafeea1   Kload   [fix] Upgrade to ...
656
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
657
658
  
  			$result = $this->getPreparedQuery('updatecontact')->execute($updates);
d1bafeea1   Kload   [fix] Upgrade to ...
659
660
661
662
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
663

d1bafeea1   Kload   [fix] Upgrade to ...
664
665
666
667
668
669
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '
  				. $e->getMessage(), \OCP\Util::ERROR);
  			\OCP\Util::writeLog('contacts', __METHOD__.', id' . $id, \OCP\Util::DEBUG);
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
670
671
672
  		$this->setModifiedAddressBook($addressBookId);
  
  		if (!$isBatch) {
d1bafeea1   Kload   [fix] Upgrade to ...
673
674
675
  			\OCP\Util::emitHook('OCA\Contacts', 'post_updateContact',
  				array(
  					'backend' => $this->name,
6d9380f96   Cédric Dupont   Update sources OC...
676
  					'addressBookId' => $addressBookId,
d1bafeea1   Kload   [fix] Upgrade to ...
677
678
679
680
681
  					'contactId' => $id,
  					'contact' => $contact,
  					'carddav' => $isCardDAV
  				)
  			);
6d9380f96   Cédric Dupont   Update sources OC...
682

d1bafeea1   Kload   [fix] Upgrade to ...
683
  		}
6d9380f96   Cédric Dupont   Update sources OC...
684

d1bafeea1   Kload   [fix] Upgrade to ...
685
686
687
688
689
690
  		return true;
  	}
  
  	/**
  	 * Deletes a contact
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
691
692
  	 * @param string $addressBookId
  	 * @param string|array $id
d1bafeea1   Kload   [fix] Upgrade to ...
693
694
695
696
  	 * @param array $options - Optional (backend specific options)
  	 * @see getContact
  	 * @return bool
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
697
  	public function deleteContact($addressBookId, $id, array $options = array()) {
d1bafeea1   Kload   [fix] Upgrade to ...
698
  		// TODO: pass the uri in $options instead.
d1bafeea1   Kload   [fix] Upgrade to ...
699
700
  		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
  		$isBatch = isset($options['isBatch']) ? $options['isBatch'] : false;
6d9380f96   Cédric Dupont   Update sources OC...
701
702
703
  		if (is_array($id)) {
  
  			if (isset($id['id'])) {
d1bafeea1   Kload   [fix] Upgrade to ...
704
  				$id = $id['id'];
6d9380f96   Cédric Dupont   Update sources OC...
705
  			} elseif (isset($id['uri'])) {
d1bafeea1   Kload   [fix] Upgrade to ...
706
  				$id = $this->getIdFromUri($id['uri']);
6d9380f96   Cédric Dupont   Update sources OC...
707
708
  
  				if (is_null($id)) {
d1bafeea1   Kload   [fix] Upgrade to ...
709
710
711
  					\OCP\Util::writeLog('contacts', __METHOD__ . ' Couldn\'t find contact', \OCP\Util::ERROR);
  					return false;
  				}
6d9380f96   Cédric Dupont   Update sources OC...
712

d1bafeea1   Kload   [fix] Upgrade to ...
713
  			} else {
6d9380f96   Cédric Dupont   Update sources OC...
714
  				throw new \Exception(
d1bafeea1   Kload   [fix] Upgrade to ...
715
716
717
718
  					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
  				);
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
719
  		if (!$isBatch) {
d1bafeea1   Kload   [fix] Upgrade to ...
720
721
722
723
  			\OCP\Util::emitHook('OCA\Contacts', 'pre_deleteContact',
  				array('id' => $id)
  			);
  		}
6d9380f96   Cédric Dupont   Update sources OC...
724
  		if ($noCollection) {
d1bafeea1   Kload   [fix] Upgrade to ...
725
  			$me = $this->getContact(null, $id, $options);
6d9380f96   Cédric Dupont   Update sources OC...
726
  			$addressBookId = $me['parent'];
d1bafeea1   Kload   [fix] Upgrade to ...
727
  		}
d1bafeea1   Kload   [fix] Upgrade to ...
728
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
729
730
731
  
  			$result = $this->getPreparedQuery('deletecontact')
  				->execute(array($id, $addressBookId));
d1bafeea1   Kload   [fix] Upgrade to ...
732
733
734
735
736
  			if (\OCP\DB::isError($result)) {
  				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
  					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  				return false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
737

d1bafeea1   Kload   [fix] Upgrade to ...
738
739
740
741
742
743
744
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__.
  				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
  			\OCP\Util::writeLog('contacts', __METHOD__.', id: '
  				. $id, \OCP\Util::DEBUG);
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
745
746
  
  		$this->setModifiedAddressBook($addressBookId);
d1bafeea1   Kload   [fix] Upgrade to ...
747
748
749
750
751
752
753
754
755
  		return true;
  	}
  
  	/**
  	 * @brief Get the last modification time for a contact.
  	 *
  	 * Must return a UNIX time stamp or null if the backend
  	 * doesn't support it.
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
756
  	 * @param string $addressBookId
d1bafeea1   Kload   [fix] Upgrade to ...
757
758
759
  	 * @param mixed $id
  	 * @returns int | null
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
760
761
762
  	public function lastModifiedContact($addressBookId, $id) {
  
  		$contact = $this->getContact($addressBookId, $id);
d1bafeea1   Kload   [fix] Upgrade to ...
763
  		return ($contact ? $contact['lastmodified'] : null);
6d9380f96   Cédric Dupont   Update sources OC...
764

d1bafeea1   Kload   [fix] Upgrade to ...
765
766
767
768
769
770
771
772
773
  	}
  
  	/**
  	 * @brief Get the contact id from the uri.
  	 *
  	 * @param mixed $id
  	 * @returns int | null
  	 */
  	public function getIdFromUri($uri) {
6d9380f96   Cédric Dupont   Update sources OC...
774
775
  
  		$stmt = $this->getPreparedQuery('contactidfromuri');
d1bafeea1   Kload   [fix] Upgrade to ...
776
  		$result = $stmt->execute(array($uri));
6d9380f96   Cédric Dupont   Update sources OC...
777

d1bafeea1   Kload   [fix] Upgrade to ...
778
779
780
781
  		if (\OCP\DB::isError($result)) {
  			\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
  			return null;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
782

d1bafeea1   Kload   [fix] Upgrade to ...
783
  		$one = $result->fetchOne();
6d9380f96   Cédric Dupont   Update sources OC...
784
785
  
  		if (!$one) {
d1bafeea1   Kload   [fix] Upgrade to ...
786
787
788
  			\OCP\Util::writeLog('contacts', __METHOD__.', Not found, uri: '. $uri, \OCP\Util::DEBUG);
  			return null;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
789

d1bafeea1   Kload   [fix] Upgrade to ...
790
791
  		return $one;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
792
793
794
795
796
797
798
799
800
  	/**
  	 * Create a unique URI based on the display name.
  	 *
  	 * @param string $displayName
  	 * @return string
  	 */
  	private function createAddressBookURI($displayName) {
  
  		$name = str_replace(' ', '_', strtolower($displayName));
d1bafeea1   Kload   [fix] Upgrade to ...
801
  		try {
6d9380f96   Cédric Dupont   Update sources OC...
802
803
  			$stmt = $this->getPreparedQuery('addressbookuris');
  			$result = $stmt->execute(array($this->userid));
d1bafeea1   Kload   [fix] Upgrade to ...
804
  			if (\OCP\DB::isError($result)) {
6d9380f96   Cédric Dupont   Update sources OC...
805
806
807
808
  				\OCP\Util::writeLog('contacts',
  					__METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result),
  					\OCP\Util::ERROR
  				);
d1bafeea1   Kload   [fix] Upgrade to ...
809
810
  				return $name;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
811

d1bafeea1   Kload   [fix] Upgrade to ...
812
813
814
815
816
  		} catch(\Exception $e) {
  			\OCP\Util::writeLog('contacts', __METHOD__ . ' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
  			return $name;
  		}
  		$uris = array();
6d9380f96   Cédric Dupont   Update sources OC...
817
  		while ($row = $result->fetchRow()) {
d1bafeea1   Kload   [fix] Upgrade to ...
818
819
820
821
  			$uris[] = $row['uri'];
  		}
  
  		$newname = $name;
6d9380f96   Cédric Dupont   Update sources OC...
822
823
824
  		$i = 1
  		;
  		while (in_array($newname, $uris)) {
d1bafeea1   Kload   [fix] Upgrade to ...
825
826
827
828
829
830
831
832
833
834
835
836
837
  			$newname = $name.$i;
  			$i = $i + 1;
  		}
  		return $newname;
  	}
  
  	/**
  	* @brief Checks if a contact with the same URI already exist in the address book.
  	* @param string $addressBookId Address book ID.
  	* @param string $uri
  	* @returns string Unique URI
  	*/
  	protected function uniqueURI($addressBookId, $uri) {
6d9380f96   Cédric Dupont   Update sources OC...
838
  		$stmt = $this->getPreparedQuery('counturi');
d1bafeea1   Kload   [fix] Upgrade to ...
839
840
  
  		$result = $stmt->execute(array($addressBookId, $uri));
6d9380f96   Cédric Dupont   Update sources OC...
841
  		$result = $result->fetchRow();
d1bafeea1   Kload   [fix] Upgrade to ...
842

6d9380f96   Cédric Dupont   Update sources OC...
843
844
845
  		if (is_array($result) && count($result) > 0 && $result['count'] > 0) {
  
  			while (true) {
d1bafeea1   Kload   [fix] Upgrade to ...
846
847
  				$uri = Properties::generateUID() . '.vcf';
  				$result = $stmt->execute(array($addressBookId, $uri));
6d9380f96   Cédric Dupont   Update sources OC...
848
849
  
  				if (is_array($result) && count($result) > 0 && $result['count'] > 0) {
d1bafeea1   Kload   [fix] Upgrade to ...
850
851
852
853
  					continue;
  				} else {
  					return $uri;
  				}
6d9380f96   Cédric Dupont   Update sources OC...
854

d1bafeea1   Kload   [fix] Upgrade to ...
855
  			}
d1bafeea1   Kload   [fix] Upgrade to ...
856
  		}
6d9380f96   Cédric Dupont   Update sources OC...
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
  
  		return $uri;
  	}
  
  	/**
  	* Collect (nearly) all queries in one place
  	*
  	* @param string $identifier
  	* @param array $options Can be used for e.g. offset/limit
  	* @throws \Exception If $identifier isn't known
  	* @return \OC_DB_StatementWrapper
  	*/
  	protected function getPreparedQuery($identifier, array $options = array()) {
  
  		if (isset(self::$preparedQueries[$identifier])) {
  			return self::$preparedQueries[$identifier];
  		}
  
  		$args = array();
  
  		switch ($identifier) {
  
  			case 'getaddressbooksforuser':
  				$args[] = 'SELECT `id`, `displayname`, `description`, `ctag`'
  					. ' AS `lastmodified`, `userid` AS `owner`, `uri` FROM `'
  					. $this->addressBooksTableName
  					. '` WHERE `userid` = ? ORDER BY `displayname`';
  				break;
  			case 'getaddressbook':
  				$args[] = 'SELECT `id`, `displayname`, `description`, '
  						. '`userid` AS `owner`, `ctag` AS `lastmodified`, `uri` FROM `'
  						. $this->addressBooksTableName
  						. '` WHERE `id` = ? AND `userid` = ?';
  				break;
  			case 'createaddressbook':
  				$args[] = 'INSERT INTO `'
  						. $this->addressBooksTableName . '` '
  						. '(`userid`,`displayname`,`uri`,`description`,`ctag`) '
  						. 'VALUES(?,?,?,?,?)';
  				break;
  			case 'deleteaddressbookcontacts':
  				$args[] = 'DELETE FROM `' . $this->cardsTableName
  						. '` WHERE `addressbookid` = ?';
  				break;
  			case 'deleteaddressbook':
  				$args[] = 'DELETE FROM `'
  						. $this->addressBooksTableName . '` WHERE `id` = ?';
  				break;
  			case 'touchaddressbook':
  				$args[] = 'UPDATE `' . $this->addressBooksTableName
  						. '` SET `ctag` = ? + 1 WHERE `id` = ?';
  				break;
  			case 'counturi':
  				$args[] = 'SELECT COUNT(*) AS `count` FROM `'
  						. $this->cardsTableName
  						. '` WHERE `addressbookid` = ? AND `uri` = ?';
  				break;
  			case 'addressbookuris':
  				$args[] = 'SELECT `uri` FROM `'
  						. $this->addressBooksTableName . '` WHERE `userid` = ? ';
  				break;
  			case 'contactidfromuri':
  				$args[] = 'SELECT `id` FROM `'
  						. $this->cardsTableName
  						. '` WHERE `uri` = ?';
  				break;
  			case 'deletecontact':
  				$args[] = 'DELETE FROM `'
  					. $this->cardsTableName
  					. '` WHERE `id` = ? AND `addressbookid` = ?';
  				break;
  			case 'updatecontact':
  				$args[] = 'UPDATE `' . $this->cardsTableName
  						. '` SET `fullname` = ?,`carddata` = ?, `lastmodified` = ?'
  						. ' WHERE `id` = ? AND `addressbookid` = ?';
  				break;
  			case 'createcontact':
  				$args[] = 'INSERT INTO `'
  					. $this->cardsTableName
  					. '` (`addressbookid`,`fullname`,`carddata`,`uri`,`lastmodified`) '
  					. ' VALUES(?,?,?,?,?)';
  				break;
  			case 'getcontactbyid':
  				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
  						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
  						. $this->cardsTableName
  						. '` WHERE `id` = ? AND `addressbookid` = ?';
  				break;
  			case 'getcontactbyuri':
  				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
  						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
  						. $this->cardsTableName
  						. '` WHERE `uri` = ? AND `addressbookid` = ?';
  				break;
  			case 'getcontactbyidnocollection':
  				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
  						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
  						. $this->cardsTableName . '` WHERE `id` = ?';
  				break;
  			case 'getcontactbyurinocollection':
  				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
  						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
  						. $this->cardsTableName . '` WHERE `uri` = ?';
  				break;
  			case 'getcontactids':
  				$args[] = 'SELECT `id` FROM `'
  						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
  				break;
  			case 'getcontacts':
  				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
  						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
  						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
  				$args[] = isset($options['limit']) ? $options['limit'] : null;
  				$args[] = isset($options['offset']) ? $options['offset'] : null;
  				break;
  			case 'getcontactsomitdata':
  				$args[] = 'SELECT `id`, `uri`, `lastmodified`, '
  						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
  						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
  				$args[] = isset($options['limit']) ? $options['limit'] : null;
  				$args[] = isset($options['offset']) ? $options['offset'] : null;
  				break;
  			case 'numcontacts':
  				$args[] = 'SELECT COUNT(*) AS `count` FROM `'
  						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
  				break;
  			default:
  				throw new \Exception('Unknown query identifier: ' . $identifier);
  
  		}
  
  		self::$preparedQueries[$identifier] = call_user_func_array('\OCP\DB::prepare', $args);
  
  		return self::$preparedQueries[$identifier];
  	}
  
  	public function getSearchProvider($addressbook) {
  		return new \OCA\Contacts\AddressbookProvider($addressbook);
d1bafeea1   Kload   [fix] Upgrade to ...
995
  	}
6d9380f96   Cédric Dupont   Update sources OC...
996
  	
d1bafeea1   Kload   [fix] Upgrade to ...
997
  }