1<?php
2/**
3 * @author Thomas Müller <thomas.mueller@tmit.eu>
4 *
5 * @copyright Copyright (c) 2018, ownCloud GmbH
6 * @license AGPL-3.0
7 *
8 * This code is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License, version 3,
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License, version 3,
18 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19 *
20 */
21namespace OCA\DAV\CardDAV;
22
23use OCA\DAV\DAV\Sharing\IShareable;
24use Sabre\CardDAV\Card;
25use Sabre\DAV\Exception\Forbidden;
26use Sabre\DAV\Exception\NotFound;
27use Sabre\DAV\PropPatch;
28
29class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
30
31	/**
32	 * Updates the list of shares.
33	 *
34	 * The first array is a list of people that are to be added to the
35	 * addressbook.
36	 *
37	 * Every element in the add array has the following properties:
38	 *   * href - A url. Usually a mailto: address
39	 *   * commonName - Usually a first and last name, or false
40	 *   * summary - A description of the share, can also be false
41	 *   * readOnly - A boolean value
42	 *
43	 * Every element in the remove array is just the address string.
44	 *
45	 * @param array $add
46	 * @param array $remove
47	 * @return void
48	 */
49	public function updateShares(array $add, array $remove) {
50		/** @var CardDavBackend $cardDavBackend */
51		$cardDavBackend = $this->carddavBackend;
52		'@phan-var CardDavBackend $cardDavBackend';
53		$cardDavBackend->updateShares($this, $add, $remove);
54	}
55
56	/**
57	 * Returns the list of people whom this addressbook is shared with.
58	 *
59	 * Every element in this array should have the following properties:
60	 *   * href - Often a mailto: address
61	 *   * commonName - Optional, for example a first + last name
62	 *   * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
63	 *   * readOnly - boolean
64	 *   * summary - Optional, a description for the share
65	 *
66	 * @return array
67	 */
68	public function getShares() {
69		/** @var CardDavBackend $cardDavBackend */
70		$cardDavBackend = $this->carddavBackend;
71		'@phan-var CardDavBackend $cardDavBackend';
72		return $cardDavBackend->getShares($this->getResourceId());
73	}
74
75	public function getACL() {
76		$acl =  [
77			[
78				'privilege' => '{DAV:}read',
79				'principal' => $this->getOwner(),
80				'protected' => true,
81			]];
82		$acl[] = [
83				'privilege' => '{DAV:}write',
84				'principal' => $this->getOwner(),
85				'protected' => true,
86			];
87		if ($this->getOwner() !== parent::getOwner()) {
88			$acl[] =  [
89					'privilege' => '{DAV:}read',
90					'principal' => parent::getOwner(),
91					'protected' => true,
92				];
93			if ($this->canWrite()) {
94				$acl[] = [
95					'privilege' => '{DAV:}write',
96					'principal' => parent::getOwner(),
97					'protected' => true,
98				];
99			}
100		}
101		if ($this->getOwner() === 'principals/system/system') {
102			$acl[] = [
103					'privilege' => '{DAV:}read',
104					'principal' => '{DAV:}authenticated',
105					'protected' => true,
106			];
107		}
108
109		/** @var CardDavBackend $cardDavBackend */
110		$cardDavBackend = $this->carddavBackend;
111		'@phan-var CardDavBackend $cardDavBackend';
112		return $cardDavBackend->applyShareAcl($this->getResourceId(), $acl);
113	}
114
115	public function getChildACL() {
116		return $this->getACL();
117	}
118
119	public function getChild($name) {
120		$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name);
121		if (!$obj) {
122			throw new NotFound('Card not found');
123		}
124		$obj['acl'] = $this->getChildACL();
125		return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
126	}
127
128	/**
129	 * @return int
130	 */
131	public function getResourceId() {
132		return $this->addressBookInfo['id'];
133	}
134
135	public function getOwner() {
136		if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
137			return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'];
138		}
139		return parent::getOwner();
140	}
141
142	public function delete() {
143		if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
144			$principal = 'principal:' . parent::getOwner();
145			$shares = $this->getShares();
146			$shares = \array_filter($shares, function ($share) use ($principal) {
147				return $share['href'] === $principal;
148			});
149			if (empty($shares)) {
150				throw new Forbidden();
151			}
152
153			/** @var CardDavBackend $cardDavBackend */
154			$cardDavBackend = $this->carddavBackend;
155			'@phan-var CardDavBackend $cardDavBackend';
156			$cardDavBackend->updateShares($this, [], [
157				$principal
158			]);
159			return;
160		}
161		parent::delete();
162	}
163
164	public function propPatch(PropPatch $propPatch) {
165		if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
166			throw new Forbidden();
167		}
168		parent::propPatch($propPatch);
169	}
170
171	public function getContactsGroups() {
172		/** @var CardDavBackend $cardDavBackend */
173		$cardDavBackend = $this->carddavBackend;
174		'@phan-var CardDavBackend $cardDavBackend';
175
176		return $cardDavBackend->collectCardProperties($this->getResourceId(), 'CATEGORIES');
177	}
178
179	private function canWrite() {
180		if (isset($this->addressBookInfo['{http://owncloud.org/ns}read-only'])) {
181			return !$this->addressBookInfo['{http://owncloud.org/ns}read-only'];
182		}
183		return true;
184	}
185}
186