Completed
Pull Request — master (#5734)
by Joas
53:47 queued 37:03
created
lib/private/Share20/Manager.php 1 patch
Indentation   +1358 added lines, -1358 removed lines patch added patch discarded remove patch
@@ -56,1386 +56,1386 @@
 block discarded – undo
56 56
  */
57 57
 class Manager implements IManager {
58 58
 
59
-	/** @var IProviderFactory */
60
-	private $factory;
61
-	/** @var ILogger */
62
-	private $logger;
63
-	/** @var IConfig */
64
-	private $config;
65
-	/** @var ISecureRandom */
66
-	private $secureRandom;
67
-	/** @var IHasher */
68
-	private $hasher;
69
-	/** @var IMountManager */
70
-	private $mountManager;
71
-	/** @var IGroupManager */
72
-	private $groupManager;
73
-	/** @var IL10N */
74
-	private $l;
75
-	/** @var IUserManager */
76
-	private $userManager;
77
-	/** @var IRootFolder */
78
-	private $rootFolder;
79
-	/** @var CappedMemoryCache */
80
-	private $sharingDisabledForUsersCache;
81
-	/** @var EventDispatcher */
82
-	private $eventDispatcher;
83
-	/** @var LegacyHooks */
84
-	private $legacyHooks;
85
-
86
-
87
-	/**
88
-	 * Manager constructor.
89
-	 *
90
-	 * @param ILogger $logger
91
-	 * @param IConfig $config
92
-	 * @param ISecureRandom $secureRandom
93
-	 * @param IHasher $hasher
94
-	 * @param IMountManager $mountManager
95
-	 * @param IGroupManager $groupManager
96
-	 * @param IL10N $l
97
-	 * @param IProviderFactory $factory
98
-	 * @param IUserManager $userManager
99
-	 * @param IRootFolder $rootFolder
100
-	 * @param EventDispatcher $eventDispatcher
101
-	 */
102
-	public function __construct(
103
-			ILogger $logger,
104
-			IConfig $config,
105
-			ISecureRandom $secureRandom,
106
-			IHasher $hasher,
107
-			IMountManager $mountManager,
108
-			IGroupManager $groupManager,
109
-			IL10N $l,
110
-			IProviderFactory $factory,
111
-			IUserManager $userManager,
112
-			IRootFolder $rootFolder,
113
-			EventDispatcher $eventDispatcher
114
-	) {
115
-		$this->logger = $logger;
116
-		$this->config = $config;
117
-		$this->secureRandom = $secureRandom;
118
-		$this->hasher = $hasher;
119
-		$this->mountManager = $mountManager;
120
-		$this->groupManager = $groupManager;
121
-		$this->l = $l;
122
-		$this->factory = $factory;
123
-		$this->userManager = $userManager;
124
-		$this->rootFolder = $rootFolder;
125
-		$this->eventDispatcher = $eventDispatcher;
126
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
127
-		$this->legacyHooks = new LegacyHooks($this->eventDispatcher);
128
-	}
129
-
130
-	/**
131
-	 * Convert from a full share id to a tuple (providerId, shareId)
132
-	 *
133
-	 * @param string $id
134
-	 * @return string[]
135
-	 */
136
-	private function splitFullId($id) {
137
-		return explode(':', $id, 2);
138
-	}
139
-
140
-	/**
141
-	 * Verify if a password meets all requirements
142
-	 *
143
-	 * @param string $password
144
-	 * @throws \Exception
145
-	 */
146
-	protected function verifyPassword($password) {
147
-		if ($password === null) {
148
-			// No password is set, check if this is allowed.
149
-			if ($this->shareApiLinkEnforcePassword()) {
150
-				throw new \InvalidArgumentException('Passwords are enforced for link shares');
151
-			}
152
-
153
-			return;
154
-		}
155
-
156
-		// Let others verify the password
157
-		try {
158
-			$event = new GenericEvent($password);
159
-			$this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
160
-		} catch (HintException $e) {
161
-			throw new \Exception($e->getHint());
162
-		}
163
-	}
164
-
165
-	/**
166
-	 * Check for generic requirements before creating a share
167
-	 *
168
-	 * @param \OCP\Share\IShare $share
169
-	 * @throws \InvalidArgumentException
170
-	 * @throws GenericShareException
171
-	 */
172
-	protected function generalCreateChecks(\OCP\Share\IShare $share) {
173
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
174
-			// We expect a valid user as sharedWith for user shares
175
-			if (!$this->userManager->userExists($share->getSharedWith())) {
176
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
177
-			}
178
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
179
-			// We expect a valid group as sharedWith for group shares
180
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
181
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
182
-			}
183
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
184
-			if ($share->getSharedWith() !== null) {
185
-				throw new \InvalidArgumentException('SharedWith should be empty');
186
-			}
187
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
188
-			if ($share->getSharedWith() === null) {
189
-				throw new \InvalidArgumentException('SharedWith should not be empty');
190
-			}
191
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
192
-			if ($share->getSharedWith() === null) {
193
-				throw new \InvalidArgumentException('SharedWith should not be empty');
194
-			}
195
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
196
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
197
-			if ($circle === null) {
198
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
199
-			}
200
-		} else {
201
-			// We can't handle other types yet
202
-			throw new \InvalidArgumentException('unknown share type');
203
-		}
204
-
205
-		// Verify the initiator of the share is set
206
-		if ($share->getSharedBy() === null) {
207
-			throw new \InvalidArgumentException('SharedBy should be set');
208
-		}
209
-
210
-		// Cannot share with yourself
211
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
212
-			$share->getSharedWith() === $share->getSharedBy()) {
213
-			throw new \InvalidArgumentException('Can’t share with yourself');
214
-		}
215
-
216
-		// The path should be set
217
-		if ($share->getNode() === null) {
218
-			throw new \InvalidArgumentException('Path should be set');
219
-		}
220
-
221
-		// And it should be a file or a folder
222
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
223
-				!($share->getNode() instanceof \OCP\Files\Folder)) {
224
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
225
-		}
226
-
227
-		// And you can't share your rootfolder
228
-		if ($this->userManager->userExists($share->getSharedBy())) {
229
-			$sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
230
-		} else {
231
-			$sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
232
-		}
233
-		if ($sharedPath === $share->getNode()->getPath()) {
234
-			throw new \InvalidArgumentException('You can’t share your root folder');
235
-		}
236
-
237
-		// Check if we actually have share permissions
238
-		if (!$share->getNode()->isShareable()) {
239
-			$message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
240
-			throw new GenericShareException($message_t, $message_t, 404);
241
-		}
242
-
243
-		// Permissions should be set
244
-		if ($share->getPermissions() === null) {
245
-			throw new \InvalidArgumentException('A share requires permissions');
246
-		}
247
-
248
-		/*
59
+    /** @var IProviderFactory */
60
+    private $factory;
61
+    /** @var ILogger */
62
+    private $logger;
63
+    /** @var IConfig */
64
+    private $config;
65
+    /** @var ISecureRandom */
66
+    private $secureRandom;
67
+    /** @var IHasher */
68
+    private $hasher;
69
+    /** @var IMountManager */
70
+    private $mountManager;
71
+    /** @var IGroupManager */
72
+    private $groupManager;
73
+    /** @var IL10N */
74
+    private $l;
75
+    /** @var IUserManager */
76
+    private $userManager;
77
+    /** @var IRootFolder */
78
+    private $rootFolder;
79
+    /** @var CappedMemoryCache */
80
+    private $sharingDisabledForUsersCache;
81
+    /** @var EventDispatcher */
82
+    private $eventDispatcher;
83
+    /** @var LegacyHooks */
84
+    private $legacyHooks;
85
+
86
+
87
+    /**
88
+     * Manager constructor.
89
+     *
90
+     * @param ILogger $logger
91
+     * @param IConfig $config
92
+     * @param ISecureRandom $secureRandom
93
+     * @param IHasher $hasher
94
+     * @param IMountManager $mountManager
95
+     * @param IGroupManager $groupManager
96
+     * @param IL10N $l
97
+     * @param IProviderFactory $factory
98
+     * @param IUserManager $userManager
99
+     * @param IRootFolder $rootFolder
100
+     * @param EventDispatcher $eventDispatcher
101
+     */
102
+    public function __construct(
103
+            ILogger $logger,
104
+            IConfig $config,
105
+            ISecureRandom $secureRandom,
106
+            IHasher $hasher,
107
+            IMountManager $mountManager,
108
+            IGroupManager $groupManager,
109
+            IL10N $l,
110
+            IProviderFactory $factory,
111
+            IUserManager $userManager,
112
+            IRootFolder $rootFolder,
113
+            EventDispatcher $eventDispatcher
114
+    ) {
115
+        $this->logger = $logger;
116
+        $this->config = $config;
117
+        $this->secureRandom = $secureRandom;
118
+        $this->hasher = $hasher;
119
+        $this->mountManager = $mountManager;
120
+        $this->groupManager = $groupManager;
121
+        $this->l = $l;
122
+        $this->factory = $factory;
123
+        $this->userManager = $userManager;
124
+        $this->rootFolder = $rootFolder;
125
+        $this->eventDispatcher = $eventDispatcher;
126
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
127
+        $this->legacyHooks = new LegacyHooks($this->eventDispatcher);
128
+    }
129
+
130
+    /**
131
+     * Convert from a full share id to a tuple (providerId, shareId)
132
+     *
133
+     * @param string $id
134
+     * @return string[]
135
+     */
136
+    private function splitFullId($id) {
137
+        return explode(':', $id, 2);
138
+    }
139
+
140
+    /**
141
+     * Verify if a password meets all requirements
142
+     *
143
+     * @param string $password
144
+     * @throws \Exception
145
+     */
146
+    protected function verifyPassword($password) {
147
+        if ($password === null) {
148
+            // No password is set, check if this is allowed.
149
+            if ($this->shareApiLinkEnforcePassword()) {
150
+                throw new \InvalidArgumentException('Passwords are enforced for link shares');
151
+            }
152
+
153
+            return;
154
+        }
155
+
156
+        // Let others verify the password
157
+        try {
158
+            $event = new GenericEvent($password);
159
+            $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
160
+        } catch (HintException $e) {
161
+            throw new \Exception($e->getHint());
162
+        }
163
+    }
164
+
165
+    /**
166
+     * Check for generic requirements before creating a share
167
+     *
168
+     * @param \OCP\Share\IShare $share
169
+     * @throws \InvalidArgumentException
170
+     * @throws GenericShareException
171
+     */
172
+    protected function generalCreateChecks(\OCP\Share\IShare $share) {
173
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
174
+            // We expect a valid user as sharedWith for user shares
175
+            if (!$this->userManager->userExists($share->getSharedWith())) {
176
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
177
+            }
178
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
179
+            // We expect a valid group as sharedWith for group shares
180
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
181
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
182
+            }
183
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
184
+            if ($share->getSharedWith() !== null) {
185
+                throw new \InvalidArgumentException('SharedWith should be empty');
186
+            }
187
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
188
+            if ($share->getSharedWith() === null) {
189
+                throw new \InvalidArgumentException('SharedWith should not be empty');
190
+            }
191
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
192
+            if ($share->getSharedWith() === null) {
193
+                throw new \InvalidArgumentException('SharedWith should not be empty');
194
+            }
195
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
196
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
197
+            if ($circle === null) {
198
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
199
+            }
200
+        } else {
201
+            // We can't handle other types yet
202
+            throw new \InvalidArgumentException('unknown share type');
203
+        }
204
+
205
+        // Verify the initiator of the share is set
206
+        if ($share->getSharedBy() === null) {
207
+            throw new \InvalidArgumentException('SharedBy should be set');
208
+        }
209
+
210
+        // Cannot share with yourself
211
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
212
+            $share->getSharedWith() === $share->getSharedBy()) {
213
+            throw new \InvalidArgumentException('Can’t share with yourself');
214
+        }
215
+
216
+        // The path should be set
217
+        if ($share->getNode() === null) {
218
+            throw new \InvalidArgumentException('Path should be set');
219
+        }
220
+
221
+        // And it should be a file or a folder
222
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
223
+                !($share->getNode() instanceof \OCP\Files\Folder)) {
224
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
225
+        }
226
+
227
+        // And you can't share your rootfolder
228
+        if ($this->userManager->userExists($share->getSharedBy())) {
229
+            $sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
230
+        } else {
231
+            $sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
232
+        }
233
+        if ($sharedPath === $share->getNode()->getPath()) {
234
+            throw new \InvalidArgumentException('You can’t share your root folder');
235
+        }
236
+
237
+        // Check if we actually have share permissions
238
+        if (!$share->getNode()->isShareable()) {
239
+            $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
240
+            throw new GenericShareException($message_t, $message_t, 404);
241
+        }
242
+
243
+        // Permissions should be set
244
+        if ($share->getPermissions() === null) {
245
+            throw new \InvalidArgumentException('A share requires permissions');
246
+        }
247
+
248
+        /*
249 249
 		 * Quick fix for #23536
250 250
 		 * Non moveable mount points do not have update and delete permissions
251 251
 		 * while we 'most likely' do have that on the storage.
252 252
 		 */
253
-		$permissions = $share->getNode()->getPermissions();
254
-		$mount = $share->getNode()->getMountPoint();
255
-		if (!($mount instanceof MoveableMount)) {
256
-			$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
257
-		}
258
-
259
-		// Check that we do not share with more permissions than we have
260
-		if ($share->getPermissions() & ~$permissions) {
261
-			$message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
262
-			throw new GenericShareException($message_t, $message_t, 404);
263
-		}
264
-
265
-
266
-		// Check that read permissions are always set
267
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
268
-		$noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
269
-			|| $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
270
-		if (!$noReadPermissionRequired &&
271
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
272
-			throw new \InvalidArgumentException('Shares need at least read permissions');
273
-		}
274
-
275
-		if ($share->getNode() instanceof \OCP\Files\File) {
276
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
277
-				$message_t = $this->l->t('Files can’t be shared with delete permissions');
278
-				throw new GenericShareException($message_t);
279
-			}
280
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
281
-				$message_t = $this->l->t('Files can’t be shared with create permissions');
282
-				throw new GenericShareException($message_t);
283
-			}
284
-		}
285
-	}
286
-
287
-	/**
288
-	 * Validate if the expiration date fits the system settings
289
-	 *
290
-	 * @param \OCP\Share\IShare $share The share to validate the expiration date of
291
-	 * @return \OCP\Share\IShare The modified share object
292
-	 * @throws GenericShareException
293
-	 * @throws \InvalidArgumentException
294
-	 * @throws \Exception
295
-	 */
296
-	protected function validateExpirationDate(\OCP\Share\IShare $share) {
297
-
298
-		$expirationDate = $share->getExpirationDate();
299
-
300
-		if ($expirationDate !== null) {
301
-			//Make sure the expiration date is a date
302
-			$expirationDate->setTime(0, 0, 0);
303
-
304
-			$date = new \DateTime();
305
-			$date->setTime(0, 0, 0);
306
-			if ($date >= $expirationDate) {
307
-				$message = $this->l->t('Expiration date is in the past');
308
-				throw new GenericShareException($message, $message, 404);
309
-			}
310
-		}
311
-
312
-		// If expiredate is empty set a default one if there is a default
313
-		$fullId = null;
314
-		try {
315
-			$fullId = $share->getFullId();
316
-		} catch (\UnexpectedValueException $e) {
317
-			// This is a new share
318
-		}
319
-
320
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
321
-			$expirationDate = new \DateTime();
322
-			$expirationDate->setTime(0,0,0);
323
-			$expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
324
-		}
325
-
326
-		// If we enforce the expiration date check that is does not exceed
327
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
328
-			if ($expirationDate === null) {
329
-				throw new \InvalidArgumentException('Expiration date is enforced');
330
-			}
331
-
332
-			$date = new \DateTime();
333
-			$date->setTime(0, 0, 0);
334
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
335
-			if ($date < $expirationDate) {
336
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
337
-				throw new GenericShareException($message, $message, 404);
338
-			}
339
-		}
340
-
341
-		$accepted = true;
342
-		$message = '';
343
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
344
-			'expirationDate' => &$expirationDate,
345
-			'accepted' => &$accepted,
346
-			'message' => &$message,
347
-			'passwordSet' => $share->getPassword() !== null,
348
-		]);
349
-
350
-		if (!$accepted) {
351
-			throw new \Exception($message);
352
-		}
353
-
354
-		$share->setExpirationDate($expirationDate);
355
-
356
-		return $share;
357
-	}
358
-
359
-	/**
360
-	 * Check for pre share requirements for user shares
361
-	 *
362
-	 * @param \OCP\Share\IShare $share
363
-	 * @throws \Exception
364
-	 */
365
-	protected function userCreateChecks(\OCP\Share\IShare $share) {
366
-		// Check if we can share with group members only
367
-		if ($this->shareWithGroupMembersOnly()) {
368
-			$sharedBy = $this->userManager->get($share->getSharedBy());
369
-			$sharedWith = $this->userManager->get($share->getSharedWith());
370
-			// Verify we can share with this user
371
-			$groups = array_intersect(
372
-					$this->groupManager->getUserGroupIds($sharedBy),
373
-					$this->groupManager->getUserGroupIds($sharedWith)
374
-			);
375
-			if (empty($groups)) {
376
-				throw new \Exception('Sharing is only allowed with group members');
377
-			}
378
-		}
379
-
380
-		/*
253
+        $permissions = $share->getNode()->getPermissions();
254
+        $mount = $share->getNode()->getMountPoint();
255
+        if (!($mount instanceof MoveableMount)) {
256
+            $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
257
+        }
258
+
259
+        // Check that we do not share with more permissions than we have
260
+        if ($share->getPermissions() & ~$permissions) {
261
+            $message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
262
+            throw new GenericShareException($message_t, $message_t, 404);
263
+        }
264
+
265
+
266
+        // Check that read permissions are always set
267
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
268
+        $noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
269
+            || $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
270
+        if (!$noReadPermissionRequired &&
271
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
272
+            throw new \InvalidArgumentException('Shares need at least read permissions');
273
+        }
274
+
275
+        if ($share->getNode() instanceof \OCP\Files\File) {
276
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
277
+                $message_t = $this->l->t('Files can’t be shared with delete permissions');
278
+                throw new GenericShareException($message_t);
279
+            }
280
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
281
+                $message_t = $this->l->t('Files can’t be shared with create permissions');
282
+                throw new GenericShareException($message_t);
283
+            }
284
+        }
285
+    }
286
+
287
+    /**
288
+     * Validate if the expiration date fits the system settings
289
+     *
290
+     * @param \OCP\Share\IShare $share The share to validate the expiration date of
291
+     * @return \OCP\Share\IShare The modified share object
292
+     * @throws GenericShareException
293
+     * @throws \InvalidArgumentException
294
+     * @throws \Exception
295
+     */
296
+    protected function validateExpirationDate(\OCP\Share\IShare $share) {
297
+
298
+        $expirationDate = $share->getExpirationDate();
299
+
300
+        if ($expirationDate !== null) {
301
+            //Make sure the expiration date is a date
302
+            $expirationDate->setTime(0, 0, 0);
303
+
304
+            $date = new \DateTime();
305
+            $date->setTime(0, 0, 0);
306
+            if ($date >= $expirationDate) {
307
+                $message = $this->l->t('Expiration date is in the past');
308
+                throw new GenericShareException($message, $message, 404);
309
+            }
310
+        }
311
+
312
+        // If expiredate is empty set a default one if there is a default
313
+        $fullId = null;
314
+        try {
315
+            $fullId = $share->getFullId();
316
+        } catch (\UnexpectedValueException $e) {
317
+            // This is a new share
318
+        }
319
+
320
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
321
+            $expirationDate = new \DateTime();
322
+            $expirationDate->setTime(0,0,0);
323
+            $expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
324
+        }
325
+
326
+        // If we enforce the expiration date check that is does not exceed
327
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
328
+            if ($expirationDate === null) {
329
+                throw new \InvalidArgumentException('Expiration date is enforced');
330
+            }
331
+
332
+            $date = new \DateTime();
333
+            $date->setTime(0, 0, 0);
334
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
335
+            if ($date < $expirationDate) {
336
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
337
+                throw new GenericShareException($message, $message, 404);
338
+            }
339
+        }
340
+
341
+        $accepted = true;
342
+        $message = '';
343
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
344
+            'expirationDate' => &$expirationDate,
345
+            'accepted' => &$accepted,
346
+            'message' => &$message,
347
+            'passwordSet' => $share->getPassword() !== null,
348
+        ]);
349
+
350
+        if (!$accepted) {
351
+            throw new \Exception($message);
352
+        }
353
+
354
+        $share->setExpirationDate($expirationDate);
355
+
356
+        return $share;
357
+    }
358
+
359
+    /**
360
+     * Check for pre share requirements for user shares
361
+     *
362
+     * @param \OCP\Share\IShare $share
363
+     * @throws \Exception
364
+     */
365
+    protected function userCreateChecks(\OCP\Share\IShare $share) {
366
+        // Check if we can share with group members only
367
+        if ($this->shareWithGroupMembersOnly()) {
368
+            $sharedBy = $this->userManager->get($share->getSharedBy());
369
+            $sharedWith = $this->userManager->get($share->getSharedWith());
370
+            // Verify we can share with this user
371
+            $groups = array_intersect(
372
+                    $this->groupManager->getUserGroupIds($sharedBy),
373
+                    $this->groupManager->getUserGroupIds($sharedWith)
374
+            );
375
+            if (empty($groups)) {
376
+                throw new \Exception('Sharing is only allowed with group members');
377
+            }
378
+        }
379
+
380
+        /*
381 381
 		 * TODO: Could be costly, fix
382 382
 		 *
383 383
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
384 384
 		 */
385
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
386
-		$existingShares = $provider->getSharesByPath($share->getNode());
387
-		foreach($existingShares as $existingShare) {
388
-			// Ignore if it is the same share
389
-			try {
390
-				if ($existingShare->getFullId() === $share->getFullId()) {
391
-					continue;
392
-				}
393
-			} catch (\UnexpectedValueException $e) {
394
-				//Shares are not identical
395
-			}
396
-
397
-			// Identical share already existst
398
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
399
-				throw new \Exception('Path is already shared with this user');
400
-			}
401
-
402
-			// The share is already shared with this user via a group share
403
-			if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
404
-				$group = $this->groupManager->get($existingShare->getSharedWith());
405
-				if (!is_null($group)) {
406
-					$user = $this->userManager->get($share->getSharedWith());
407
-
408
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
409
-						throw new \Exception('Path is already shared with this user');
410
-					}
411
-				}
412
-			}
413
-		}
414
-	}
415
-
416
-	/**
417
-	 * Check for pre share requirements for group shares
418
-	 *
419
-	 * @param \OCP\Share\IShare $share
420
-	 * @throws \Exception
421
-	 */
422
-	protected function groupCreateChecks(\OCP\Share\IShare $share) {
423
-		// Verify group shares are allowed
424
-		if (!$this->allowGroupSharing()) {
425
-			throw new \Exception('Group sharing is now allowed');
426
-		}
427
-
428
-		// Verify if the user can share with this group
429
-		if ($this->shareWithGroupMembersOnly()) {
430
-			$sharedBy = $this->userManager->get($share->getSharedBy());
431
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
432
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
433
-				throw new \Exception('Sharing is only allowed within your own groups');
434
-			}
435
-		}
436
-
437
-		/*
385
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
386
+        $existingShares = $provider->getSharesByPath($share->getNode());
387
+        foreach($existingShares as $existingShare) {
388
+            // Ignore if it is the same share
389
+            try {
390
+                if ($existingShare->getFullId() === $share->getFullId()) {
391
+                    continue;
392
+                }
393
+            } catch (\UnexpectedValueException $e) {
394
+                //Shares are not identical
395
+            }
396
+
397
+            // Identical share already existst
398
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
399
+                throw new \Exception('Path is already shared with this user');
400
+            }
401
+
402
+            // The share is already shared with this user via a group share
403
+            if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
404
+                $group = $this->groupManager->get($existingShare->getSharedWith());
405
+                if (!is_null($group)) {
406
+                    $user = $this->userManager->get($share->getSharedWith());
407
+
408
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
409
+                        throw new \Exception('Path is already shared with this user');
410
+                    }
411
+                }
412
+            }
413
+        }
414
+    }
415
+
416
+    /**
417
+     * Check for pre share requirements for group shares
418
+     *
419
+     * @param \OCP\Share\IShare $share
420
+     * @throws \Exception
421
+     */
422
+    protected function groupCreateChecks(\OCP\Share\IShare $share) {
423
+        // Verify group shares are allowed
424
+        if (!$this->allowGroupSharing()) {
425
+            throw new \Exception('Group sharing is now allowed');
426
+        }
427
+
428
+        // Verify if the user can share with this group
429
+        if ($this->shareWithGroupMembersOnly()) {
430
+            $sharedBy = $this->userManager->get($share->getSharedBy());
431
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
432
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
433
+                throw new \Exception('Sharing is only allowed within your own groups');
434
+            }
435
+        }
436
+
437
+        /*
438 438
 		 * TODO: Could be costly, fix
439 439
 		 *
440 440
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
441 441
 		 */
442
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
443
-		$existingShares = $provider->getSharesByPath($share->getNode());
444
-		foreach($existingShares as $existingShare) {
445
-			try {
446
-				if ($existingShare->getFullId() === $share->getFullId()) {
447
-					continue;
448
-				}
449
-			} catch (\UnexpectedValueException $e) {
450
-				//It is a new share so just continue
451
-			}
452
-
453
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
454
-				throw new \Exception('Path is already shared with this group');
455
-			}
456
-		}
457
-	}
458
-
459
-	/**
460
-	 * Check for pre share requirements for link shares
461
-	 *
462
-	 * @param \OCP\Share\IShare $share
463
-	 * @throws \Exception
464
-	 */
465
-	protected function linkCreateChecks(\OCP\Share\IShare $share) {
466
-		// Are link shares allowed?
467
-		if (!$this->shareApiAllowLinks()) {
468
-			throw new \Exception('Link sharing is not allowed');
469
-		}
470
-
471
-		// Link shares by definition can't have share permissions
472
-		if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
473
-			throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
474
-		}
475
-
476
-		// Check if public upload is allowed
477
-		if (!$this->shareApiLinkAllowPublicUpload() &&
478
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
479
-			throw new \InvalidArgumentException('Public upload is not allowed');
480
-		}
481
-	}
482
-
483
-	/**
484
-	 * To make sure we don't get invisible link shares we set the parent
485
-	 * of a link if it is a reshare. This is a quick word around
486
-	 * until we can properly display multiple link shares in the UI
487
-	 *
488
-	 * See: https://github.com/owncloud/core/issues/22295
489
-	 *
490
-	 * FIXME: Remove once multiple link shares can be properly displayed
491
-	 *
492
-	 * @param \OCP\Share\IShare $share
493
-	 */
494
-	protected function setLinkParent(\OCP\Share\IShare $share) {
495
-
496
-		// No sense in checking if the method is not there.
497
-		if (method_exists($share, 'setParent')) {
498
-			$storage = $share->getNode()->getStorage();
499
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
500
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
501
-				$share->setParent($storage->getShareId());
502
-			}
503
-		};
504
-	}
505
-
506
-	/**
507
-	 * @param File|Folder $path
508
-	 */
509
-	protected function pathCreateChecks($path) {
510
-		// Make sure that we do not share a path that contains a shared mountpoint
511
-		if ($path instanceof \OCP\Files\Folder) {
512
-			$mounts = $this->mountManager->findIn($path->getPath());
513
-			foreach($mounts as $mount) {
514
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
515
-					throw new \InvalidArgumentException('Path contains files shared with you');
516
-				}
517
-			}
518
-		}
519
-	}
520
-
521
-	/**
522
-	 * Check if the user that is sharing can actually share
523
-	 *
524
-	 * @param \OCP\Share\IShare $share
525
-	 * @throws \Exception
526
-	 */
527
-	protected function canShare(\OCP\Share\IShare $share) {
528
-		if (!$this->shareApiEnabled()) {
529
-			throw new \Exception('Sharing is disabled');
530
-		}
531
-
532
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
533
-			throw new \Exception('Sharing is disabled for you');
534
-		}
535
-	}
536
-
537
-	/**
538
-	 * Share a path
539
-	 *
540
-	 * @param \OCP\Share\IShare $share
541
-	 * @return Share The share object
542
-	 * @throws \Exception
543
-	 *
544
-	 * TODO: handle link share permissions or check them
545
-	 */
546
-	public function createShare(\OCP\Share\IShare $share) {
547
-		$this->canShare($share);
548
-
549
-		$this->generalCreateChecks($share);
550
-
551
-		// Verify if there are any issues with the path
552
-		$this->pathCreateChecks($share->getNode());
553
-
554
-		/*
442
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
443
+        $existingShares = $provider->getSharesByPath($share->getNode());
444
+        foreach($existingShares as $existingShare) {
445
+            try {
446
+                if ($existingShare->getFullId() === $share->getFullId()) {
447
+                    continue;
448
+                }
449
+            } catch (\UnexpectedValueException $e) {
450
+                //It is a new share so just continue
451
+            }
452
+
453
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
454
+                throw new \Exception('Path is already shared with this group');
455
+            }
456
+        }
457
+    }
458
+
459
+    /**
460
+     * Check for pre share requirements for link shares
461
+     *
462
+     * @param \OCP\Share\IShare $share
463
+     * @throws \Exception
464
+     */
465
+    protected function linkCreateChecks(\OCP\Share\IShare $share) {
466
+        // Are link shares allowed?
467
+        if (!$this->shareApiAllowLinks()) {
468
+            throw new \Exception('Link sharing is not allowed');
469
+        }
470
+
471
+        // Link shares by definition can't have share permissions
472
+        if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
473
+            throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
474
+        }
475
+
476
+        // Check if public upload is allowed
477
+        if (!$this->shareApiLinkAllowPublicUpload() &&
478
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
479
+            throw new \InvalidArgumentException('Public upload is not allowed');
480
+        }
481
+    }
482
+
483
+    /**
484
+     * To make sure we don't get invisible link shares we set the parent
485
+     * of a link if it is a reshare. This is a quick word around
486
+     * until we can properly display multiple link shares in the UI
487
+     *
488
+     * See: https://github.com/owncloud/core/issues/22295
489
+     *
490
+     * FIXME: Remove once multiple link shares can be properly displayed
491
+     *
492
+     * @param \OCP\Share\IShare $share
493
+     */
494
+    protected function setLinkParent(\OCP\Share\IShare $share) {
495
+
496
+        // No sense in checking if the method is not there.
497
+        if (method_exists($share, 'setParent')) {
498
+            $storage = $share->getNode()->getStorage();
499
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
500
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
501
+                $share->setParent($storage->getShareId());
502
+            }
503
+        };
504
+    }
505
+
506
+    /**
507
+     * @param File|Folder $path
508
+     */
509
+    protected function pathCreateChecks($path) {
510
+        // Make sure that we do not share a path that contains a shared mountpoint
511
+        if ($path instanceof \OCP\Files\Folder) {
512
+            $mounts = $this->mountManager->findIn($path->getPath());
513
+            foreach($mounts as $mount) {
514
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
515
+                    throw new \InvalidArgumentException('Path contains files shared with you');
516
+                }
517
+            }
518
+        }
519
+    }
520
+
521
+    /**
522
+     * Check if the user that is sharing can actually share
523
+     *
524
+     * @param \OCP\Share\IShare $share
525
+     * @throws \Exception
526
+     */
527
+    protected function canShare(\OCP\Share\IShare $share) {
528
+        if (!$this->shareApiEnabled()) {
529
+            throw new \Exception('Sharing is disabled');
530
+        }
531
+
532
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
533
+            throw new \Exception('Sharing is disabled for you');
534
+        }
535
+    }
536
+
537
+    /**
538
+     * Share a path
539
+     *
540
+     * @param \OCP\Share\IShare $share
541
+     * @return Share The share object
542
+     * @throws \Exception
543
+     *
544
+     * TODO: handle link share permissions or check them
545
+     */
546
+    public function createShare(\OCP\Share\IShare $share) {
547
+        $this->canShare($share);
548
+
549
+        $this->generalCreateChecks($share);
550
+
551
+        // Verify if there are any issues with the path
552
+        $this->pathCreateChecks($share->getNode());
553
+
554
+        /*
555 555
 		 * On creation of a share the owner is always the owner of the path
556 556
 		 * Except for mounted federated shares.
557 557
 		 */
558
-		$storage = $share->getNode()->getStorage();
559
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
560
-			$parent = $share->getNode()->getParent();
561
-			while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
562
-				$parent = $parent->getParent();
563
-			}
564
-			$share->setShareOwner($parent->getOwner()->getUID());
565
-		} else {
566
-			$share->setShareOwner($share->getNode()->getOwner()->getUID());
567
-		}
568
-
569
-		//Verify share type
570
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
571
-			$this->userCreateChecks($share);
572
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
573
-			$this->groupCreateChecks($share);
574
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
575
-			$this->linkCreateChecks($share);
576
-			$this->setLinkParent($share);
577
-
578
-			/*
558
+        $storage = $share->getNode()->getStorage();
559
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
560
+            $parent = $share->getNode()->getParent();
561
+            while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
562
+                $parent = $parent->getParent();
563
+            }
564
+            $share->setShareOwner($parent->getOwner()->getUID());
565
+        } else {
566
+            $share->setShareOwner($share->getNode()->getOwner()->getUID());
567
+        }
568
+
569
+        //Verify share type
570
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
571
+            $this->userCreateChecks($share);
572
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
573
+            $this->groupCreateChecks($share);
574
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
575
+            $this->linkCreateChecks($share);
576
+            $this->setLinkParent($share);
577
+
578
+            /*
579 579
 			 * For now ignore a set token.
580 580
 			 */
581
-			$share->setToken(
582
-				$this->secureRandom->generate(
583
-					\OC\Share\Constants::TOKEN_LENGTH,
584
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
585
-				)
586
-			);
587
-
588
-			//Verify the expiration date
589
-			$this->validateExpirationDate($share);
590
-
591
-			//Verify the password
592
-			$this->verifyPassword($share->getPassword());
593
-
594
-			// If a password is set. Hash it!
595
-			if ($share->getPassword() !== null) {
596
-				$share->setPassword($this->hasher->hash($share->getPassword()));
597
-			}
598
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
599
-			$share->setToken(
600
-				$this->secureRandom->generate(
601
-					\OC\Share\Constants::TOKEN_LENGTH,
602
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
603
-				)
604
-			);
605
-		}
606
-
607
-		// Cannot share with the owner
608
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
609
-			$share->getSharedWith() === $share->getShareOwner()) {
610
-			throw new \InvalidArgumentException('Can’t share with the share owner');
611
-		}
612
-
613
-		// Generate the target
614
-		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
615
-		$target = \OC\Files\Filesystem::normalizePath($target);
616
-		$share->setTarget($target);
617
-
618
-		// Pre share hook
619
-		$run = true;
620
-		$error = '';
621
-		$preHookData = [
622
-			'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
623
-			'itemSource' => $share->getNode()->getId(),
624
-			'shareType' => $share->getShareType(),
625
-			'uidOwner' => $share->getSharedBy(),
626
-			'permissions' => $share->getPermissions(),
627
-			'fileSource' => $share->getNode()->getId(),
628
-			'expiration' => $share->getExpirationDate(),
629
-			'token' => $share->getToken(),
630
-			'itemTarget' => $share->getTarget(),
631
-			'shareWith' => $share->getSharedWith(),
632
-			'run' => &$run,
633
-			'error' => &$error,
634
-		];
635
-		\OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
636
-
637
-		if ($run === false) {
638
-			throw new \Exception($error);
639
-		}
640
-
641
-		$oldShare = $share;
642
-		$provider = $this->factory->getProviderForType($share->getShareType());
643
-		$share = $provider->create($share);
644
-		//reuse the node we already have
645
-		$share->setNode($oldShare->getNode());
646
-
647
-		// Post share hook
648
-		$postHookData = [
649
-			'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
650
-			'itemSource' => $share->getNode()->getId(),
651
-			'shareType' => $share->getShareType(),
652
-			'uidOwner' => $share->getSharedBy(),
653
-			'permissions' => $share->getPermissions(),
654
-			'fileSource' => $share->getNode()->getId(),
655
-			'expiration' => $share->getExpirationDate(),
656
-			'token' => $share->getToken(),
657
-			'id' => $share->getId(),
658
-			'shareWith' => $share->getSharedWith(),
659
-			'itemTarget' => $share->getTarget(),
660
-			'fileTarget' => $share->getTarget(),
661
-		];
662
-
663
-		\OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
664
-
665
-		return $share;
666
-	}
667
-
668
-	/**
669
-	 * Update a share
670
-	 *
671
-	 * @param \OCP\Share\IShare $share
672
-	 * @return \OCP\Share\IShare The share object
673
-	 * @throws \InvalidArgumentException
674
-	 */
675
-	public function updateShare(\OCP\Share\IShare $share) {
676
-		$expirationDateUpdated = false;
677
-
678
-		$this->canShare($share);
679
-
680
-		try {
681
-			$originalShare = $this->getShareById($share->getFullId());
682
-		} catch (\UnexpectedValueException $e) {
683
-			throw new \InvalidArgumentException('Share does not have a full id');
684
-		}
685
-
686
-		// We can't change the share type!
687
-		if ($share->getShareType() !== $originalShare->getShareType()) {
688
-			throw new \InvalidArgumentException('Can’t change share type');
689
-		}
690
-
691
-		// We can only change the recipient on user shares
692
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
693
-		    $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
694
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
695
-		}
696
-
697
-		// Cannot share with the owner
698
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
699
-			$share->getSharedWith() === $share->getShareOwner()) {
700
-			throw new \InvalidArgumentException('Can’t share with the share owner');
701
-		}
702
-
703
-		$this->generalCreateChecks($share);
704
-
705
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
706
-			$this->userCreateChecks($share);
707
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
708
-			$this->groupCreateChecks($share);
709
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
710
-			$this->linkCreateChecks($share);
711
-
712
-			$this->updateSharePasswordIfNeeded($share, $originalShare);
713
-
714
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
715
-				//Verify the expiration date
716
-				$this->validateExpirationDate($share);
717
-				$expirationDateUpdated = true;
718
-			}
719
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
720
-			$plainTextPassword = $share->getPassword();
721
-			if (!$this->updateSharePasswordIfNeeded($share, $originalShare)) {
722
-				$plainTextPassword = null;
723
-			}
724
-		}
725
-
726
-		$this->pathCreateChecks($share->getNode());
727
-
728
-		// Now update the share!
729
-		$provider = $this->factory->getProviderForType($share->getShareType());
730
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
731
-			$share = $provider->update($share, $plainTextPassword);
732
-		} else {
733
-			$share = $provider->update($share);
734
-		}
735
-
736
-		if ($expirationDateUpdated === true) {
737
-			\OC_Hook::emit('OCP\Share', 'post_set_expiration_date', [
738
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
739
-				'itemSource' => $share->getNode()->getId(),
740
-				'date' => $share->getExpirationDate(),
741
-				'uidOwner' => $share->getSharedBy(),
742
-			]);
743
-		}
744
-
745
-		if ($share->getPassword() !== $originalShare->getPassword()) {
746
-			\OC_Hook::emit('OCP\Share', 'post_update_password', [
747
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
748
-				'itemSource' => $share->getNode()->getId(),
749
-				'uidOwner' => $share->getSharedBy(),
750
-				'token' => $share->getToken(),
751
-				'disabled' => is_null($share->getPassword()),
752
-			]);
753
-		}
754
-
755
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
756
-			if ($this->userManager->userExists($share->getShareOwner())) {
757
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
758
-			} else {
759
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
760
-			}
761
-			\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
762
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
763
-				'itemSource' => $share->getNode()->getId(),
764
-				'shareType' => $share->getShareType(),
765
-				'shareWith' => $share->getSharedWith(),
766
-				'uidOwner' => $share->getSharedBy(),
767
-				'permissions' => $share->getPermissions(),
768
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
769
-			));
770
-		}
771
-
772
-		return $share;
773
-	}
774
-
775
-	/**
776
-	 * Updates the password of the given share if it is not the same as the
777
-	 * password of the original share.
778
-	 *
779
-	 * @param \OCP\Share\IShare $share the share to update its password.
780
-	 * @param \OCP\Share\IShare $originalShare the original share to compare its
781
-	 *        password with.
782
-	 * @return boolean whether the password was updated or not.
783
-	 */
784
-	private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
785
-		// Password updated.
786
-		if ($share->getPassword() !== $originalShare->getPassword()) {
787
-			//Verify the password
788
-			$this->verifyPassword($share->getPassword());
789
-
790
-			// If a password is set. Hash it!
791
-			if ($share->getPassword() !== null) {
792
-				$share->setPassword($this->hasher->hash($share->getPassword()));
793
-
794
-				return true;
795
-			}
796
-		}
797
-
798
-		return false;
799
-	}
800
-
801
-	/**
802
-	 * Delete all the children of this share
803
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
804
-	 *
805
-	 * @param \OCP\Share\IShare $share
806
-	 * @return \OCP\Share\IShare[] List of deleted shares
807
-	 */
808
-	protected function deleteChildren(\OCP\Share\IShare $share) {
809
-		$deletedShares = [];
810
-
811
-		$provider = $this->factory->getProviderForType($share->getShareType());
812
-
813
-		foreach ($provider->getChildren($share) as $child) {
814
-			$deletedChildren = $this->deleteChildren($child);
815
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
816
-
817
-			$provider->delete($child);
818
-			$deletedShares[] = $child;
819
-		}
820
-
821
-		return $deletedShares;
822
-	}
823
-
824
-	/**
825
-	 * Delete a share
826
-	 *
827
-	 * @param \OCP\Share\IShare $share
828
-	 * @throws ShareNotFound
829
-	 * @throws \InvalidArgumentException
830
-	 */
831
-	public function deleteShare(\OCP\Share\IShare $share) {
832
-
833
-		try {
834
-			$share->getFullId();
835
-		} catch (\UnexpectedValueException $e) {
836
-			throw new \InvalidArgumentException('Share does not have a full id');
837
-		}
838
-
839
-		$event = new GenericEvent($share);
840
-		$this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
841
-
842
-		// Get all children and delete them as well
843
-		$deletedShares = $this->deleteChildren($share);
844
-
845
-		// Do the actual delete
846
-		$provider = $this->factory->getProviderForType($share->getShareType());
847
-		$provider->delete($share);
848
-
849
-		// All the deleted shares caused by this delete
850
-		$deletedShares[] = $share;
851
-
852
-		// Emit post hook
853
-		$event->setArgument('deletedShares', $deletedShares);
854
-		$this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
855
-	}
856
-
857
-
858
-	/**
859
-	 * Unshare a file as the recipient.
860
-	 * This can be different from a regular delete for example when one of
861
-	 * the users in a groups deletes that share. But the provider should
862
-	 * handle this.
863
-	 *
864
-	 * @param \OCP\Share\IShare $share
865
-	 * @param string $recipientId
866
-	 */
867
-	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
868
-		list($providerId, ) = $this->splitFullId($share->getFullId());
869
-		$provider = $this->factory->getProvider($providerId);
870
-
871
-		$provider->deleteFromSelf($share, $recipientId);
872
-	}
873
-
874
-	/**
875
-	 * @inheritdoc
876
-	 */
877
-	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
878
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
879
-			throw new \InvalidArgumentException('Can’t change target of link share');
880
-		}
881
-
882
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
883
-			throw new \InvalidArgumentException('Invalid recipient');
884
-		}
885
-
886
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
887
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
888
-			if (is_null($sharedWith)) {
889
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
890
-			}
891
-			$recipient = $this->userManager->get($recipientId);
892
-			if (!$sharedWith->inGroup($recipient)) {
893
-				throw new \InvalidArgumentException('Invalid recipient');
894
-			}
895
-		}
896
-
897
-		list($providerId, ) = $this->splitFullId($share->getFullId());
898
-		$provider = $this->factory->getProvider($providerId);
899
-
900
-		$provider->move($share, $recipientId);
901
-	}
902
-
903
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
904
-		$providers = $this->factory->getAllProviders();
905
-
906
-		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
907
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
908
-			foreach ($newShares as $fid => $data) {
909
-				if (!isset($shares[$fid])) {
910
-					$shares[$fid] = [];
911
-				}
912
-
913
-				$shares[$fid] = array_merge($shares[$fid], $data);
914
-			}
915
-			return $shares;
916
-		}, []);
917
-	}
918
-
919
-	/**
920
-	 * @inheritdoc
921
-	 */
922
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
923
-		if ($path !== null &&
924
-				!($path instanceof \OCP\Files\File) &&
925
-				!($path instanceof \OCP\Files\Folder)) {
926
-			throw new \InvalidArgumentException('invalid path');
927
-		}
928
-
929
-		try {
930
-			$provider = $this->factory->getProviderForType($shareType);
931
-		} catch (ProviderException $e) {
932
-			return [];
933
-		}
934
-
935
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
936
-
937
-		/*
581
+            $share->setToken(
582
+                $this->secureRandom->generate(
583
+                    \OC\Share\Constants::TOKEN_LENGTH,
584
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
585
+                )
586
+            );
587
+
588
+            //Verify the expiration date
589
+            $this->validateExpirationDate($share);
590
+
591
+            //Verify the password
592
+            $this->verifyPassword($share->getPassword());
593
+
594
+            // If a password is set. Hash it!
595
+            if ($share->getPassword() !== null) {
596
+                $share->setPassword($this->hasher->hash($share->getPassword()));
597
+            }
598
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
599
+            $share->setToken(
600
+                $this->secureRandom->generate(
601
+                    \OC\Share\Constants::TOKEN_LENGTH,
602
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
603
+                )
604
+            );
605
+        }
606
+
607
+        // Cannot share with the owner
608
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
609
+            $share->getSharedWith() === $share->getShareOwner()) {
610
+            throw new \InvalidArgumentException('Can’t share with the share owner');
611
+        }
612
+
613
+        // Generate the target
614
+        $target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
615
+        $target = \OC\Files\Filesystem::normalizePath($target);
616
+        $share->setTarget($target);
617
+
618
+        // Pre share hook
619
+        $run = true;
620
+        $error = '';
621
+        $preHookData = [
622
+            'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
623
+            'itemSource' => $share->getNode()->getId(),
624
+            'shareType' => $share->getShareType(),
625
+            'uidOwner' => $share->getSharedBy(),
626
+            'permissions' => $share->getPermissions(),
627
+            'fileSource' => $share->getNode()->getId(),
628
+            'expiration' => $share->getExpirationDate(),
629
+            'token' => $share->getToken(),
630
+            'itemTarget' => $share->getTarget(),
631
+            'shareWith' => $share->getSharedWith(),
632
+            'run' => &$run,
633
+            'error' => &$error,
634
+        ];
635
+        \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
636
+
637
+        if ($run === false) {
638
+            throw new \Exception($error);
639
+        }
640
+
641
+        $oldShare = $share;
642
+        $provider = $this->factory->getProviderForType($share->getShareType());
643
+        $share = $provider->create($share);
644
+        //reuse the node we already have
645
+        $share->setNode($oldShare->getNode());
646
+
647
+        // Post share hook
648
+        $postHookData = [
649
+            'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
650
+            'itemSource' => $share->getNode()->getId(),
651
+            'shareType' => $share->getShareType(),
652
+            'uidOwner' => $share->getSharedBy(),
653
+            'permissions' => $share->getPermissions(),
654
+            'fileSource' => $share->getNode()->getId(),
655
+            'expiration' => $share->getExpirationDate(),
656
+            'token' => $share->getToken(),
657
+            'id' => $share->getId(),
658
+            'shareWith' => $share->getSharedWith(),
659
+            'itemTarget' => $share->getTarget(),
660
+            'fileTarget' => $share->getTarget(),
661
+        ];
662
+
663
+        \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
664
+
665
+        return $share;
666
+    }
667
+
668
+    /**
669
+     * Update a share
670
+     *
671
+     * @param \OCP\Share\IShare $share
672
+     * @return \OCP\Share\IShare The share object
673
+     * @throws \InvalidArgumentException
674
+     */
675
+    public function updateShare(\OCP\Share\IShare $share) {
676
+        $expirationDateUpdated = false;
677
+
678
+        $this->canShare($share);
679
+
680
+        try {
681
+            $originalShare = $this->getShareById($share->getFullId());
682
+        } catch (\UnexpectedValueException $e) {
683
+            throw new \InvalidArgumentException('Share does not have a full id');
684
+        }
685
+
686
+        // We can't change the share type!
687
+        if ($share->getShareType() !== $originalShare->getShareType()) {
688
+            throw new \InvalidArgumentException('Can’t change share type');
689
+        }
690
+
691
+        // We can only change the recipient on user shares
692
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
693
+            $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
694
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
695
+        }
696
+
697
+        // Cannot share with the owner
698
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
699
+            $share->getSharedWith() === $share->getShareOwner()) {
700
+            throw new \InvalidArgumentException('Can’t share with the share owner');
701
+        }
702
+
703
+        $this->generalCreateChecks($share);
704
+
705
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
706
+            $this->userCreateChecks($share);
707
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
708
+            $this->groupCreateChecks($share);
709
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
710
+            $this->linkCreateChecks($share);
711
+
712
+            $this->updateSharePasswordIfNeeded($share, $originalShare);
713
+
714
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
715
+                //Verify the expiration date
716
+                $this->validateExpirationDate($share);
717
+                $expirationDateUpdated = true;
718
+            }
719
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
720
+            $plainTextPassword = $share->getPassword();
721
+            if (!$this->updateSharePasswordIfNeeded($share, $originalShare)) {
722
+                $plainTextPassword = null;
723
+            }
724
+        }
725
+
726
+        $this->pathCreateChecks($share->getNode());
727
+
728
+        // Now update the share!
729
+        $provider = $this->factory->getProviderForType($share->getShareType());
730
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
731
+            $share = $provider->update($share, $plainTextPassword);
732
+        } else {
733
+            $share = $provider->update($share);
734
+        }
735
+
736
+        if ($expirationDateUpdated === true) {
737
+            \OC_Hook::emit('OCP\Share', 'post_set_expiration_date', [
738
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
739
+                'itemSource' => $share->getNode()->getId(),
740
+                'date' => $share->getExpirationDate(),
741
+                'uidOwner' => $share->getSharedBy(),
742
+            ]);
743
+        }
744
+
745
+        if ($share->getPassword() !== $originalShare->getPassword()) {
746
+            \OC_Hook::emit('OCP\Share', 'post_update_password', [
747
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
748
+                'itemSource' => $share->getNode()->getId(),
749
+                'uidOwner' => $share->getSharedBy(),
750
+                'token' => $share->getToken(),
751
+                'disabled' => is_null($share->getPassword()),
752
+            ]);
753
+        }
754
+
755
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
756
+            if ($this->userManager->userExists($share->getShareOwner())) {
757
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
758
+            } else {
759
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
760
+            }
761
+            \OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
762
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
763
+                'itemSource' => $share->getNode()->getId(),
764
+                'shareType' => $share->getShareType(),
765
+                'shareWith' => $share->getSharedWith(),
766
+                'uidOwner' => $share->getSharedBy(),
767
+                'permissions' => $share->getPermissions(),
768
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
769
+            ));
770
+        }
771
+
772
+        return $share;
773
+    }
774
+
775
+    /**
776
+     * Updates the password of the given share if it is not the same as the
777
+     * password of the original share.
778
+     *
779
+     * @param \OCP\Share\IShare $share the share to update its password.
780
+     * @param \OCP\Share\IShare $originalShare the original share to compare its
781
+     *        password with.
782
+     * @return boolean whether the password was updated or not.
783
+     */
784
+    private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
785
+        // Password updated.
786
+        if ($share->getPassword() !== $originalShare->getPassword()) {
787
+            //Verify the password
788
+            $this->verifyPassword($share->getPassword());
789
+
790
+            // If a password is set. Hash it!
791
+            if ($share->getPassword() !== null) {
792
+                $share->setPassword($this->hasher->hash($share->getPassword()));
793
+
794
+                return true;
795
+            }
796
+        }
797
+
798
+        return false;
799
+    }
800
+
801
+    /**
802
+     * Delete all the children of this share
803
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
804
+     *
805
+     * @param \OCP\Share\IShare $share
806
+     * @return \OCP\Share\IShare[] List of deleted shares
807
+     */
808
+    protected function deleteChildren(\OCP\Share\IShare $share) {
809
+        $deletedShares = [];
810
+
811
+        $provider = $this->factory->getProviderForType($share->getShareType());
812
+
813
+        foreach ($provider->getChildren($share) as $child) {
814
+            $deletedChildren = $this->deleteChildren($child);
815
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
816
+
817
+            $provider->delete($child);
818
+            $deletedShares[] = $child;
819
+        }
820
+
821
+        return $deletedShares;
822
+    }
823
+
824
+    /**
825
+     * Delete a share
826
+     *
827
+     * @param \OCP\Share\IShare $share
828
+     * @throws ShareNotFound
829
+     * @throws \InvalidArgumentException
830
+     */
831
+    public function deleteShare(\OCP\Share\IShare $share) {
832
+
833
+        try {
834
+            $share->getFullId();
835
+        } catch (\UnexpectedValueException $e) {
836
+            throw new \InvalidArgumentException('Share does not have a full id');
837
+        }
838
+
839
+        $event = new GenericEvent($share);
840
+        $this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
841
+
842
+        // Get all children and delete them as well
843
+        $deletedShares = $this->deleteChildren($share);
844
+
845
+        // Do the actual delete
846
+        $provider = $this->factory->getProviderForType($share->getShareType());
847
+        $provider->delete($share);
848
+
849
+        // All the deleted shares caused by this delete
850
+        $deletedShares[] = $share;
851
+
852
+        // Emit post hook
853
+        $event->setArgument('deletedShares', $deletedShares);
854
+        $this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
855
+    }
856
+
857
+
858
+    /**
859
+     * Unshare a file as the recipient.
860
+     * This can be different from a regular delete for example when one of
861
+     * the users in a groups deletes that share. But the provider should
862
+     * handle this.
863
+     *
864
+     * @param \OCP\Share\IShare $share
865
+     * @param string $recipientId
866
+     */
867
+    public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
868
+        list($providerId, ) = $this->splitFullId($share->getFullId());
869
+        $provider = $this->factory->getProvider($providerId);
870
+
871
+        $provider->deleteFromSelf($share, $recipientId);
872
+    }
873
+
874
+    /**
875
+     * @inheritdoc
876
+     */
877
+    public function moveShare(\OCP\Share\IShare $share, $recipientId) {
878
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
879
+            throw new \InvalidArgumentException('Can’t change target of link share');
880
+        }
881
+
882
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
883
+            throw new \InvalidArgumentException('Invalid recipient');
884
+        }
885
+
886
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
887
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
888
+            if (is_null($sharedWith)) {
889
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
890
+            }
891
+            $recipient = $this->userManager->get($recipientId);
892
+            if (!$sharedWith->inGroup($recipient)) {
893
+                throw new \InvalidArgumentException('Invalid recipient');
894
+            }
895
+        }
896
+
897
+        list($providerId, ) = $this->splitFullId($share->getFullId());
898
+        $provider = $this->factory->getProvider($providerId);
899
+
900
+        $provider->move($share, $recipientId);
901
+    }
902
+
903
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
904
+        $providers = $this->factory->getAllProviders();
905
+
906
+        return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
907
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
908
+            foreach ($newShares as $fid => $data) {
909
+                if (!isset($shares[$fid])) {
910
+                    $shares[$fid] = [];
911
+                }
912
+
913
+                $shares[$fid] = array_merge($shares[$fid], $data);
914
+            }
915
+            return $shares;
916
+        }, []);
917
+    }
918
+
919
+    /**
920
+     * @inheritdoc
921
+     */
922
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
923
+        if ($path !== null &&
924
+                !($path instanceof \OCP\Files\File) &&
925
+                !($path instanceof \OCP\Files\Folder)) {
926
+            throw new \InvalidArgumentException('invalid path');
927
+        }
928
+
929
+        try {
930
+            $provider = $this->factory->getProviderForType($shareType);
931
+        } catch (ProviderException $e) {
932
+            return [];
933
+        }
934
+
935
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
936
+
937
+        /*
938 938
 		 * Work around so we don't return expired shares but still follow
939 939
 		 * proper pagination.
940 940
 		 */
941 941
 
942
-		$shares2 = [];
943
-
944
-		while(true) {
945
-			$added = 0;
946
-			foreach ($shares as $share) {
947
-
948
-				try {
949
-					$this->checkExpireDate($share);
950
-				} catch (ShareNotFound $e) {
951
-					//Ignore since this basically means the share is deleted
952
-					continue;
953
-				}
954
-
955
-				$added++;
956
-				$shares2[] = $share;
957
-
958
-				if (count($shares2) === $limit) {
959
-					break;
960
-				}
961
-			}
962
-
963
-			if (count($shares2) === $limit) {
964
-				break;
965
-			}
966
-
967
-			// If there was no limit on the select we are done
968
-			if ($limit === -1) {
969
-				break;
970
-			}
971
-
972
-			$offset += $added;
973
-
974
-			// Fetch again $limit shares
975
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
976
-
977
-			// No more shares means we are done
978
-			if (empty($shares)) {
979
-				break;
980
-			}
981
-		}
982
-
983
-		$shares = $shares2;
984
-
985
-		return $shares;
986
-	}
987
-
988
-	/**
989
-	 * @inheritdoc
990
-	 */
991
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
992
-		try {
993
-			$provider = $this->factory->getProviderForType($shareType);
994
-		} catch (ProviderException $e) {
995
-			return [];
996
-		}
997
-
998
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
999
-
1000
-		// remove all shares which are already expired
1001
-		foreach ($shares as $key => $share) {
1002
-			try {
1003
-				$this->checkExpireDate($share);
1004
-			} catch (ShareNotFound $e) {
1005
-				unset($shares[$key]);
1006
-			}
1007
-		}
1008
-
1009
-		return $shares;
1010
-	}
1011
-
1012
-	/**
1013
-	 * @inheritdoc
1014
-	 */
1015
-	public function getShareById($id, $recipient = null) {
1016
-		if ($id === null) {
1017
-			throw new ShareNotFound();
1018
-		}
1019
-
1020
-		list($providerId, $id) = $this->splitFullId($id);
1021
-
1022
-		try {
1023
-			$provider = $this->factory->getProvider($providerId);
1024
-		} catch (ProviderException $e) {
1025
-			throw new ShareNotFound();
1026
-		}
1027
-
1028
-		$share = $provider->getShareById($id, $recipient);
1029
-
1030
-		$this->checkExpireDate($share);
1031
-
1032
-		return $share;
1033
-	}
1034
-
1035
-	/**
1036
-	 * Get all the shares for a given path
1037
-	 *
1038
-	 * @param \OCP\Files\Node $path
1039
-	 * @param int $page
1040
-	 * @param int $perPage
1041
-	 *
1042
-	 * @return Share[]
1043
-	 */
1044
-	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1045
-		return [];
1046
-	}
1047
-
1048
-	/**
1049
-	 * Get the share by token possible with password
1050
-	 *
1051
-	 * @param string $token
1052
-	 * @return Share
1053
-	 *
1054
-	 * @throws ShareNotFound
1055
-	 */
1056
-	public function getShareByToken($token) {
1057
-		$share = null;
1058
-		try {
1059
-			if($this->shareApiAllowLinks()) {
1060
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1061
-				$share = $provider->getShareByToken($token);
1062
-			}
1063
-		} catch (ProviderException $e) {
1064
-		} catch (ShareNotFound $e) {
1065
-		}
1066
-
1067
-
1068
-		// If it is not a link share try to fetch a federated share by token
1069
-		if ($share === null) {
1070
-			try {
1071
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1072
-				$share = $provider->getShareByToken($token);
1073
-			} catch (ProviderException $e) {
1074
-			} catch (ShareNotFound $e) {
1075
-			}
1076
-		}
1077
-
1078
-		// If it is not a link share try to fetch a mail share by token
1079
-		if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1080
-			try {
1081
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1082
-				$share = $provider->getShareByToken($token);
1083
-			} catch (ProviderException $e) {
1084
-			} catch (ShareNotFound $e) {
1085
-			}
1086
-		}
1087
-
1088
-		if ($share === null) {
1089
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1090
-		}
1091
-
1092
-		$this->checkExpireDate($share);
1093
-
1094
-		/*
942
+        $shares2 = [];
943
+
944
+        while(true) {
945
+            $added = 0;
946
+            foreach ($shares as $share) {
947
+
948
+                try {
949
+                    $this->checkExpireDate($share);
950
+                } catch (ShareNotFound $e) {
951
+                    //Ignore since this basically means the share is deleted
952
+                    continue;
953
+                }
954
+
955
+                $added++;
956
+                $shares2[] = $share;
957
+
958
+                if (count($shares2) === $limit) {
959
+                    break;
960
+                }
961
+            }
962
+
963
+            if (count($shares2) === $limit) {
964
+                break;
965
+            }
966
+
967
+            // If there was no limit on the select we are done
968
+            if ($limit === -1) {
969
+                break;
970
+            }
971
+
972
+            $offset += $added;
973
+
974
+            // Fetch again $limit shares
975
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
976
+
977
+            // No more shares means we are done
978
+            if (empty($shares)) {
979
+                break;
980
+            }
981
+        }
982
+
983
+        $shares = $shares2;
984
+
985
+        return $shares;
986
+    }
987
+
988
+    /**
989
+     * @inheritdoc
990
+     */
991
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
992
+        try {
993
+            $provider = $this->factory->getProviderForType($shareType);
994
+        } catch (ProviderException $e) {
995
+            return [];
996
+        }
997
+
998
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
999
+
1000
+        // remove all shares which are already expired
1001
+        foreach ($shares as $key => $share) {
1002
+            try {
1003
+                $this->checkExpireDate($share);
1004
+            } catch (ShareNotFound $e) {
1005
+                unset($shares[$key]);
1006
+            }
1007
+        }
1008
+
1009
+        return $shares;
1010
+    }
1011
+
1012
+    /**
1013
+     * @inheritdoc
1014
+     */
1015
+    public function getShareById($id, $recipient = null) {
1016
+        if ($id === null) {
1017
+            throw new ShareNotFound();
1018
+        }
1019
+
1020
+        list($providerId, $id) = $this->splitFullId($id);
1021
+
1022
+        try {
1023
+            $provider = $this->factory->getProvider($providerId);
1024
+        } catch (ProviderException $e) {
1025
+            throw new ShareNotFound();
1026
+        }
1027
+
1028
+        $share = $provider->getShareById($id, $recipient);
1029
+
1030
+        $this->checkExpireDate($share);
1031
+
1032
+        return $share;
1033
+    }
1034
+
1035
+    /**
1036
+     * Get all the shares for a given path
1037
+     *
1038
+     * @param \OCP\Files\Node $path
1039
+     * @param int $page
1040
+     * @param int $perPage
1041
+     *
1042
+     * @return Share[]
1043
+     */
1044
+    public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1045
+        return [];
1046
+    }
1047
+
1048
+    /**
1049
+     * Get the share by token possible with password
1050
+     *
1051
+     * @param string $token
1052
+     * @return Share
1053
+     *
1054
+     * @throws ShareNotFound
1055
+     */
1056
+    public function getShareByToken($token) {
1057
+        $share = null;
1058
+        try {
1059
+            if($this->shareApiAllowLinks()) {
1060
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1061
+                $share = $provider->getShareByToken($token);
1062
+            }
1063
+        } catch (ProviderException $e) {
1064
+        } catch (ShareNotFound $e) {
1065
+        }
1066
+
1067
+
1068
+        // If it is not a link share try to fetch a federated share by token
1069
+        if ($share === null) {
1070
+            try {
1071
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1072
+                $share = $provider->getShareByToken($token);
1073
+            } catch (ProviderException $e) {
1074
+            } catch (ShareNotFound $e) {
1075
+            }
1076
+        }
1077
+
1078
+        // If it is not a link share try to fetch a mail share by token
1079
+        if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1080
+            try {
1081
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1082
+                $share = $provider->getShareByToken($token);
1083
+            } catch (ProviderException $e) {
1084
+            } catch (ShareNotFound $e) {
1085
+            }
1086
+        }
1087
+
1088
+        if ($share === null) {
1089
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1090
+        }
1091
+
1092
+        $this->checkExpireDate($share);
1093
+
1094
+        /*
1095 1095
 		 * Reduce the permissions for link shares if public upload is not enabled
1096 1096
 		 */
1097
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1098
-			!$this->shareApiLinkAllowPublicUpload()) {
1099
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1100
-		}
1101
-
1102
-		return $share;
1103
-	}
1104
-
1105
-	protected function checkExpireDate($share) {
1106
-		if ($share->getExpirationDate() !== null &&
1107
-			$share->getExpirationDate() <= new \DateTime()) {
1108
-			$this->deleteShare($share);
1109
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1110
-		}
1111
-
1112
-	}
1113
-
1114
-	/**
1115
-	 * Verify the password of a public share
1116
-	 *
1117
-	 * @param \OCP\Share\IShare $share
1118
-	 * @param string $password
1119
-	 * @return bool
1120
-	 */
1121
-	public function checkPassword(\OCP\Share\IShare $share, $password) {
1122
-		$passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1123
-			|| $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1124
-		if (!$passwordProtected) {
1125
-			//TODO maybe exception?
1126
-			return false;
1127
-		}
1128
-
1129
-		if ($password === null || $share->getPassword() === null) {
1130
-			return false;
1131
-		}
1132
-
1133
-		$newHash = '';
1134
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1135
-			return false;
1136
-		}
1137
-
1138
-		if (!empty($newHash)) {
1139
-			$share->setPassword($newHash);
1140
-			$provider = $this->factory->getProviderForType($share->getShareType());
1141
-			$provider->update($share);
1142
-		}
1143
-
1144
-		return true;
1145
-	}
1146
-
1147
-	/**
1148
-	 * @inheritdoc
1149
-	 */
1150
-	public function userDeleted($uid) {
1151
-		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
1152
-
1153
-		foreach ($types as $type) {
1154
-			try {
1155
-				$provider = $this->factory->getProviderForType($type);
1156
-			} catch (ProviderException $e) {
1157
-				continue;
1158
-			}
1159
-			$provider->userDeleted($uid, $type);
1160
-		}
1161
-	}
1162
-
1163
-	/**
1164
-	 * @inheritdoc
1165
-	 */
1166
-	public function groupDeleted($gid) {
1167
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1168
-		$provider->groupDeleted($gid);
1169
-	}
1170
-
1171
-	/**
1172
-	 * @inheritdoc
1173
-	 */
1174
-	public function userDeletedFromGroup($uid, $gid) {
1175
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1176
-		$provider->userDeletedFromGroup($uid, $gid);
1177
-	}
1178
-
1179
-	/**
1180
-	 * Get access list to a path. This means
1181
-	 * all the users that can access a given path.
1182
-	 *
1183
-	 * Consider:
1184
-	 * -root
1185
-	 * |-folder1 (23)
1186
-	 *  |-folder2 (32)
1187
-	 *   |-fileA (42)
1188
-	 *
1189
-	 * fileA is shared with user1 and user1@server1
1190
-	 * folder2 is shared with group2 (user4 is a member of group2)
1191
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1192
-	 *
1193
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1194
-	 * [
1195
-	 *  users  => [
1196
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1197
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1198
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1199
-	 *  ],
1200
-	 *  remote => [
1201
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1202
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1203
-	 *  ],
1204
-	 *  public => bool
1205
-	 *  mail => bool
1206
-	 * ]
1207
-	 *
1208
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1209
-	 * [
1210
-	 *  users  => ['user1', 'user2', 'user4'],
1211
-	 *  remote => bool,
1212
-	 *  public => bool
1213
-	 *  mail => bool
1214
-	 * ]
1215
-	 *
1216
-	 * This is required for encryption/activity
1217
-	 *
1218
-	 * @param \OCP\Files\Node $path
1219
-	 * @param bool $recursive Should we check all parent folders as well
1220
-	 * @param bool $currentAccess Should the user have currently access to the file
1221
-	 * @return array
1222
-	 */
1223
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1224
-		$owner = $path->getOwner()->getUID();
1225
-
1226
-		if ($currentAccess) {
1227
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1228
-		} else {
1229
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1230
-		}
1231
-		if (!$this->userManager->userExists($owner)) {
1232
-			return $al;
1233
-		}
1234
-
1235
-		//Get node for the owner
1236
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1237
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1238
-			$path = $userFolder->getById($path->getId())[0];
1239
-		}
1240
-
1241
-		$providers = $this->factory->getAllProviders();
1242
-
1243
-		/** @var Node[] $nodes */
1244
-		$nodes = [];
1245
-
1246
-
1247
-		if ($currentAccess) {
1248
-			$ownerPath = $path->getPath();
1249
-			$ownerPath = explode('/', $ownerPath, 4);
1250
-			if (count($ownerPath) < 4) {
1251
-				$ownerPath = '';
1252
-			} else {
1253
-				$ownerPath = $ownerPath[3];
1254
-			}
1255
-			$al['users'][$owner] = [
1256
-				'node_id' => $path->getId(),
1257
-				'node_path' => '/' . $ownerPath,
1258
-			];
1259
-		} else {
1260
-			$al['users'][] = $owner;
1261
-		}
1262
-
1263
-		// Collect all the shares
1264
-		while ($path->getPath() !== $userFolder->getPath()) {
1265
-			$nodes[] = $path;
1266
-			if (!$recursive) {
1267
-				break;
1268
-			}
1269
-			$path = $path->getParent();
1270
-		}
1271
-
1272
-		foreach ($providers as $provider) {
1273
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1274
-
1275
-			foreach ($tmp as $k => $v) {
1276
-				if (isset($al[$k])) {
1277
-					if (is_array($al[$k])) {
1278
-						$al[$k] = array_merge($al[$k], $v);
1279
-					} else {
1280
-						$al[$k] = $al[$k] || $v;
1281
-					}
1282
-				} else {
1283
-					$al[$k] = $v;
1284
-				}
1285
-			}
1286
-		}
1287
-
1288
-		return $al;
1289
-	}
1290
-
1291
-	/**
1292
-	 * Create a new share
1293
-	 * @return \OCP\Share\IShare;
1294
-	 */
1295
-	public function newShare() {
1296
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1297
-	}
1298
-
1299
-	/**
1300
-	 * Is the share API enabled
1301
-	 *
1302
-	 * @return bool
1303
-	 */
1304
-	public function shareApiEnabled() {
1305
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1306
-	}
1307
-
1308
-	/**
1309
-	 * Is public link sharing enabled
1310
-	 *
1311
-	 * @return bool
1312
-	 */
1313
-	public function shareApiAllowLinks() {
1314
-		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1315
-	}
1316
-
1317
-	/**
1318
-	 * Is password on public link requires
1319
-	 *
1320
-	 * @return bool
1321
-	 */
1322
-	public function shareApiLinkEnforcePassword() {
1323
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1324
-	}
1325
-
1326
-	/**
1327
-	 * Is default expire date enabled
1328
-	 *
1329
-	 * @return bool
1330
-	 */
1331
-	public function shareApiLinkDefaultExpireDate() {
1332
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1333
-	}
1334
-
1335
-	/**
1336
-	 * Is default expire date enforced
1337
-	 *`
1338
-	 * @return bool
1339
-	 */
1340
-	public function shareApiLinkDefaultExpireDateEnforced() {
1341
-		return $this->shareApiLinkDefaultExpireDate() &&
1342
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1343
-	}
1344
-
1345
-	/**
1346
-	 * Number of default expire days
1347
-	 *shareApiLinkAllowPublicUpload
1348
-	 * @return int
1349
-	 */
1350
-	public function shareApiLinkDefaultExpireDays() {
1351
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1352
-	}
1353
-
1354
-	/**
1355
-	 * Allow public upload on link shares
1356
-	 *
1357
-	 * @return bool
1358
-	 */
1359
-	public function shareApiLinkAllowPublicUpload() {
1360
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1361
-	}
1362
-
1363
-	/**
1364
-	 * check if user can only share with group members
1365
-	 * @return bool
1366
-	 */
1367
-	public function shareWithGroupMembersOnly() {
1368
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1369
-	}
1370
-
1371
-	/**
1372
-	 * Check if users can share with groups
1373
-	 * @return bool
1374
-	 */
1375
-	public function allowGroupSharing() {
1376
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1377
-	}
1378
-
1379
-	/**
1380
-	 * Copied from \OC_Util::isSharingDisabledForUser
1381
-	 *
1382
-	 * TODO: Deprecate fuction from OC_Util
1383
-	 *
1384
-	 * @param string $userId
1385
-	 * @return bool
1386
-	 */
1387
-	public function sharingDisabledForUser($userId) {
1388
-		if ($userId === null) {
1389
-			return false;
1390
-		}
1391
-
1392
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1393
-			return $this->sharingDisabledForUsersCache[$userId];
1394
-		}
1395
-
1396
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1397
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1398
-			$excludedGroups = json_decode($groupsList);
1399
-			if (is_null($excludedGroups)) {
1400
-				$excludedGroups = explode(',', $groupsList);
1401
-				$newValue = json_encode($excludedGroups);
1402
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1403
-			}
1404
-			$user = $this->userManager->get($userId);
1405
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1406
-			if (!empty($usersGroups)) {
1407
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1408
-				// if the user is only in groups which are disabled for sharing then
1409
-				// sharing is also disabled for the user
1410
-				if (empty($remainingGroups)) {
1411
-					$this->sharingDisabledForUsersCache[$userId] = true;
1412
-					return true;
1413
-				}
1414
-			}
1415
-		}
1416
-
1417
-		$this->sharingDisabledForUsersCache[$userId] = false;
1418
-		return false;
1419
-	}
1420
-
1421
-	/**
1422
-	 * @inheritdoc
1423
-	 */
1424
-	public function outgoingServer2ServerSharesAllowed() {
1425
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1426
-	}
1427
-
1428
-	/**
1429
-	 * @inheritdoc
1430
-	 */
1431
-	public function shareProviderExists($shareType) {
1432
-		try {
1433
-			$this->factory->getProviderForType($shareType);
1434
-		} catch (ProviderException $e) {
1435
-			return false;
1436
-		}
1437
-
1438
-		return true;
1439
-	}
1097
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1098
+            !$this->shareApiLinkAllowPublicUpload()) {
1099
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1100
+        }
1101
+
1102
+        return $share;
1103
+    }
1104
+
1105
+    protected function checkExpireDate($share) {
1106
+        if ($share->getExpirationDate() !== null &&
1107
+            $share->getExpirationDate() <= new \DateTime()) {
1108
+            $this->deleteShare($share);
1109
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1110
+        }
1111
+
1112
+    }
1113
+
1114
+    /**
1115
+     * Verify the password of a public share
1116
+     *
1117
+     * @param \OCP\Share\IShare $share
1118
+     * @param string $password
1119
+     * @return bool
1120
+     */
1121
+    public function checkPassword(\OCP\Share\IShare $share, $password) {
1122
+        $passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1123
+            || $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1124
+        if (!$passwordProtected) {
1125
+            //TODO maybe exception?
1126
+            return false;
1127
+        }
1128
+
1129
+        if ($password === null || $share->getPassword() === null) {
1130
+            return false;
1131
+        }
1132
+
1133
+        $newHash = '';
1134
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1135
+            return false;
1136
+        }
1137
+
1138
+        if (!empty($newHash)) {
1139
+            $share->setPassword($newHash);
1140
+            $provider = $this->factory->getProviderForType($share->getShareType());
1141
+            $provider->update($share);
1142
+        }
1143
+
1144
+        return true;
1145
+    }
1146
+
1147
+    /**
1148
+     * @inheritdoc
1149
+     */
1150
+    public function userDeleted($uid) {
1151
+        $types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
1152
+
1153
+        foreach ($types as $type) {
1154
+            try {
1155
+                $provider = $this->factory->getProviderForType($type);
1156
+            } catch (ProviderException $e) {
1157
+                continue;
1158
+            }
1159
+            $provider->userDeleted($uid, $type);
1160
+        }
1161
+    }
1162
+
1163
+    /**
1164
+     * @inheritdoc
1165
+     */
1166
+    public function groupDeleted($gid) {
1167
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1168
+        $provider->groupDeleted($gid);
1169
+    }
1170
+
1171
+    /**
1172
+     * @inheritdoc
1173
+     */
1174
+    public function userDeletedFromGroup($uid, $gid) {
1175
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1176
+        $provider->userDeletedFromGroup($uid, $gid);
1177
+    }
1178
+
1179
+    /**
1180
+     * Get access list to a path. This means
1181
+     * all the users that can access a given path.
1182
+     *
1183
+     * Consider:
1184
+     * -root
1185
+     * |-folder1 (23)
1186
+     *  |-folder2 (32)
1187
+     *   |-fileA (42)
1188
+     *
1189
+     * fileA is shared with user1 and user1@server1
1190
+     * folder2 is shared with group2 (user4 is a member of group2)
1191
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1192
+     *
1193
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1194
+     * [
1195
+     *  users  => [
1196
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1197
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1198
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1199
+     *  ],
1200
+     *  remote => [
1201
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1202
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1203
+     *  ],
1204
+     *  public => bool
1205
+     *  mail => bool
1206
+     * ]
1207
+     *
1208
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1209
+     * [
1210
+     *  users  => ['user1', 'user2', 'user4'],
1211
+     *  remote => bool,
1212
+     *  public => bool
1213
+     *  mail => bool
1214
+     * ]
1215
+     *
1216
+     * This is required for encryption/activity
1217
+     *
1218
+     * @param \OCP\Files\Node $path
1219
+     * @param bool $recursive Should we check all parent folders as well
1220
+     * @param bool $currentAccess Should the user have currently access to the file
1221
+     * @return array
1222
+     */
1223
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1224
+        $owner = $path->getOwner()->getUID();
1225
+
1226
+        if ($currentAccess) {
1227
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1228
+        } else {
1229
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1230
+        }
1231
+        if (!$this->userManager->userExists($owner)) {
1232
+            return $al;
1233
+        }
1234
+
1235
+        //Get node for the owner
1236
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1237
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1238
+            $path = $userFolder->getById($path->getId())[0];
1239
+        }
1240
+
1241
+        $providers = $this->factory->getAllProviders();
1242
+
1243
+        /** @var Node[] $nodes */
1244
+        $nodes = [];
1245
+
1246
+
1247
+        if ($currentAccess) {
1248
+            $ownerPath = $path->getPath();
1249
+            $ownerPath = explode('/', $ownerPath, 4);
1250
+            if (count($ownerPath) < 4) {
1251
+                $ownerPath = '';
1252
+            } else {
1253
+                $ownerPath = $ownerPath[3];
1254
+            }
1255
+            $al['users'][$owner] = [
1256
+                'node_id' => $path->getId(),
1257
+                'node_path' => '/' . $ownerPath,
1258
+            ];
1259
+        } else {
1260
+            $al['users'][] = $owner;
1261
+        }
1262
+
1263
+        // Collect all the shares
1264
+        while ($path->getPath() !== $userFolder->getPath()) {
1265
+            $nodes[] = $path;
1266
+            if (!$recursive) {
1267
+                break;
1268
+            }
1269
+            $path = $path->getParent();
1270
+        }
1271
+
1272
+        foreach ($providers as $provider) {
1273
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1274
+
1275
+            foreach ($tmp as $k => $v) {
1276
+                if (isset($al[$k])) {
1277
+                    if (is_array($al[$k])) {
1278
+                        $al[$k] = array_merge($al[$k], $v);
1279
+                    } else {
1280
+                        $al[$k] = $al[$k] || $v;
1281
+                    }
1282
+                } else {
1283
+                    $al[$k] = $v;
1284
+                }
1285
+            }
1286
+        }
1287
+
1288
+        return $al;
1289
+    }
1290
+
1291
+    /**
1292
+     * Create a new share
1293
+     * @return \OCP\Share\IShare;
1294
+     */
1295
+    public function newShare() {
1296
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1297
+    }
1298
+
1299
+    /**
1300
+     * Is the share API enabled
1301
+     *
1302
+     * @return bool
1303
+     */
1304
+    public function shareApiEnabled() {
1305
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1306
+    }
1307
+
1308
+    /**
1309
+     * Is public link sharing enabled
1310
+     *
1311
+     * @return bool
1312
+     */
1313
+    public function shareApiAllowLinks() {
1314
+        return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1315
+    }
1316
+
1317
+    /**
1318
+     * Is password on public link requires
1319
+     *
1320
+     * @return bool
1321
+     */
1322
+    public function shareApiLinkEnforcePassword() {
1323
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1324
+    }
1325
+
1326
+    /**
1327
+     * Is default expire date enabled
1328
+     *
1329
+     * @return bool
1330
+     */
1331
+    public function shareApiLinkDefaultExpireDate() {
1332
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1333
+    }
1334
+
1335
+    /**
1336
+     * Is default expire date enforced
1337
+     *`
1338
+     * @return bool
1339
+     */
1340
+    public function shareApiLinkDefaultExpireDateEnforced() {
1341
+        return $this->shareApiLinkDefaultExpireDate() &&
1342
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1343
+    }
1344
+
1345
+    /**
1346
+     * Number of default expire days
1347
+     *shareApiLinkAllowPublicUpload
1348
+     * @return int
1349
+     */
1350
+    public function shareApiLinkDefaultExpireDays() {
1351
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1352
+    }
1353
+
1354
+    /**
1355
+     * Allow public upload on link shares
1356
+     *
1357
+     * @return bool
1358
+     */
1359
+    public function shareApiLinkAllowPublicUpload() {
1360
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1361
+    }
1362
+
1363
+    /**
1364
+     * check if user can only share with group members
1365
+     * @return bool
1366
+     */
1367
+    public function shareWithGroupMembersOnly() {
1368
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1369
+    }
1370
+
1371
+    /**
1372
+     * Check if users can share with groups
1373
+     * @return bool
1374
+     */
1375
+    public function allowGroupSharing() {
1376
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1377
+    }
1378
+
1379
+    /**
1380
+     * Copied from \OC_Util::isSharingDisabledForUser
1381
+     *
1382
+     * TODO: Deprecate fuction from OC_Util
1383
+     *
1384
+     * @param string $userId
1385
+     * @return bool
1386
+     */
1387
+    public function sharingDisabledForUser($userId) {
1388
+        if ($userId === null) {
1389
+            return false;
1390
+        }
1391
+
1392
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1393
+            return $this->sharingDisabledForUsersCache[$userId];
1394
+        }
1395
+
1396
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1397
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1398
+            $excludedGroups = json_decode($groupsList);
1399
+            if (is_null($excludedGroups)) {
1400
+                $excludedGroups = explode(',', $groupsList);
1401
+                $newValue = json_encode($excludedGroups);
1402
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1403
+            }
1404
+            $user = $this->userManager->get($userId);
1405
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1406
+            if (!empty($usersGroups)) {
1407
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1408
+                // if the user is only in groups which are disabled for sharing then
1409
+                // sharing is also disabled for the user
1410
+                if (empty($remainingGroups)) {
1411
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1412
+                    return true;
1413
+                }
1414
+            }
1415
+        }
1416
+
1417
+        $this->sharingDisabledForUsersCache[$userId] = false;
1418
+        return false;
1419
+    }
1420
+
1421
+    /**
1422
+     * @inheritdoc
1423
+     */
1424
+    public function outgoingServer2ServerSharesAllowed() {
1425
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1426
+    }
1427
+
1428
+    /**
1429
+     * @inheritdoc
1430
+     */
1431
+    public function shareProviderExists($shareType) {
1432
+        try {
1433
+            $this->factory->getProviderForType($shareType);
1434
+        } catch (ProviderException $e) {
1435
+            return false;
1436
+        }
1437
+
1438
+        return true;
1439
+    }
1440 1440
 
1441 1441
 }
Please login to merge, or discard this patch.
lib/private/Share/Share.php 1 patch
Indentation   +2827 added lines, -2827 removed lines patch added patch discarded remove patch
@@ -60,2864 +60,2864 @@
 block discarded – undo
60 60
  */
61 61
 class Share extends Constants {
62 62
 
63
-	/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
64
-	 * Construct permissions for share() and setPermissions with Or (|) e.g.
65
-	 * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
66
-	 *
67
-	 * Check if permission is granted with And (&) e.g. Check if delete is
68
-	 * granted: if ($permissions & PERMISSION_DELETE)
69
-	 *
70
-	 * Remove permissions with And (&) and Not (~) e.g. Remove the update
71
-	 * permission: $permissions &= ~PERMISSION_UPDATE
72
-	 *
73
-	 * Apps are required to handle permissions on their own, this class only
74
-	 * stores and manages the permissions of shares
75
-	 * @see lib/public/constants.php
76
-	 */
77
-
78
-	/**
79
-	 * Register a sharing backend class that implements OCP\Share_Backend for an item type
80
-	 * @param string $itemType Item type
81
-	 * @param string $class Backend class
82
-	 * @param string $collectionOf (optional) Depends on item type
83
-	 * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
84
-	 * @return boolean true if backend is registered or false if error
85
-	 */
86
-	public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
87
-		if (self::isEnabled()) {
88
-			if (!isset(self::$backendTypes[$itemType])) {
89
-				self::$backendTypes[$itemType] = array(
90
-					'class' => $class,
91
-					'collectionOf' => $collectionOf,
92
-					'supportedFileExtensions' => $supportedFileExtensions
93
-				);
94
-				if(count(self::$backendTypes) === 1) {
95
-					Util::addScript('core', 'merged-share-backend');
96
-					\OC_Util::addStyle('core', 'share');
97
-				}
98
-				return true;
99
-			}
100
-			\OCP\Util::writeLog('OCP\Share',
101
-				'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
102
-				.' is already registered for '.$itemType,
103
-				\OCP\Util::WARN);
104
-		}
105
-		return false;
106
-	}
107
-
108
-	/**
109
-	 * Check if the Share API is enabled
110
-	 * @return boolean true if enabled or false
111
-	 *
112
-	 * The Share API is enabled by default if not configured
113
-	 */
114
-	public static function isEnabled() {
115
-		if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_enabled', 'yes') == 'yes') {
116
-			return true;
117
-		}
118
-		return false;
119
-	}
120
-
121
-	/**
122
-	 * Find which users can access a shared item
123
-	 * @param string $path to the file
124
-	 * @param string $ownerUser owner of the file
125
-	 * @param IUserManager $userManager
126
-	 * @param ILogger $logger
127
-	 * @param boolean $includeOwner include owner to the list of users with access to the file
128
-	 * @param boolean $returnUserPaths Return an array with the user => path map
129
-	 * @param boolean $recursive take all parent folders into account (default true)
130
-	 * @return array
131
-	 * @note $path needs to be relative to user data dir, e.g. 'file.txt'
132
-	 *       not '/admin/data/file.txt'
133
-	 * @throws \OC\User\NoUserException
134
-	 */
135
-	public static function getUsersSharingFile($path,
136
-											   $ownerUser,
137
-											   IUserManager $userManager,
138
-											   ILogger $logger,
139
-											   $includeOwner = false,
140
-											   $returnUserPaths = false,
141
-											   $recursive = true) {
142
-		$userObject = $userManager->get($ownerUser);
143
-
144
-		if (is_null($userObject)) {
145
-			$logger->error(
146
-				sprintf(
147
-					'Backends provided no user object for %s',
148
-					$ownerUser
149
-				),
150
-				[
151
-					'app' => 'files',
152
-				]
153
-			);
154
-			throw new \OC\User\NoUserException('Backends provided no user object');
155
-		}
156
-
157
-		$ownerUser = $userObject->getUID();
158
-
159
-		Filesystem::initMountPoints($ownerUser);
160
-		$shares = $sharePaths = $fileTargets = array();
161
-		$publicShare = false;
162
-		$remoteShare = false;
163
-		$source = -1;
164
-		$cache = $mountPath = false;
165
-
166
-		$view = new \OC\Files\View('/' . $ownerUser . '/files');
167
-		$meta = $view->getFileInfo($path);
168
-		if ($meta) {
169
-			$path = substr($meta->getPath(), strlen('/' . $ownerUser . '/files'));
170
-		} else {
171
-			// if the file doesn't exists yet we start with the parent folder
172
-			$meta = $view->getFileInfo(dirname($path));
173
-		}
174
-
175
-		if($meta !== false) {
176
-			$source = $meta['fileid'];
177
-			$cache = new \OC\Files\Cache\Cache($meta['storage']);
178
-
179
-			$mountPath = $meta->getMountPoint()->getMountPoint();
180
-			if ($mountPath !== false) {
181
-				$mountPath = substr($mountPath, strlen('/' . $ownerUser . '/files'));
182
-			}
183
-		}
184
-
185
-		$paths = [];
186
-		while ($source !== -1) {
187
-			// Fetch all shares with another user
188
-			if (!$returnUserPaths) {
189
-				$query = \OC_DB::prepare(
190
-					'SELECT `share_with`, `file_source`, `file_target`
63
+    /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
64
+     * Construct permissions for share() and setPermissions with Or (|) e.g.
65
+     * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
66
+     *
67
+     * Check if permission is granted with And (&) e.g. Check if delete is
68
+     * granted: if ($permissions & PERMISSION_DELETE)
69
+     *
70
+     * Remove permissions with And (&) and Not (~) e.g. Remove the update
71
+     * permission: $permissions &= ~PERMISSION_UPDATE
72
+     *
73
+     * Apps are required to handle permissions on their own, this class only
74
+     * stores and manages the permissions of shares
75
+     * @see lib/public/constants.php
76
+     */
77
+
78
+    /**
79
+     * Register a sharing backend class that implements OCP\Share_Backend for an item type
80
+     * @param string $itemType Item type
81
+     * @param string $class Backend class
82
+     * @param string $collectionOf (optional) Depends on item type
83
+     * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
84
+     * @return boolean true if backend is registered or false if error
85
+     */
86
+    public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
87
+        if (self::isEnabled()) {
88
+            if (!isset(self::$backendTypes[$itemType])) {
89
+                self::$backendTypes[$itemType] = array(
90
+                    'class' => $class,
91
+                    'collectionOf' => $collectionOf,
92
+                    'supportedFileExtensions' => $supportedFileExtensions
93
+                );
94
+                if(count(self::$backendTypes) === 1) {
95
+                    Util::addScript('core', 'merged-share-backend');
96
+                    \OC_Util::addStyle('core', 'share');
97
+                }
98
+                return true;
99
+            }
100
+            \OCP\Util::writeLog('OCP\Share',
101
+                'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
102
+                .' is already registered for '.$itemType,
103
+                \OCP\Util::WARN);
104
+        }
105
+        return false;
106
+    }
107
+
108
+    /**
109
+     * Check if the Share API is enabled
110
+     * @return boolean true if enabled or false
111
+     *
112
+     * The Share API is enabled by default if not configured
113
+     */
114
+    public static function isEnabled() {
115
+        if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_enabled', 'yes') == 'yes') {
116
+            return true;
117
+        }
118
+        return false;
119
+    }
120
+
121
+    /**
122
+     * Find which users can access a shared item
123
+     * @param string $path to the file
124
+     * @param string $ownerUser owner of the file
125
+     * @param IUserManager $userManager
126
+     * @param ILogger $logger
127
+     * @param boolean $includeOwner include owner to the list of users with access to the file
128
+     * @param boolean $returnUserPaths Return an array with the user => path map
129
+     * @param boolean $recursive take all parent folders into account (default true)
130
+     * @return array
131
+     * @note $path needs to be relative to user data dir, e.g. 'file.txt'
132
+     *       not '/admin/data/file.txt'
133
+     * @throws \OC\User\NoUserException
134
+     */
135
+    public static function getUsersSharingFile($path,
136
+                                                $ownerUser,
137
+                                                IUserManager $userManager,
138
+                                                ILogger $logger,
139
+                                                $includeOwner = false,
140
+                                                $returnUserPaths = false,
141
+                                                $recursive = true) {
142
+        $userObject = $userManager->get($ownerUser);
143
+
144
+        if (is_null($userObject)) {
145
+            $logger->error(
146
+                sprintf(
147
+                    'Backends provided no user object for %s',
148
+                    $ownerUser
149
+                ),
150
+                [
151
+                    'app' => 'files',
152
+                ]
153
+            );
154
+            throw new \OC\User\NoUserException('Backends provided no user object');
155
+        }
156
+
157
+        $ownerUser = $userObject->getUID();
158
+
159
+        Filesystem::initMountPoints($ownerUser);
160
+        $shares = $sharePaths = $fileTargets = array();
161
+        $publicShare = false;
162
+        $remoteShare = false;
163
+        $source = -1;
164
+        $cache = $mountPath = false;
165
+
166
+        $view = new \OC\Files\View('/' . $ownerUser . '/files');
167
+        $meta = $view->getFileInfo($path);
168
+        if ($meta) {
169
+            $path = substr($meta->getPath(), strlen('/' . $ownerUser . '/files'));
170
+        } else {
171
+            // if the file doesn't exists yet we start with the parent folder
172
+            $meta = $view->getFileInfo(dirname($path));
173
+        }
174
+
175
+        if($meta !== false) {
176
+            $source = $meta['fileid'];
177
+            $cache = new \OC\Files\Cache\Cache($meta['storage']);
178
+
179
+            $mountPath = $meta->getMountPoint()->getMountPoint();
180
+            if ($mountPath !== false) {
181
+                $mountPath = substr($mountPath, strlen('/' . $ownerUser . '/files'));
182
+            }
183
+        }
184
+
185
+        $paths = [];
186
+        while ($source !== -1) {
187
+            // Fetch all shares with another user
188
+            if (!$returnUserPaths) {
189
+                $query = \OC_DB::prepare(
190
+                    'SELECT `share_with`, `file_source`, `file_target`
191 191
 					FROM
192 192
 					`*PREFIX*share`
193 193
 					WHERE
194 194
 					`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
195
-				);
196
-				$result = $query->execute(array($source, self::SHARE_TYPE_USER));
197
-			} else {
198
-				$query = \OC_DB::prepare(
199
-					'SELECT `share_with`, `file_source`, `file_target`
195
+                );
196
+                $result = $query->execute(array($source, self::SHARE_TYPE_USER));
197
+            } else {
198
+                $query = \OC_DB::prepare(
199
+                    'SELECT `share_with`, `file_source`, `file_target`
200 200
 				FROM
201 201
 				`*PREFIX*share`
202 202
 				WHERE
203 203
 				`item_source` = ? AND `share_type` IN (?, ?) AND `item_type` IN (\'file\', \'folder\')'
204
-				);
205
-				$result = $query->execute(array($source, self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
206
-			}
207
-
208
-			if (\OCP\DB::isError($result)) {
209
-				\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
210
-			} else {
211
-				while ($row = $result->fetchRow()) {
212
-					$shares[] = $row['share_with'];
213
-					if ($returnUserPaths) {
214
-						$fileTargets[(int) $row['file_source']][$row['share_with']] = $row;
215
-					}
216
-				}
217
-			}
218
-
219
-			// We also need to take group shares into account
220
-			$query = \OC_DB::prepare(
221
-				'SELECT `share_with`, `file_source`, `file_target`
204
+                );
205
+                $result = $query->execute(array($source, self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
206
+            }
207
+
208
+            if (\OCP\DB::isError($result)) {
209
+                \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
210
+            } else {
211
+                while ($row = $result->fetchRow()) {
212
+                    $shares[] = $row['share_with'];
213
+                    if ($returnUserPaths) {
214
+                        $fileTargets[(int) $row['file_source']][$row['share_with']] = $row;
215
+                    }
216
+                }
217
+            }
218
+
219
+            // We also need to take group shares into account
220
+            $query = \OC_DB::prepare(
221
+                'SELECT `share_with`, `file_source`, `file_target`
222 222
 				FROM
223 223
 				`*PREFIX*share`
224 224
 				WHERE
225 225
 				`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
226
-			);
227
-
228
-			$result = $query->execute(array($source, self::SHARE_TYPE_GROUP));
229
-
230
-			if (\OCP\DB::isError($result)) {
231
-				\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
232
-			} else {
233
-				$groupManager = \OC::$server->getGroupManager();
234
-				while ($row = $result->fetchRow()) {
235
-
236
-					$usersInGroup = [];
237
-					$group = $groupManager->get($row['share_with']);
238
-					if ($group) {
239
-						$users = $group->searchUsers('', -1, 0);
240
-						$userIds = array();
241
-						foreach ($users as $user) {
242
-							$userIds[] = $user->getUID();
243
-						}
244
-						$usersInGroup = $userIds;
245
-					}
246
-					$shares = array_merge($shares, $usersInGroup);
247
-					if ($returnUserPaths) {
248
-						foreach ($usersInGroup as $user) {
249
-							if (!isset($fileTargets[(int) $row['file_source']][$user])) {
250
-								// When the user already has an entry for this file source
251
-								// the file is either shared directly with him as well, or
252
-								// he has an exception entry (because of naming conflict).
253
-								$fileTargets[(int) $row['file_source']][$user] = $row;
254
-							}
255
-						}
256
-					}
257
-				}
258
-			}
259
-
260
-			//check for public link shares
261
-			if (!$publicShare) {
262
-				$query = \OC_DB::prepare('
226
+            );
227
+
228
+            $result = $query->execute(array($source, self::SHARE_TYPE_GROUP));
229
+
230
+            if (\OCP\DB::isError($result)) {
231
+                \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
232
+            } else {
233
+                $groupManager = \OC::$server->getGroupManager();
234
+                while ($row = $result->fetchRow()) {
235
+
236
+                    $usersInGroup = [];
237
+                    $group = $groupManager->get($row['share_with']);
238
+                    if ($group) {
239
+                        $users = $group->searchUsers('', -1, 0);
240
+                        $userIds = array();
241
+                        foreach ($users as $user) {
242
+                            $userIds[] = $user->getUID();
243
+                        }
244
+                        $usersInGroup = $userIds;
245
+                    }
246
+                    $shares = array_merge($shares, $usersInGroup);
247
+                    if ($returnUserPaths) {
248
+                        foreach ($usersInGroup as $user) {
249
+                            if (!isset($fileTargets[(int) $row['file_source']][$user])) {
250
+                                // When the user already has an entry for this file source
251
+                                // the file is either shared directly with him as well, or
252
+                                // he has an exception entry (because of naming conflict).
253
+                                $fileTargets[(int) $row['file_source']][$user] = $row;
254
+                            }
255
+                        }
256
+                    }
257
+                }
258
+            }
259
+
260
+            //check for public link shares
261
+            if (!$publicShare) {
262
+                $query = \OC_DB::prepare('
263 263
 					SELECT `share_with`
264 264
 					FROM `*PREFIX*share`
265 265
 					WHERE `item_source` = ? AND `share_type` IN (?, ?) AND `item_type` IN (\'file\', \'folder\')', 1
266
-				);
267
-
268
-				$result = $query->execute(array($source, self::SHARE_TYPE_LINK, self::SHARE_TYPE_EMAIL));
269
-
270
-				if (\OCP\DB::isError($result)) {
271
-					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
272
-				} else {
273
-					if ($result->fetchRow()) {
274
-						$publicShare = true;
275
-					}
276
-				}
277
-			}
278
-
279
-			//check for remote share
280
-			if (!$remoteShare) {
281
-				$query = \OC_DB::prepare('
266
+                );
267
+
268
+                $result = $query->execute(array($source, self::SHARE_TYPE_LINK, self::SHARE_TYPE_EMAIL));
269
+
270
+                if (\OCP\DB::isError($result)) {
271
+                    \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
272
+                } else {
273
+                    if ($result->fetchRow()) {
274
+                        $publicShare = true;
275
+                    }
276
+                }
277
+            }
278
+
279
+            //check for remote share
280
+            if (!$remoteShare) {
281
+                $query = \OC_DB::prepare('
282 282
 					SELECT `share_with`
283 283
 					FROM `*PREFIX*share`
284 284
 					WHERE `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')', 1
285
-				);
286
-
287
-				$result = $query->execute(array($source, self::SHARE_TYPE_REMOTE));
288
-
289
-				if (\OCP\DB::isError($result)) {
290
-					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
291
-				} else {
292
-					if ($result->fetchRow()) {
293
-						$remoteShare = true;
294
-					}
295
-				}
296
-			}
297
-
298
-			// let's get the parent for the next round
299
-			$meta = $cache->get((int)$source);
300
-			if ($recursive === true && $meta !== false) {
301
-				$paths[$source] = $meta['path'];
302
-				$source = (int)$meta['parent'];
303
-			} else {
304
-				$source = -1;
305
-			}
306
-		}
307
-
308
-		// Include owner in list of users, if requested
309
-		if ($includeOwner) {
310
-			$shares[] = $ownerUser;
311
-		}
312
-
313
-		if ($returnUserPaths) {
314
-			$fileTargetIDs = array_keys($fileTargets);
315
-			$fileTargetIDs = array_unique($fileTargetIDs);
316
-
317
-			if (!empty($fileTargetIDs)) {
318
-				$query = \OC_DB::prepare(
319
-					'SELECT `fileid`, `path`
285
+                );
286
+
287
+                $result = $query->execute(array($source, self::SHARE_TYPE_REMOTE));
288
+
289
+                if (\OCP\DB::isError($result)) {
290
+                    \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
291
+                } else {
292
+                    if ($result->fetchRow()) {
293
+                        $remoteShare = true;
294
+                    }
295
+                }
296
+            }
297
+
298
+            // let's get the parent for the next round
299
+            $meta = $cache->get((int)$source);
300
+            if ($recursive === true && $meta !== false) {
301
+                $paths[$source] = $meta['path'];
302
+                $source = (int)$meta['parent'];
303
+            } else {
304
+                $source = -1;
305
+            }
306
+        }
307
+
308
+        // Include owner in list of users, if requested
309
+        if ($includeOwner) {
310
+            $shares[] = $ownerUser;
311
+        }
312
+
313
+        if ($returnUserPaths) {
314
+            $fileTargetIDs = array_keys($fileTargets);
315
+            $fileTargetIDs = array_unique($fileTargetIDs);
316
+
317
+            if (!empty($fileTargetIDs)) {
318
+                $query = \OC_DB::prepare(
319
+                    'SELECT `fileid`, `path`
320 320
 					FROM `*PREFIX*filecache`
321 321
 					WHERE `fileid` IN (' . implode(',', $fileTargetIDs) . ')'
322
-				);
323
-				$result = $query->execute();
324
-
325
-				if (\OCP\DB::isError($result)) {
326
-					\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
327
-				} else {
328
-					while ($row = $result->fetchRow()) {
329
-						foreach ($fileTargets[$row['fileid']] as $uid => $shareData) {
330
-							if ($mountPath !== false) {
331
-								$sharedPath = $shareData['file_target'];
332
-								$sharedPath .= substr($path, strlen($mountPath) + strlen($paths[$row['fileid']]));
333
-								$sharePaths[$uid] = $sharedPath;
334
-							} else {
335
-								$sharedPath = $shareData['file_target'];
336
-								$sharedPath .= substr($path, strlen($row['path']) -5);
337
-								$sharePaths[$uid] = $sharedPath;
338
-							}
339
-						}
340
-					}
341
-				}
342
-			}
343
-
344
-			if ($includeOwner) {
345
-				$sharePaths[$ownerUser] = $path;
346
-			} else {
347
-				unset($sharePaths[$ownerUser]);
348
-			}
349
-
350
-			return $sharePaths;
351
-		}
352
-
353
-		return array('users' => array_unique($shares), 'public' => $publicShare, 'remote' => $remoteShare);
354
-	}
355
-
356
-	/**
357
-	 * Get the items of item type shared with the current user
358
-	 * @param string $itemType
359
-	 * @param int $format (optional) Format type must be defined by the backend
360
-	 * @param mixed $parameters (optional)
361
-	 * @param int $limit Number of items to return (optional) Returns all by default
362
-	 * @param boolean $includeCollections (optional)
363
-	 * @return mixed Return depends on format
364
-	 */
365
-	public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
366
-											  $parameters = null, $limit = -1, $includeCollections = false) {
367
-		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
368
-			$parameters, $limit, $includeCollections);
369
-	}
370
-
371
-	/**
372
-	 * Get the items of item type shared with a user
373
-	 * @param string $itemType
374
-	 * @param string $user id for which user we want the shares
375
-	 * @param int $format (optional) Format type must be defined by the backend
376
-	 * @param mixed $parameters (optional)
377
-	 * @param int $limit Number of items to return (optional) Returns all by default
378
-	 * @param boolean $includeCollections (optional)
379
-	 * @return mixed Return depends on format
380
-	 */
381
-	public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
382
-												  $parameters = null, $limit = -1, $includeCollections = false) {
383
-		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
384
-			$parameters, $limit, $includeCollections);
385
-	}
386
-
387
-	/**
388
-	 * Get the item of item type shared with the current user
389
-	 * @param string $itemType
390
-	 * @param string $itemTarget
391
-	 * @param int $format (optional) Format type must be defined by the backend
392
-	 * @param mixed $parameters (optional)
393
-	 * @param boolean $includeCollections (optional)
394
-	 * @return mixed Return depends on format
395
-	 */
396
-	public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE,
397
-											 $parameters = null, $includeCollections = false) {
398
-		return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
399
-			$parameters, 1, $includeCollections);
400
-	}
401
-
402
-	/**
403
-	 * Get the item of item type shared with a given user by source
404
-	 * @param string $itemType
405
-	 * @param string $itemSource
406
-	 * @param string $user User to whom the item was shared
407
-	 * @param string $owner Owner of the share
408
-	 * @param int $shareType only look for a specific share type
409
-	 * @return array Return list of items with file_target, permissions and expiration
410
-	 */
411
-	public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
412
-		$shares = array();
413
-		$fileDependent = false;
414
-
415
-		$where = 'WHERE';
416
-		$fileDependentWhere = '';
417
-		if ($itemType === 'file' || $itemType === 'folder') {
418
-			$fileDependent = true;
419
-			$column = 'file_source';
420
-			$fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
421
-			$fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
422
-		} else {
423
-			$column = 'item_source';
424
-		}
425
-
426
-		$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
427
-
428
-		$where .= ' `' . $column . '` = ? AND `item_type` = ? ';
429
-		$arguments = array($itemSource, $itemType);
430
-		// for link shares $user === null
431
-		if ($user !== null) {
432
-			$where .= ' AND `share_with` = ? ';
433
-			$arguments[] = $user;
434
-		}
435
-
436
-		if ($shareType !== null) {
437
-			$where .= ' AND `share_type` = ? ';
438
-			$arguments[] = $shareType;
439
-		}
440
-
441
-		if ($owner !== null) {
442
-			$where .= ' AND `uid_owner` = ? ';
443
-			$arguments[] = $owner;
444
-		}
445
-
446
-		$query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
447
-
448
-		$result = \OC_DB::executeAudited($query, $arguments);
449
-
450
-		while ($row = $result->fetchRow()) {
451
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
452
-				continue;
453
-			}
454
-			if ($fileDependent && (int)$row['file_parent'] === -1) {
455
-				// if it is a mount point we need to get the path from the mount manager
456
-				$mountManager = \OC\Files\Filesystem::getMountManager();
457
-				$mountPoint = $mountManager->findByStorageId($row['storage_id']);
458
-				if (!empty($mountPoint)) {
459
-					$path = $mountPoint[0]->getMountPoint();
460
-					$path = trim($path, '/');
461
-					$path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
462
-					$row['path'] = $path;
463
-				} else {
464
-					\OC::$server->getLogger()->warning(
465
-						'Could not resolve mount point for ' . $row['storage_id'],
466
-						['app' => 'OCP\Share']
467
-					);
468
-				}
469
-			}
470
-			$shares[] = $row;
471
-		}
472
-
473
-		//if didn't found a result than let's look for a group share.
474
-		if(empty($shares) && $user !== null) {
475
-			$userObject = \OC::$server->getUserManager()->get($user);
476
-			$groups = [];
477
-			if ($userObject) {
478
-				$groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
479
-			}
480
-
481
-			if (!empty($groups)) {
482
-				$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
483
-				$arguments = array($itemSource, $itemType, $groups);
484
-				$types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
485
-
486
-				if ($owner !== null) {
487
-					$where .= ' AND `uid_owner` = ?';
488
-					$arguments[] = $owner;
489
-					$types[] = null;
490
-				}
491
-
492
-				// TODO: inject connection, hopefully one day in the future when this
493
-				// class isn't static anymore...
494
-				$conn = \OC::$server->getDatabaseConnection();
495
-				$result = $conn->executeQuery(
496
-					'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
497
-					$arguments,
498
-					$types
499
-				);
500
-
501
-				while ($row = $result->fetch()) {
502
-					$shares[] = $row;
503
-				}
504
-			}
505
-		}
506
-
507
-		return $shares;
508
-
509
-	}
510
-
511
-	/**
512
-	 * Get the item of item type shared with the current user by source
513
-	 * @param string $itemType
514
-	 * @param string $itemSource
515
-	 * @param int $format (optional) Format type must be defined by the backend
516
-	 * @param mixed $parameters
517
-	 * @param boolean $includeCollections
518
-	 * @param string $shareWith (optional) define against which user should be checked, default: current user
519
-	 * @return array
520
-	 */
521
-	public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
522
-													 $parameters = null, $includeCollections = false, $shareWith = null) {
523
-		$shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
524
-		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
525
-			$parameters, 1, $includeCollections, true);
526
-	}
527
-
528
-	/**
529
-	 * Get the item of item type shared by a link
530
-	 * @param string $itemType
531
-	 * @param string $itemSource
532
-	 * @param string $uidOwner Owner of link
533
-	 * @return array
534
-	 */
535
-	public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) {
536
-		return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE,
537
-			null, 1);
538
-	}
539
-
540
-	/**
541
-	 * Based on the given token the share information will be returned - password protected shares will be verified
542
-	 * @param string $token
543
-	 * @param bool $checkPasswordProtection
544
-	 * @return array|boolean false will be returned in case the token is unknown or unauthorized
545
-	 */
546
-	public static function getShareByToken($token, $checkPasswordProtection = true) {
547
-		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
548
-		$result = $query->execute(array($token));
549
-		if ($result === false) {
550
-			\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
551
-		}
552
-		$row = $result->fetchRow();
553
-		if ($row === false) {
554
-			return false;
555
-		}
556
-		if (is_array($row) and self::expireItem($row)) {
557
-			return false;
558
-		}
559
-
560
-		// password protected shares need to be authenticated
561
-		if ($checkPasswordProtection && !\OCP\Share::checkPasswordProtectedShare($row)) {
562
-			return false;
563
-		}
564
-
565
-		return $row;
566
-	}
567
-
568
-	/**
569
-	 * resolves reshares down to the last real share
570
-	 * @param array $linkItem
571
-	 * @return array file owner
572
-	 */
573
-	public static function resolveReShare($linkItem)
574
-	{
575
-		if (isset($linkItem['parent'])) {
576
-			$parent = $linkItem['parent'];
577
-			while (isset($parent)) {
578
-				$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
579
-				$item = $query->execute(array($parent))->fetchRow();
580
-				if (isset($item['parent'])) {
581
-					$parent = $item['parent'];
582
-				} else {
583
-					return $item;
584
-				}
585
-			}
586
-		}
587
-		return $linkItem;
588
-	}
589
-
590
-
591
-	/**
592
-	 * Get the shared items of item type owned by the current user
593
-	 * @param string $itemType
594
-	 * @param int $format (optional) Format type must be defined by the backend
595
-	 * @param mixed $parameters
596
-	 * @param int $limit Number of items to return (optional) Returns all by default
597
-	 * @param boolean $includeCollections
598
-	 * @return mixed Return depends on format
599
-	 */
600
-	public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
601
-										  $limit = -1, $includeCollections = false) {
602
-		return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
603
-			$parameters, $limit, $includeCollections);
604
-	}
605
-
606
-	/**
607
-	 * Get the shared item of item type owned by the current user
608
-	 * @param string $itemType
609
-	 * @param string $itemSource
610
-	 * @param int $format (optional) Format type must be defined by the backend
611
-	 * @param mixed $parameters
612
-	 * @param boolean $includeCollections
613
-	 * @return mixed Return depends on format
614
-	 */
615
-	public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
616
-										 $parameters = null, $includeCollections = false) {
617
-		return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
618
-			$parameters, -1, $includeCollections);
619
-	}
620
-
621
-	/**
622
-	 * Get all users an item is shared with
623
-	 * @param string $itemType
624
-	 * @param string $itemSource
625
-	 * @param string $uidOwner
626
-	 * @param boolean $includeCollections
627
-	 * @param boolean $checkExpireDate
628
-	 * @return array Return array of users
629
-	 */
630
-	public static function getUsersItemShared($itemType, $itemSource, $uidOwner, $includeCollections = false, $checkExpireDate = true) {
631
-
632
-		$users = array();
633
-		$items = self::getItems($itemType, $itemSource, null, null, $uidOwner, self::FORMAT_NONE, null, -1, $includeCollections, false, $checkExpireDate);
634
-		if ($items) {
635
-			foreach ($items as $item) {
636
-				if ((int)$item['share_type'] === self::SHARE_TYPE_USER) {
637
-					$users[] = $item['share_with'];
638
-				} else if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) {
639
-
640
-					$group = \OC::$server->getGroupManager()->get($item['share_with']);
641
-					$userIds = [];
642
-					if ($group) {
643
-						$users = $group->searchUsers('', -1, 0);
644
-						foreach ($users as $user) {
645
-							$userIds[] = $user->getUID();
646
-						}
647
-						return $userIds;
648
-					}
649
-
650
-					$users = array_merge($users, $userIds);
651
-				}
652
-			}
653
-		}
654
-		return $users;
655
-	}
656
-
657
-	/**
658
-	 * Share an item with a user, group, or via private link
659
-	 * @param string $itemType
660
-	 * @param string $itemSource
661
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
662
-	 * @param string $shareWith User or group the item is being shared with
663
-	 * @param int $permissions CRUDS
664
-	 * @param string $itemSourceName
665
-	 * @param \DateTime $expirationDate
666
-	 * @param bool $passwordChanged
667
-	 * @return boolean|string Returns true on success or false on failure, Returns token on success for links
668
-	 * @throws \OC\HintException when the share type is remote and the shareWith is invalid
669
-	 * @throws \Exception
670
-	 */
671
-	public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
672
-
673
-		$backend = self::getBackend($itemType);
674
-		$l = \OC::$server->getL10N('lib');
675
-
676
-		if ($backend->isShareTypeAllowed($shareType) === false) {
677
-			$message = 'Sharing %s failed, because the backend does not allow shares from type %i';
678
-			$message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
679
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), \OCP\Util::DEBUG);
680
-			throw new \Exception($message_t);
681
-		}
682
-
683
-		$uidOwner = \OC_User::getUser();
684
-		$shareWithinGroupOnly = self::shareWithGroupMembersOnly();
685
-
686
-		if (is_null($itemSourceName)) {
687
-			$itemSourceName = $itemSource;
688
-		}
689
-		$itemName = $itemSourceName;
690
-
691
-		// check if file can be shared
692
-		if ($itemType === 'file' or $itemType === 'folder') {
693
-			$path = \OC\Files\Filesystem::getPath($itemSource);
694
-			$itemName = $path;
695
-
696
-			// verify that the file exists before we try to share it
697
-			if (!$path) {
698
-				$message = 'Sharing %s failed, because the file does not exist';
699
-				$message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
700
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
701
-				throw new \Exception($message_t);
702
-			}
703
-			// verify that the user has share permission
704
-			if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
705
-				$message = 'You are not allowed to share %s';
706
-				$message_t = $l->t('You are not allowed to share %s', [$path]);
707
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
708
-				throw new \Exception($message_t);
709
-			}
710
-		}
711
-
712
-		//verify that we don't share a folder which already contains a share mount point
713
-		if ($itemType === 'folder') {
714
-			$path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
715
-			$mountManager = \OC\Files\Filesystem::getMountManager();
716
-			$mounts = $mountManager->findIn($path);
717
-			foreach ($mounts as $mount) {
718
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
719
-					$message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
720
-					\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
721
-					throw new \Exception($message);
722
-				}
723
-
724
-			}
725
-		}
726
-
727
-		// single file shares should never have delete permissions
728
-		if ($itemType === 'file') {
729
-			$permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
730
-		}
731
-
732
-		//Validate expirationDate
733
-		if ($expirationDate !== null) {
734
-			try {
735
-				/*
322
+                );
323
+                $result = $query->execute();
324
+
325
+                if (\OCP\DB::isError($result)) {
326
+                    \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OCP\Util::ERROR);
327
+                } else {
328
+                    while ($row = $result->fetchRow()) {
329
+                        foreach ($fileTargets[$row['fileid']] as $uid => $shareData) {
330
+                            if ($mountPath !== false) {
331
+                                $sharedPath = $shareData['file_target'];
332
+                                $sharedPath .= substr($path, strlen($mountPath) + strlen($paths[$row['fileid']]));
333
+                                $sharePaths[$uid] = $sharedPath;
334
+                            } else {
335
+                                $sharedPath = $shareData['file_target'];
336
+                                $sharedPath .= substr($path, strlen($row['path']) -5);
337
+                                $sharePaths[$uid] = $sharedPath;
338
+                            }
339
+                        }
340
+                    }
341
+                }
342
+            }
343
+
344
+            if ($includeOwner) {
345
+                $sharePaths[$ownerUser] = $path;
346
+            } else {
347
+                unset($sharePaths[$ownerUser]);
348
+            }
349
+
350
+            return $sharePaths;
351
+        }
352
+
353
+        return array('users' => array_unique($shares), 'public' => $publicShare, 'remote' => $remoteShare);
354
+    }
355
+
356
+    /**
357
+     * Get the items of item type shared with the current user
358
+     * @param string $itemType
359
+     * @param int $format (optional) Format type must be defined by the backend
360
+     * @param mixed $parameters (optional)
361
+     * @param int $limit Number of items to return (optional) Returns all by default
362
+     * @param boolean $includeCollections (optional)
363
+     * @return mixed Return depends on format
364
+     */
365
+    public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
366
+                                                $parameters = null, $limit = -1, $includeCollections = false) {
367
+        return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
368
+            $parameters, $limit, $includeCollections);
369
+    }
370
+
371
+    /**
372
+     * Get the items of item type shared with a user
373
+     * @param string $itemType
374
+     * @param string $user id for which user we want the shares
375
+     * @param int $format (optional) Format type must be defined by the backend
376
+     * @param mixed $parameters (optional)
377
+     * @param int $limit Number of items to return (optional) Returns all by default
378
+     * @param boolean $includeCollections (optional)
379
+     * @return mixed Return depends on format
380
+     */
381
+    public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
382
+                                                    $parameters = null, $limit = -1, $includeCollections = false) {
383
+        return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
384
+            $parameters, $limit, $includeCollections);
385
+    }
386
+
387
+    /**
388
+     * Get the item of item type shared with the current user
389
+     * @param string $itemType
390
+     * @param string $itemTarget
391
+     * @param int $format (optional) Format type must be defined by the backend
392
+     * @param mixed $parameters (optional)
393
+     * @param boolean $includeCollections (optional)
394
+     * @return mixed Return depends on format
395
+     */
396
+    public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE,
397
+                                                $parameters = null, $includeCollections = false) {
398
+        return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
399
+            $parameters, 1, $includeCollections);
400
+    }
401
+
402
+    /**
403
+     * Get the item of item type shared with a given user by source
404
+     * @param string $itemType
405
+     * @param string $itemSource
406
+     * @param string $user User to whom the item was shared
407
+     * @param string $owner Owner of the share
408
+     * @param int $shareType only look for a specific share type
409
+     * @return array Return list of items with file_target, permissions and expiration
410
+     */
411
+    public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
412
+        $shares = array();
413
+        $fileDependent = false;
414
+
415
+        $where = 'WHERE';
416
+        $fileDependentWhere = '';
417
+        if ($itemType === 'file' || $itemType === 'folder') {
418
+            $fileDependent = true;
419
+            $column = 'file_source';
420
+            $fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
421
+            $fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
422
+        } else {
423
+            $column = 'item_source';
424
+        }
425
+
426
+        $select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
427
+
428
+        $where .= ' `' . $column . '` = ? AND `item_type` = ? ';
429
+        $arguments = array($itemSource, $itemType);
430
+        // for link shares $user === null
431
+        if ($user !== null) {
432
+            $where .= ' AND `share_with` = ? ';
433
+            $arguments[] = $user;
434
+        }
435
+
436
+        if ($shareType !== null) {
437
+            $where .= ' AND `share_type` = ? ';
438
+            $arguments[] = $shareType;
439
+        }
440
+
441
+        if ($owner !== null) {
442
+            $where .= ' AND `uid_owner` = ? ';
443
+            $arguments[] = $owner;
444
+        }
445
+
446
+        $query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
447
+
448
+        $result = \OC_DB::executeAudited($query, $arguments);
449
+
450
+        while ($row = $result->fetchRow()) {
451
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
452
+                continue;
453
+            }
454
+            if ($fileDependent && (int)$row['file_parent'] === -1) {
455
+                // if it is a mount point we need to get the path from the mount manager
456
+                $mountManager = \OC\Files\Filesystem::getMountManager();
457
+                $mountPoint = $mountManager->findByStorageId($row['storage_id']);
458
+                if (!empty($mountPoint)) {
459
+                    $path = $mountPoint[0]->getMountPoint();
460
+                    $path = trim($path, '/');
461
+                    $path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
462
+                    $row['path'] = $path;
463
+                } else {
464
+                    \OC::$server->getLogger()->warning(
465
+                        'Could not resolve mount point for ' . $row['storage_id'],
466
+                        ['app' => 'OCP\Share']
467
+                    );
468
+                }
469
+            }
470
+            $shares[] = $row;
471
+        }
472
+
473
+        //if didn't found a result than let's look for a group share.
474
+        if(empty($shares) && $user !== null) {
475
+            $userObject = \OC::$server->getUserManager()->get($user);
476
+            $groups = [];
477
+            if ($userObject) {
478
+                $groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
479
+            }
480
+
481
+            if (!empty($groups)) {
482
+                $where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
483
+                $arguments = array($itemSource, $itemType, $groups);
484
+                $types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
485
+
486
+                if ($owner !== null) {
487
+                    $where .= ' AND `uid_owner` = ?';
488
+                    $arguments[] = $owner;
489
+                    $types[] = null;
490
+                }
491
+
492
+                // TODO: inject connection, hopefully one day in the future when this
493
+                // class isn't static anymore...
494
+                $conn = \OC::$server->getDatabaseConnection();
495
+                $result = $conn->executeQuery(
496
+                    'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
497
+                    $arguments,
498
+                    $types
499
+                );
500
+
501
+                while ($row = $result->fetch()) {
502
+                    $shares[] = $row;
503
+                }
504
+            }
505
+        }
506
+
507
+        return $shares;
508
+
509
+    }
510
+
511
+    /**
512
+     * Get the item of item type shared with the current user by source
513
+     * @param string $itemType
514
+     * @param string $itemSource
515
+     * @param int $format (optional) Format type must be defined by the backend
516
+     * @param mixed $parameters
517
+     * @param boolean $includeCollections
518
+     * @param string $shareWith (optional) define against which user should be checked, default: current user
519
+     * @return array
520
+     */
521
+    public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
522
+                                                        $parameters = null, $includeCollections = false, $shareWith = null) {
523
+        $shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
524
+        return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
525
+            $parameters, 1, $includeCollections, true);
526
+    }
527
+
528
+    /**
529
+     * Get the item of item type shared by a link
530
+     * @param string $itemType
531
+     * @param string $itemSource
532
+     * @param string $uidOwner Owner of link
533
+     * @return array
534
+     */
535
+    public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) {
536
+        return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE,
537
+            null, 1);
538
+    }
539
+
540
+    /**
541
+     * Based on the given token the share information will be returned - password protected shares will be verified
542
+     * @param string $token
543
+     * @param bool $checkPasswordProtection
544
+     * @return array|boolean false will be returned in case the token is unknown or unauthorized
545
+     */
546
+    public static function getShareByToken($token, $checkPasswordProtection = true) {
547
+        $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
548
+        $result = $query->execute(array($token));
549
+        if ($result === false) {
550
+            \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
551
+        }
552
+        $row = $result->fetchRow();
553
+        if ($row === false) {
554
+            return false;
555
+        }
556
+        if (is_array($row) and self::expireItem($row)) {
557
+            return false;
558
+        }
559
+
560
+        // password protected shares need to be authenticated
561
+        if ($checkPasswordProtection && !\OCP\Share::checkPasswordProtectedShare($row)) {
562
+            return false;
563
+        }
564
+
565
+        return $row;
566
+    }
567
+
568
+    /**
569
+     * resolves reshares down to the last real share
570
+     * @param array $linkItem
571
+     * @return array file owner
572
+     */
573
+    public static function resolveReShare($linkItem)
574
+    {
575
+        if (isset($linkItem['parent'])) {
576
+            $parent = $linkItem['parent'];
577
+            while (isset($parent)) {
578
+                $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
579
+                $item = $query->execute(array($parent))->fetchRow();
580
+                if (isset($item['parent'])) {
581
+                    $parent = $item['parent'];
582
+                } else {
583
+                    return $item;
584
+                }
585
+            }
586
+        }
587
+        return $linkItem;
588
+    }
589
+
590
+
591
+    /**
592
+     * Get the shared items of item type owned by the current user
593
+     * @param string $itemType
594
+     * @param int $format (optional) Format type must be defined by the backend
595
+     * @param mixed $parameters
596
+     * @param int $limit Number of items to return (optional) Returns all by default
597
+     * @param boolean $includeCollections
598
+     * @return mixed Return depends on format
599
+     */
600
+    public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
601
+                                            $limit = -1, $includeCollections = false) {
602
+        return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
603
+            $parameters, $limit, $includeCollections);
604
+    }
605
+
606
+    /**
607
+     * Get the shared item of item type owned by the current user
608
+     * @param string $itemType
609
+     * @param string $itemSource
610
+     * @param int $format (optional) Format type must be defined by the backend
611
+     * @param mixed $parameters
612
+     * @param boolean $includeCollections
613
+     * @return mixed Return depends on format
614
+     */
615
+    public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
616
+                                            $parameters = null, $includeCollections = false) {
617
+        return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
618
+            $parameters, -1, $includeCollections);
619
+    }
620
+
621
+    /**
622
+     * Get all users an item is shared with
623
+     * @param string $itemType
624
+     * @param string $itemSource
625
+     * @param string $uidOwner
626
+     * @param boolean $includeCollections
627
+     * @param boolean $checkExpireDate
628
+     * @return array Return array of users
629
+     */
630
+    public static function getUsersItemShared($itemType, $itemSource, $uidOwner, $includeCollections = false, $checkExpireDate = true) {
631
+
632
+        $users = array();
633
+        $items = self::getItems($itemType, $itemSource, null, null, $uidOwner, self::FORMAT_NONE, null, -1, $includeCollections, false, $checkExpireDate);
634
+        if ($items) {
635
+            foreach ($items as $item) {
636
+                if ((int)$item['share_type'] === self::SHARE_TYPE_USER) {
637
+                    $users[] = $item['share_with'];
638
+                } else if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) {
639
+
640
+                    $group = \OC::$server->getGroupManager()->get($item['share_with']);
641
+                    $userIds = [];
642
+                    if ($group) {
643
+                        $users = $group->searchUsers('', -1, 0);
644
+                        foreach ($users as $user) {
645
+                            $userIds[] = $user->getUID();
646
+                        }
647
+                        return $userIds;
648
+                    }
649
+
650
+                    $users = array_merge($users, $userIds);
651
+                }
652
+            }
653
+        }
654
+        return $users;
655
+    }
656
+
657
+    /**
658
+     * Share an item with a user, group, or via private link
659
+     * @param string $itemType
660
+     * @param string $itemSource
661
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
662
+     * @param string $shareWith User or group the item is being shared with
663
+     * @param int $permissions CRUDS
664
+     * @param string $itemSourceName
665
+     * @param \DateTime $expirationDate
666
+     * @param bool $passwordChanged
667
+     * @return boolean|string Returns true on success or false on failure, Returns token on success for links
668
+     * @throws \OC\HintException when the share type is remote and the shareWith is invalid
669
+     * @throws \Exception
670
+     */
671
+    public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
672
+
673
+        $backend = self::getBackend($itemType);
674
+        $l = \OC::$server->getL10N('lib');
675
+
676
+        if ($backend->isShareTypeAllowed($shareType) === false) {
677
+            $message = 'Sharing %s failed, because the backend does not allow shares from type %i';
678
+            $message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
679
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), \OCP\Util::DEBUG);
680
+            throw new \Exception($message_t);
681
+        }
682
+
683
+        $uidOwner = \OC_User::getUser();
684
+        $shareWithinGroupOnly = self::shareWithGroupMembersOnly();
685
+
686
+        if (is_null($itemSourceName)) {
687
+            $itemSourceName = $itemSource;
688
+        }
689
+        $itemName = $itemSourceName;
690
+
691
+        // check if file can be shared
692
+        if ($itemType === 'file' or $itemType === 'folder') {
693
+            $path = \OC\Files\Filesystem::getPath($itemSource);
694
+            $itemName = $path;
695
+
696
+            // verify that the file exists before we try to share it
697
+            if (!$path) {
698
+                $message = 'Sharing %s failed, because the file does not exist';
699
+                $message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
700
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
701
+                throw new \Exception($message_t);
702
+            }
703
+            // verify that the user has share permission
704
+            if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
705
+                $message = 'You are not allowed to share %s';
706
+                $message_t = $l->t('You are not allowed to share %s', [$path]);
707
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
708
+                throw new \Exception($message_t);
709
+            }
710
+        }
711
+
712
+        //verify that we don't share a folder which already contains a share mount point
713
+        if ($itemType === 'folder') {
714
+            $path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
715
+            $mountManager = \OC\Files\Filesystem::getMountManager();
716
+            $mounts = $mountManager->findIn($path);
717
+            foreach ($mounts as $mount) {
718
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
719
+                    $message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
720
+                    \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
721
+                    throw new \Exception($message);
722
+                }
723
+
724
+            }
725
+        }
726
+
727
+        // single file shares should never have delete permissions
728
+        if ($itemType === 'file') {
729
+            $permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
730
+        }
731
+
732
+        //Validate expirationDate
733
+        if ($expirationDate !== null) {
734
+            try {
735
+                /*
736 736
 				 * Reuse the validateExpireDate.
737 737
 				 * We have to pass time() since the second arg is the time
738 738
 				 * the file was shared, since it is not shared yet we just use
739 739
 				 * the current time.
740 740
 				 */
741
-				$expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
742
-			} catch (\Exception $e) {
743
-				throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
744
-			}
745
-		}
746
-
747
-		// Verify share type and sharing conditions are met
748
-		if ($shareType === self::SHARE_TYPE_USER) {
749
-			if ($shareWith == $uidOwner) {
750
-				$message = 'Sharing %s failed, because you can not share with yourself';
751
-				$message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
752
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
753
-				throw new \Exception($message_t);
754
-			}
755
-			if (!\OC_User::userExists($shareWith)) {
756
-				$message = 'Sharing %s failed, because the user %s does not exist';
757
-				$message_t = $l->t('Sharing %s failed, because the user %s does not exist', array($itemSourceName, $shareWith));
758
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
759
-				throw new \Exception($message_t);
760
-			}
761
-			if ($shareWithinGroupOnly) {
762
-				$userManager = \OC::$server->getUserManager();
763
-				$groupManager = \OC::$server->getGroupManager();
764
-				$userOwner = $userManager->get($uidOwner);
765
-				$userShareWith = $userManager->get($shareWith);
766
-				$groupsOwner = [];
767
-				$groupsShareWith = [];
768
-				if ($userOwner) {
769
-					$groupsOwner = $groupManager->getUserGroupIds($userOwner);
770
-				}
771
-				if ($userShareWith) {
772
-					$groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
773
-				}
774
-				$inGroup = array_intersect($groupsOwner, $groupsShareWith);
775
-				if (empty($inGroup)) {
776
-					$message = 'Sharing %s failed, because the user '
777
-						.'%s is not a member of any groups that %s is a member of';
778
-					$message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner));
779
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
780
-					throw new \Exception($message_t);
781
-				}
782
-			}
783
-			// Check if the item source is already shared with the user, either from the same owner or a different user
784
-			if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
785
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
786
-				// Only allow the same share to occur again if it is the same
787
-				// owner and is not a user share, this use case is for increasing
788
-				// permissions for a specific user
789
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
790
-					$message = 'Sharing %s failed, because this item is already shared with %s';
791
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
792
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
793
-					throw new \Exception($message_t);
794
-				}
795
-			}
796
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
797
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
798
-				// Only allow the same share to occur again if it is the same
799
-				// owner and is not a user share, this use case is for increasing
800
-				// permissions for a specific user
801
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
802
-					$message = 'Sharing %s failed, because this item is already shared with user %s';
803
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with user %s', array($itemSourceName, $shareWith));
804
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::ERROR);
805
-					throw new \Exception($message_t);
806
-				}
807
-			}
808
-		} else if ($shareType === self::SHARE_TYPE_GROUP) {
809
-			if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
810
-				$message = 'Sharing %s failed, because the group %s does not exist';
811
-				$message_t = $l->t('Sharing %s failed, because the group %s does not exist', array($itemSourceName, $shareWith));
812
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
813
-				throw new \Exception($message_t);
814
-			}
815
-			if ($shareWithinGroupOnly) {
816
-				$group = \OC::$server->getGroupManager()->get($shareWith);
817
-				$user = \OC::$server->getUserManager()->get($uidOwner);
818
-				if (!$group || !$user || !$group->inGroup($user)) {
819
-					$message = 'Sharing %s failed, because '
820
-						. '%s is not a member of the group %s';
821
-					$message_t = $l->t('Sharing %s failed, because %s is not a member of the group %s', array($itemSourceName, $uidOwner, $shareWith));
822
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), \OCP\Util::DEBUG);
823
-					throw new \Exception($message_t);
824
-				}
825
-			}
826
-			// Check if the item source is already shared with the group, either from the same owner or a different user
827
-			// The check for each user in the group is done inside the put() function
828
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
829
-				null, self::FORMAT_NONE, null, 1, true, true)) {
830
-
831
-				if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
832
-					$message = 'Sharing %s failed, because this item is already shared with %s';
833
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
834
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
835
-					throw new \Exception($message_t);
836
-				}
837
-			}
838
-			// Convert share with into an array with the keys group and users
839
-			$group = $shareWith;
840
-			$shareWith = array();
841
-			$shareWith['group'] = $group;
842
-
843
-
844
-			$groupObject = \OC::$server->getGroupManager()->get($group);
845
-			$userIds = [];
846
-			if ($groupObject) {
847
-				$users = $groupObject->searchUsers('', -1, 0);
848
-				foreach ($users as $user) {
849
-					$userIds[] = $user->getUID();
850
-				}
851
-			}
852
-
853
-			$shareWith['users'] = array_diff($userIds, array($uidOwner));
854
-		} else if ($shareType === self::SHARE_TYPE_LINK) {
855
-			$updateExistingShare = false;
856
-			if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
857
-
858
-				// IF the password is changed via the old ajax endpoint verify it before deleting the old share
859
-				if ($passwordChanged === true) {
860
-					self::verifyPassword($shareWith);
861
-				}
862
-
863
-				// when updating a link share
864
-				// FIXME Don't delete link if we update it
865
-				if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
866
-					$uidOwner, self::FORMAT_NONE, null, 1)) {
867
-					// remember old token
868
-					$oldToken = $checkExists['token'];
869
-					$oldPermissions = $checkExists['permissions'];
870
-					//delete the old share
871
-					Helper::delete($checkExists['id']);
872
-					$updateExistingShare = true;
873
-				}
874
-
875
-				if ($passwordChanged === null) {
876
-					// Generate hash of password - same method as user passwords
877
-					if (is_string($shareWith) && $shareWith !== '') {
878
-						self::verifyPassword($shareWith);
879
-						$shareWith = \OC::$server->getHasher()->hash($shareWith);
880
-					} else {
881
-						// reuse the already set password, but only if we change permissions
882
-						// otherwise the user disabled the password protection
883
-						if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
884
-							$shareWith = $checkExists['share_with'];
885
-						}
886
-					}
887
-				} else {
888
-					if ($passwordChanged === true) {
889
-						if (is_string($shareWith) && $shareWith !== '') {
890
-							self::verifyPassword($shareWith);
891
-							$shareWith = \OC::$server->getHasher()->hash($shareWith);
892
-						}
893
-					} else if ($updateExistingShare) {
894
-						$shareWith = $checkExists['share_with'];
895
-					}
896
-				}
897
-
898
-				if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
899
-					$message = 'You need to provide a password to create a public link, only protected links are allowed';
900
-					$message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
901
-					\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
902
-					throw new \Exception($message_t);
903
-				}
904
-
905
-				if ($updateExistingShare === false &&
906
-					self::isDefaultExpireDateEnabled() &&
907
-					empty($expirationDate)) {
908
-					$expirationDate = Helper::calcExpireDate();
909
-				}
910
-
911
-				// Generate token
912
-				if (isset($oldToken)) {
913
-					$token = $oldToken;
914
-				} else {
915
-					$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
916
-						\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
917
-					);
918
-				}
919
-				$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
920
-					null, $token, $itemSourceName, $expirationDate);
921
-				if ($result) {
922
-					return $token;
923
-				} else {
924
-					return false;
925
-				}
926
-			}
927
-			$message = 'Sharing %s failed, because sharing with links is not allowed';
928
-			$message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
929
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
930
-			throw new \Exception($message_t);
931
-		} else if ($shareType === self::SHARE_TYPE_REMOTE) {
932
-
933
-			/*
741
+                $expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
742
+            } catch (\Exception $e) {
743
+                throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
744
+            }
745
+        }
746
+
747
+        // Verify share type and sharing conditions are met
748
+        if ($shareType === self::SHARE_TYPE_USER) {
749
+            if ($shareWith == $uidOwner) {
750
+                $message = 'Sharing %s failed, because you can not share with yourself';
751
+                $message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
752
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
753
+                throw new \Exception($message_t);
754
+            }
755
+            if (!\OC_User::userExists($shareWith)) {
756
+                $message = 'Sharing %s failed, because the user %s does not exist';
757
+                $message_t = $l->t('Sharing %s failed, because the user %s does not exist', array($itemSourceName, $shareWith));
758
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
759
+                throw new \Exception($message_t);
760
+            }
761
+            if ($shareWithinGroupOnly) {
762
+                $userManager = \OC::$server->getUserManager();
763
+                $groupManager = \OC::$server->getGroupManager();
764
+                $userOwner = $userManager->get($uidOwner);
765
+                $userShareWith = $userManager->get($shareWith);
766
+                $groupsOwner = [];
767
+                $groupsShareWith = [];
768
+                if ($userOwner) {
769
+                    $groupsOwner = $groupManager->getUserGroupIds($userOwner);
770
+                }
771
+                if ($userShareWith) {
772
+                    $groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
773
+                }
774
+                $inGroup = array_intersect($groupsOwner, $groupsShareWith);
775
+                if (empty($inGroup)) {
776
+                    $message = 'Sharing %s failed, because the user '
777
+                        .'%s is not a member of any groups that %s is a member of';
778
+                    $message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner));
779
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
780
+                    throw new \Exception($message_t);
781
+                }
782
+            }
783
+            // Check if the item source is already shared with the user, either from the same owner or a different user
784
+            if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
785
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
786
+                // Only allow the same share to occur again if it is the same
787
+                // owner and is not a user share, this use case is for increasing
788
+                // permissions for a specific user
789
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
790
+                    $message = 'Sharing %s failed, because this item is already shared with %s';
791
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
792
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
793
+                    throw new \Exception($message_t);
794
+                }
795
+            }
796
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
797
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
798
+                // Only allow the same share to occur again if it is the same
799
+                // owner and is not a user share, this use case is for increasing
800
+                // permissions for a specific user
801
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
802
+                    $message = 'Sharing %s failed, because this item is already shared with user %s';
803
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with user %s', array($itemSourceName, $shareWith));
804
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::ERROR);
805
+                    throw new \Exception($message_t);
806
+                }
807
+            }
808
+        } else if ($shareType === self::SHARE_TYPE_GROUP) {
809
+            if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
810
+                $message = 'Sharing %s failed, because the group %s does not exist';
811
+                $message_t = $l->t('Sharing %s failed, because the group %s does not exist', array($itemSourceName, $shareWith));
812
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
813
+                throw new \Exception($message_t);
814
+            }
815
+            if ($shareWithinGroupOnly) {
816
+                $group = \OC::$server->getGroupManager()->get($shareWith);
817
+                $user = \OC::$server->getUserManager()->get($uidOwner);
818
+                if (!$group || !$user || !$group->inGroup($user)) {
819
+                    $message = 'Sharing %s failed, because '
820
+                        . '%s is not a member of the group %s';
821
+                    $message_t = $l->t('Sharing %s failed, because %s is not a member of the group %s', array($itemSourceName, $uidOwner, $shareWith));
822
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), \OCP\Util::DEBUG);
823
+                    throw new \Exception($message_t);
824
+                }
825
+            }
826
+            // Check if the item source is already shared with the group, either from the same owner or a different user
827
+            // The check for each user in the group is done inside the put() function
828
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
829
+                null, self::FORMAT_NONE, null, 1, true, true)) {
830
+
831
+                if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
832
+                    $message = 'Sharing %s failed, because this item is already shared with %s';
833
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
834
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
835
+                    throw new \Exception($message_t);
836
+                }
837
+            }
838
+            // Convert share with into an array with the keys group and users
839
+            $group = $shareWith;
840
+            $shareWith = array();
841
+            $shareWith['group'] = $group;
842
+
843
+
844
+            $groupObject = \OC::$server->getGroupManager()->get($group);
845
+            $userIds = [];
846
+            if ($groupObject) {
847
+                $users = $groupObject->searchUsers('', -1, 0);
848
+                foreach ($users as $user) {
849
+                    $userIds[] = $user->getUID();
850
+                }
851
+            }
852
+
853
+            $shareWith['users'] = array_diff($userIds, array($uidOwner));
854
+        } else if ($shareType === self::SHARE_TYPE_LINK) {
855
+            $updateExistingShare = false;
856
+            if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
857
+
858
+                // IF the password is changed via the old ajax endpoint verify it before deleting the old share
859
+                if ($passwordChanged === true) {
860
+                    self::verifyPassword($shareWith);
861
+                }
862
+
863
+                // when updating a link share
864
+                // FIXME Don't delete link if we update it
865
+                if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
866
+                    $uidOwner, self::FORMAT_NONE, null, 1)) {
867
+                    // remember old token
868
+                    $oldToken = $checkExists['token'];
869
+                    $oldPermissions = $checkExists['permissions'];
870
+                    //delete the old share
871
+                    Helper::delete($checkExists['id']);
872
+                    $updateExistingShare = true;
873
+                }
874
+
875
+                if ($passwordChanged === null) {
876
+                    // Generate hash of password - same method as user passwords
877
+                    if (is_string($shareWith) && $shareWith !== '') {
878
+                        self::verifyPassword($shareWith);
879
+                        $shareWith = \OC::$server->getHasher()->hash($shareWith);
880
+                    } else {
881
+                        // reuse the already set password, but only if we change permissions
882
+                        // otherwise the user disabled the password protection
883
+                        if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
884
+                            $shareWith = $checkExists['share_with'];
885
+                        }
886
+                    }
887
+                } else {
888
+                    if ($passwordChanged === true) {
889
+                        if (is_string($shareWith) && $shareWith !== '') {
890
+                            self::verifyPassword($shareWith);
891
+                            $shareWith = \OC::$server->getHasher()->hash($shareWith);
892
+                        }
893
+                    } else if ($updateExistingShare) {
894
+                        $shareWith = $checkExists['share_with'];
895
+                    }
896
+                }
897
+
898
+                if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
899
+                    $message = 'You need to provide a password to create a public link, only protected links are allowed';
900
+                    $message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
901
+                    \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
902
+                    throw new \Exception($message_t);
903
+                }
904
+
905
+                if ($updateExistingShare === false &&
906
+                    self::isDefaultExpireDateEnabled() &&
907
+                    empty($expirationDate)) {
908
+                    $expirationDate = Helper::calcExpireDate();
909
+                }
910
+
911
+                // Generate token
912
+                if (isset($oldToken)) {
913
+                    $token = $oldToken;
914
+                } else {
915
+                    $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
916
+                        \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
917
+                    );
918
+                }
919
+                $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
920
+                    null, $token, $itemSourceName, $expirationDate);
921
+                if ($result) {
922
+                    return $token;
923
+                } else {
924
+                    return false;
925
+                }
926
+            }
927
+            $message = 'Sharing %s failed, because sharing with links is not allowed';
928
+            $message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
929
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
930
+            throw new \Exception($message_t);
931
+        } else if ($shareType === self::SHARE_TYPE_REMOTE) {
932
+
933
+            /*
934 934
 			 * Check if file is not already shared with the remote user
935 935
 			 */
936
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
937
-				$shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
938
-					$message = 'Sharing %s failed, because this item is already shared with %s';
939
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
940
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
941
-					throw new \Exception($message_t);
942
-			}
943
-
944
-			// don't allow federated shares if source and target server are the same
945
-			list($user, $remote) = Helper::splitUserRemote($shareWith);
946
-			$currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
947
-			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
948
-			if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
949
-				$message = 'Not allowed to create a federated share with the same user.';
950
-				$message_t = $l->t('Not allowed to create a federated share with the same user');
951
-				\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
952
-				throw new \Exception($message_t);
953
-			}
954
-
955
-			$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
956
-				\OCP\Security\ISecureRandom::CHAR_DIGITS);
957
-
958
-			$shareWith = $user . '@' . $remote;
959
-			$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
960
-
961
-			$send = false;
962
-			if ($shareId) {
963
-				$send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
964
-			}
965
-
966
-			if ($send === false) {
967
-				$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
968
-				self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
969
-				$message_t = $l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
970
-				throw new \Exception($message_t);
971
-			}
972
-
973
-			return $send;
974
-		} else {
975
-			// Future share types need to include their own conditions
976
-			$message = 'Share type %s is not valid for %s';
977
-			$message_t = $l->t('Share type %s is not valid for %s', array($shareType, $itemSource));
978
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), \OCP\Util::DEBUG);
979
-			throw new \Exception($message_t);
980
-		}
981
-
982
-		// Put the item into the database
983
-		$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
984
-
985
-		return $result ? true : false;
986
-	}
987
-
988
-	/**
989
-	 * Unshare an item from a user, group, or delete a private link
990
-	 * @param string $itemType
991
-	 * @param string $itemSource
992
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
993
-	 * @param string $shareWith User or group the item is being shared with
994
-	 * @param string $owner owner of the share, if null the current user is used
995
-	 * @return boolean true on success or false on failure
996
-	 */
997
-	public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
998
-
999
-		// check if it is a valid itemType
1000
-		self::getBackend($itemType);
1001
-
1002
-		$items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
1003
-
1004
-		$toDelete = array();
1005
-		$newParent = null;
1006
-		$currentUser = $owner ? $owner : \OC_User::getUser();
1007
-		foreach ($items as $item) {
1008
-			// delete the item with the expected share_type and owner
1009
-			if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
1010
-				$toDelete = $item;
1011
-				// if there is more then one result we don't have to delete the children
1012
-				// but update their parent. For group shares the new parent should always be
1013
-				// the original group share and not the db entry with the unique name
1014
-			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
1015
-				$newParent = $item['parent'];
1016
-			} else {
1017
-				$newParent = $item['id'];
1018
-			}
1019
-		}
1020
-
1021
-		if (!empty($toDelete)) {
1022
-			self::unshareItem($toDelete, $newParent);
1023
-			return true;
1024
-		}
1025
-		return false;
1026
-	}
1027
-
1028
-	/**
1029
-	 * Unshare an item from all users, groups, and remove all links
1030
-	 * @param string $itemType
1031
-	 * @param string $itemSource
1032
-	 * @return boolean true on success or false on failure
1033
-	 */
1034
-	public static function unshareAll($itemType, $itemSource) {
1035
-		// Get all of the owners of shares of this item.
1036
-		$query = \OC_DB::prepare( 'SELECT `uid_owner` from `*PREFIX*share` WHERE `item_type`=? AND `item_source`=?' );
1037
-		$result = $query->execute(array($itemType, $itemSource));
1038
-		$shares = array();
1039
-		// Add each owner's shares to the array of all shares for this item.
1040
-		while ($row = $result->fetchRow()) {
1041
-			$shares = array_merge($shares, self::getItems($itemType, $itemSource, null, null, $row['uid_owner']));
1042
-		}
1043
-		if (!empty($shares)) {
1044
-			// Pass all the vars we have for now, they may be useful
1045
-			$hookParams = array(
1046
-				'itemType' => $itemType,
1047
-				'itemSource' => $itemSource,
1048
-				'shares' => $shares,
1049
-			);
1050
-			\OC_Hook::emit('OCP\Share', 'pre_unshareAll', $hookParams);
1051
-			foreach ($shares as $share) {
1052
-				self::unshareItem($share);
1053
-			}
1054
-			\OC_Hook::emit('OCP\Share', 'post_unshareAll', $hookParams);
1055
-			return true;
1056
-		}
1057
-		return false;
1058
-	}
1059
-
1060
-	/**
1061
-	 * Unshare an item shared with the current user
1062
-	 * @param string $itemType
1063
-	 * @param string $itemOrigin Item target or source
1064
-	 * @param boolean $originIsSource true if $itemOrigin is the source, false if $itemOrigin is the target (optional)
1065
-	 * @return boolean true on success or false on failure
1066
-	 *
1067
-	 * Unsharing from self is not allowed for items inside collections
1068
-	 */
1069
-	public static function unshareFromSelf($itemType, $itemOrigin, $originIsSource = false) {
1070
-		$originType = ($originIsSource) ? 'source' : 'target';
1071
-		$uid = \OCP\User::getUser();
1072
-
1073
-		if ($itemType === 'file' || $itemType === 'folder') {
1074
-			$statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `file_' . $originType . '` = ?';
1075
-		} else {
1076
-			$statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `item_' . $originType . '` = ?';
1077
-		}
1078
-
1079
-		$query = \OCP\DB::prepare($statement);
1080
-		$result = $query->execute(array($itemType, $itemOrigin));
1081
-
1082
-		$shares = $result->fetchAll();
1083
-
1084
-		$listOfUnsharedItems = array();
1085
-
1086
-		$itemUnshared = false;
1087
-		foreach ($shares as $share) {
1088
-			if ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_USER &&
1089
-				$share['share_with'] === $uid) {
1090
-				$deletedShares = Helper::delete($share['id']);
1091
-				$shareTmp = array(
1092
-					'id' => $share['id'],
1093
-					'shareWith' => $share['share_with'],
1094
-					'itemTarget' => $share['item_target'],
1095
-					'itemType' => $share['item_type'],
1096
-					'shareType' => (int)$share['share_type'],
1097
-				);
1098
-				if (isset($share['file_target'])) {
1099
-					$shareTmp['fileTarget'] = $share['file_target'];
1100
-				}
1101
-				$listOfUnsharedItems = array_merge($listOfUnsharedItems, $deletedShares, array($shareTmp));
1102
-				$itemUnshared = true;
1103
-				break;
1104
-			} elseif ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
1105
-				$group = \OC::$server->getGroupManager()->get($share['share_with']);
1106
-				$user = \OC::$server->getUserManager()->get($uid);
1107
-				if ($group && $user && $group->inGroup($user)) {
1108
-					$groupShare = $share;
1109
-				}
1110
-			} elseif ((int)$share['share_type'] === self::$shareTypeGroupUserUnique &&
1111
-				$share['share_with'] === $uid) {
1112
-				$uniqueGroupShare = $share;
1113
-			}
1114
-		}
1115
-
1116
-		if (!$itemUnshared && isset($groupShare) && !isset($uniqueGroupShare)) {
1117
-			$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share`'
1118
-				.' (`item_type`, `item_source`, `item_target`, `parent`, `share_type`,'
1119
-				.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`)'
1120
-				.' VALUES (?,?,?,?,?,?,?,?,?,?,?)');
1121
-			$query->execute(array($groupShare['item_type'], $groupShare['item_source'], $groupShare['item_target'],
1122
-				$groupShare['id'], self::$shareTypeGroupUserUnique,
1123
-				\OC_User::getUser(), $groupShare['uid_owner'], 0, $groupShare['stime'], $groupShare['file_source'],
1124
-				$groupShare['file_target']));
1125
-			$shareTmp = array(
1126
-				'id' => $groupShare['id'],
1127
-				'shareWith' => $groupShare['share_with'],
1128
-				'itemTarget' => $groupShare['item_target'],
1129
-				'itemType' => $groupShare['item_type'],
1130
-				'shareType' => (int)$groupShare['share_type'],
1131
-			);
1132
-			if (isset($groupShare['file_target'])) {
1133
-				$shareTmp['fileTarget'] = $groupShare['file_target'];
1134
-			}
1135
-			$listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
1136
-			$itemUnshared = true;
1137
-		} elseif (!$itemUnshared && isset($uniqueGroupShare)) {
1138
-			$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
1139
-			$query->execute(array(0, $uniqueGroupShare['id']));
1140
-			$shareTmp = array(
1141
-				'id' => $uniqueGroupShare['id'],
1142
-				'shareWith' => $uniqueGroupShare['share_with'],
1143
-				'itemTarget' => $uniqueGroupShare['item_target'],
1144
-				'itemType' => $uniqueGroupShare['item_type'],
1145
-				'shareType' => (int)$uniqueGroupShare['share_type'],
1146
-			);
1147
-			if (isset($uniqueGroupShare['file_target'])) {
1148
-				$shareTmp['fileTarget'] = $uniqueGroupShare['file_target'];
1149
-			}
1150
-			$listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
1151
-			$itemUnshared = true;
1152
-		}
1153
-
1154
-		if ($itemUnshared) {
1155
-			\OC_Hook::emit('OCP\Share', 'post_unshareFromSelf',
1156
-				array('unsharedItems' => $listOfUnsharedItems, 'itemType' => $itemType));
1157
-		}
1158
-
1159
-		return $itemUnshared;
1160
-	}
1161
-
1162
-	/**
1163
-	 * sent status if users got informed by mail about share
1164
-	 * @param string $itemType
1165
-	 * @param string $itemSource
1166
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1167
-	 * @param string $recipient with whom was the file shared
1168
-	 * @param boolean $status
1169
-	 */
1170
-	public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
1171
-		$status = $status ? 1 : 0;
1172
-
1173
-		$query = \OC_DB::prepare(
1174
-			'UPDATE `*PREFIX*share`
936
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
937
+                $shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
938
+                    $message = 'Sharing %s failed, because this item is already shared with %s';
939
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
940
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
941
+                    throw new \Exception($message_t);
942
+            }
943
+
944
+            // don't allow federated shares if source and target server are the same
945
+            list($user, $remote) = Helper::splitUserRemote($shareWith);
946
+            $currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
947
+            $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
948
+            if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
949
+                $message = 'Not allowed to create a federated share with the same user.';
950
+                $message_t = $l->t('Not allowed to create a federated share with the same user');
951
+                \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
952
+                throw new \Exception($message_t);
953
+            }
954
+
955
+            $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
956
+                \OCP\Security\ISecureRandom::CHAR_DIGITS);
957
+
958
+            $shareWith = $user . '@' . $remote;
959
+            $shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
960
+
961
+            $send = false;
962
+            if ($shareId) {
963
+                $send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
964
+            }
965
+
966
+            if ($send === false) {
967
+                $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
968
+                self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
969
+                $message_t = $l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
970
+                throw new \Exception($message_t);
971
+            }
972
+
973
+            return $send;
974
+        } else {
975
+            // Future share types need to include their own conditions
976
+            $message = 'Share type %s is not valid for %s';
977
+            $message_t = $l->t('Share type %s is not valid for %s', array($shareType, $itemSource));
978
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), \OCP\Util::DEBUG);
979
+            throw new \Exception($message_t);
980
+        }
981
+
982
+        // Put the item into the database
983
+        $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
984
+
985
+        return $result ? true : false;
986
+    }
987
+
988
+    /**
989
+     * Unshare an item from a user, group, or delete a private link
990
+     * @param string $itemType
991
+     * @param string $itemSource
992
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
993
+     * @param string $shareWith User or group the item is being shared with
994
+     * @param string $owner owner of the share, if null the current user is used
995
+     * @return boolean true on success or false on failure
996
+     */
997
+    public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
998
+
999
+        // check if it is a valid itemType
1000
+        self::getBackend($itemType);
1001
+
1002
+        $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
1003
+
1004
+        $toDelete = array();
1005
+        $newParent = null;
1006
+        $currentUser = $owner ? $owner : \OC_User::getUser();
1007
+        foreach ($items as $item) {
1008
+            // delete the item with the expected share_type and owner
1009
+            if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
1010
+                $toDelete = $item;
1011
+                // if there is more then one result we don't have to delete the children
1012
+                // but update their parent. For group shares the new parent should always be
1013
+                // the original group share and not the db entry with the unique name
1014
+            } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
1015
+                $newParent = $item['parent'];
1016
+            } else {
1017
+                $newParent = $item['id'];
1018
+            }
1019
+        }
1020
+
1021
+        if (!empty($toDelete)) {
1022
+            self::unshareItem($toDelete, $newParent);
1023
+            return true;
1024
+        }
1025
+        return false;
1026
+    }
1027
+
1028
+    /**
1029
+     * Unshare an item from all users, groups, and remove all links
1030
+     * @param string $itemType
1031
+     * @param string $itemSource
1032
+     * @return boolean true on success or false on failure
1033
+     */
1034
+    public static function unshareAll($itemType, $itemSource) {
1035
+        // Get all of the owners of shares of this item.
1036
+        $query = \OC_DB::prepare( 'SELECT `uid_owner` from `*PREFIX*share` WHERE `item_type`=? AND `item_source`=?' );
1037
+        $result = $query->execute(array($itemType, $itemSource));
1038
+        $shares = array();
1039
+        // Add each owner's shares to the array of all shares for this item.
1040
+        while ($row = $result->fetchRow()) {
1041
+            $shares = array_merge($shares, self::getItems($itemType, $itemSource, null, null, $row['uid_owner']));
1042
+        }
1043
+        if (!empty($shares)) {
1044
+            // Pass all the vars we have for now, they may be useful
1045
+            $hookParams = array(
1046
+                'itemType' => $itemType,
1047
+                'itemSource' => $itemSource,
1048
+                'shares' => $shares,
1049
+            );
1050
+            \OC_Hook::emit('OCP\Share', 'pre_unshareAll', $hookParams);
1051
+            foreach ($shares as $share) {
1052
+                self::unshareItem($share);
1053
+            }
1054
+            \OC_Hook::emit('OCP\Share', 'post_unshareAll', $hookParams);
1055
+            return true;
1056
+        }
1057
+        return false;
1058
+    }
1059
+
1060
+    /**
1061
+     * Unshare an item shared with the current user
1062
+     * @param string $itemType
1063
+     * @param string $itemOrigin Item target or source
1064
+     * @param boolean $originIsSource true if $itemOrigin is the source, false if $itemOrigin is the target (optional)
1065
+     * @return boolean true on success or false on failure
1066
+     *
1067
+     * Unsharing from self is not allowed for items inside collections
1068
+     */
1069
+    public static function unshareFromSelf($itemType, $itemOrigin, $originIsSource = false) {
1070
+        $originType = ($originIsSource) ? 'source' : 'target';
1071
+        $uid = \OCP\User::getUser();
1072
+
1073
+        if ($itemType === 'file' || $itemType === 'folder') {
1074
+            $statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `file_' . $originType . '` = ?';
1075
+        } else {
1076
+            $statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `item_' . $originType . '` = ?';
1077
+        }
1078
+
1079
+        $query = \OCP\DB::prepare($statement);
1080
+        $result = $query->execute(array($itemType, $itemOrigin));
1081
+
1082
+        $shares = $result->fetchAll();
1083
+
1084
+        $listOfUnsharedItems = array();
1085
+
1086
+        $itemUnshared = false;
1087
+        foreach ($shares as $share) {
1088
+            if ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_USER &&
1089
+                $share['share_with'] === $uid) {
1090
+                $deletedShares = Helper::delete($share['id']);
1091
+                $shareTmp = array(
1092
+                    'id' => $share['id'],
1093
+                    'shareWith' => $share['share_with'],
1094
+                    'itemTarget' => $share['item_target'],
1095
+                    'itemType' => $share['item_type'],
1096
+                    'shareType' => (int)$share['share_type'],
1097
+                );
1098
+                if (isset($share['file_target'])) {
1099
+                    $shareTmp['fileTarget'] = $share['file_target'];
1100
+                }
1101
+                $listOfUnsharedItems = array_merge($listOfUnsharedItems, $deletedShares, array($shareTmp));
1102
+                $itemUnshared = true;
1103
+                break;
1104
+            } elseif ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
1105
+                $group = \OC::$server->getGroupManager()->get($share['share_with']);
1106
+                $user = \OC::$server->getUserManager()->get($uid);
1107
+                if ($group && $user && $group->inGroup($user)) {
1108
+                    $groupShare = $share;
1109
+                }
1110
+            } elseif ((int)$share['share_type'] === self::$shareTypeGroupUserUnique &&
1111
+                $share['share_with'] === $uid) {
1112
+                $uniqueGroupShare = $share;
1113
+            }
1114
+        }
1115
+
1116
+        if (!$itemUnshared && isset($groupShare) && !isset($uniqueGroupShare)) {
1117
+            $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share`'
1118
+                .' (`item_type`, `item_source`, `item_target`, `parent`, `share_type`,'
1119
+                .' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`)'
1120
+                .' VALUES (?,?,?,?,?,?,?,?,?,?,?)');
1121
+            $query->execute(array($groupShare['item_type'], $groupShare['item_source'], $groupShare['item_target'],
1122
+                $groupShare['id'], self::$shareTypeGroupUserUnique,
1123
+                \OC_User::getUser(), $groupShare['uid_owner'], 0, $groupShare['stime'], $groupShare['file_source'],
1124
+                $groupShare['file_target']));
1125
+            $shareTmp = array(
1126
+                'id' => $groupShare['id'],
1127
+                'shareWith' => $groupShare['share_with'],
1128
+                'itemTarget' => $groupShare['item_target'],
1129
+                'itemType' => $groupShare['item_type'],
1130
+                'shareType' => (int)$groupShare['share_type'],
1131
+            );
1132
+            if (isset($groupShare['file_target'])) {
1133
+                $shareTmp['fileTarget'] = $groupShare['file_target'];
1134
+            }
1135
+            $listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
1136
+            $itemUnshared = true;
1137
+        } elseif (!$itemUnshared && isset($uniqueGroupShare)) {
1138
+            $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
1139
+            $query->execute(array(0, $uniqueGroupShare['id']));
1140
+            $shareTmp = array(
1141
+                'id' => $uniqueGroupShare['id'],
1142
+                'shareWith' => $uniqueGroupShare['share_with'],
1143
+                'itemTarget' => $uniqueGroupShare['item_target'],
1144
+                'itemType' => $uniqueGroupShare['item_type'],
1145
+                'shareType' => (int)$uniqueGroupShare['share_type'],
1146
+            );
1147
+            if (isset($uniqueGroupShare['file_target'])) {
1148
+                $shareTmp['fileTarget'] = $uniqueGroupShare['file_target'];
1149
+            }
1150
+            $listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
1151
+            $itemUnshared = true;
1152
+        }
1153
+
1154
+        if ($itemUnshared) {
1155
+            \OC_Hook::emit('OCP\Share', 'post_unshareFromSelf',
1156
+                array('unsharedItems' => $listOfUnsharedItems, 'itemType' => $itemType));
1157
+        }
1158
+
1159
+        return $itemUnshared;
1160
+    }
1161
+
1162
+    /**
1163
+     * sent status if users got informed by mail about share
1164
+     * @param string $itemType
1165
+     * @param string $itemSource
1166
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1167
+     * @param string $recipient with whom was the file shared
1168
+     * @param boolean $status
1169
+     */
1170
+    public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
1171
+        $status = $status ? 1 : 0;
1172
+
1173
+        $query = \OC_DB::prepare(
1174
+            'UPDATE `*PREFIX*share`
1175 1175
 					SET `mail_send` = ?
1176 1176
 					WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
1177 1177
 
1178
-		$result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
1179
-
1180
-		if($result === false) {
1181
-			\OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', \OCP\Util::ERROR);
1182
-		}
1183
-	}
1184
-
1185
-	/**
1186
-	 * Set the permissions of an item for a specific user or group
1187
-	 * @param string $itemType
1188
-	 * @param string $itemSource
1189
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1190
-	 * @param string $shareWith User or group the item is being shared with
1191
-	 * @param int $permissions CRUDS permissions
1192
-	 * @return boolean true on success or false on failure
1193
-	 * @throws \Exception when trying to grant more permissions then the user has himself
1194
-	 */
1195
-	public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
1196
-		$l = \OC::$server->getL10N('lib');
1197
-		$connection = \OC::$server->getDatabaseConnection();
1198
-
1199
-		$intArrayToLiteralArray = function($intArray, $eb) {
1200
-			return array_map(function($int) use ($eb) {
1201
-				return $eb->literal((int)$int, 'integer');
1202
-			}, $intArray);
1203
-		};
1204
-		$sanitizeItem = function($item) {
1205
-			$item['id'] = (int)$item['id'];
1206
-			$item['premissions'] = (int)$item['permissions'];
1207
-			return $item;
1208
-		};
1209
-
1210
-		if ($rootItem = self::getItems($itemType, $itemSource, $shareType, $shareWith,
1211
-			\OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
1212
-			// Check if this item is a reshare and verify that the permissions
1213
-			// granted don't exceed the parent shared item
1214
-			if (isset($rootItem['parent'])) {
1215
-				$qb = $connection->getQueryBuilder();
1216
-				$qb->select('permissions')
1217
-					->from('share')
1218
-					->where($qb->expr()->eq('id', $qb->createParameter('id')))
1219
-					->setParameter(':id', $rootItem['parent']);
1220
-				$dbresult = $qb->execute();
1221
-
1222
-				$result = $dbresult->fetch();
1223
-				$dbresult->closeCursor();
1224
-				if (~(int)$result['permissions'] & $permissions) {
1225
-					$message = 'Setting permissions for %s failed,'
1226
-						.' because the permissions exceed permissions granted to %s';
1227
-					$message_t = $l->t('Setting permissions for %s failed, because the permissions exceed permissions granted to %s', array($itemSource, \OC_User::getUser()));
1228
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, \OC_User::getUser()), \OCP\Util::DEBUG);
1229
-					throw new \Exception($message_t);
1230
-				}
1231
-			}
1232
-			$qb = $connection->getQueryBuilder();
1233
-			$qb->update('share')
1234
-				->set('permissions', $qb->createParameter('permissions'))
1235
-				->where($qb->expr()->eq('id', $qb->createParameter('id')))
1236
-				->setParameter(':id', $rootItem['id'])
1237
-				->setParameter(':permissions', $permissions);
1238
-			$qb->execute();
1239
-			if ($itemType === 'file' || $itemType === 'folder') {
1240
-				\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
1241
-					'itemType' => $itemType,
1242
-					'itemSource' => $itemSource,
1243
-					'shareType' => $shareType,
1244
-					'shareWith' => $shareWith,
1245
-					'uidOwner' => \OC_User::getUser(),
1246
-					'permissions' => $permissions,
1247
-					'path' => $rootItem['path'],
1248
-					'share' => $rootItem
1249
-				));
1250
-			}
1251
-
1252
-			// Share id's to update with the new permissions
1253
-			$ids = [];
1254
-			$items = [];
1255
-
1256
-			// Check if permissions were removed
1257
-			if ((int)$rootItem['permissions'] & ~$permissions) {
1258
-				// If share permission is removed all reshares must be deleted
1259
-				if (($rootItem['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
1260
-					// delete all shares, keep parent and group children
1261
-					Helper::delete($rootItem['id'], true, null, null, true);
1262
-				}
1263
-
1264
-				// Remove permission from all children
1265
-				$parents = [$rootItem['id']];
1266
-				while (!empty($parents)) {
1267
-					$parents = $intArrayToLiteralArray($parents, $qb->expr());
1268
-					$qb = $connection->getQueryBuilder();
1269
-					$qb->select('id', 'permissions', 'item_type')
1270
-						->from('share')
1271
-						->where($qb->expr()->in('parent', $parents));
1272
-					$result = $qb->execute();
1273
-					// Reset parents array, only go through loop again if
1274
-					// items are found that need permissions removed
1275
-					$parents = [];
1276
-					while ($item = $result->fetch()) {
1277
-						$item = $sanitizeItem($item);
1278
-
1279
-						$items[] = $item;
1280
-						// Check if permissions need to be removed
1281
-						if ($item['permissions'] & ~$permissions) {
1282
-							// Add to list of items that need permissions removed
1283
-							$ids[] = $item['id'];
1284
-							$parents[] = $item['id'];
1285
-						}
1286
-					}
1287
-					$result->closeCursor();
1288
-				}
1289
-
1290
-				// Remove the permissions for all reshares of this item
1291
-				if (!empty($ids)) {
1292
-					$ids = "'".implode("','", $ids)."'";
1293
-					// TODO this should be done with Doctrine platform objects
1294
-					if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') {
1295
-						$andOp = 'BITAND(`permissions`, ?)';
1296
-					} else {
1297
-						$andOp = '`permissions` & ?';
1298
-					}
1299
-					$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
1300
-						.' WHERE `id` IN ('.$ids.')');
1301
-					$query->execute(array($permissions));
1302
-				}
1303
-
1304
-			}
1305
-
1306
-			/*
1178
+        $result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
1179
+
1180
+        if($result === false) {
1181
+            \OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', \OCP\Util::ERROR);
1182
+        }
1183
+    }
1184
+
1185
+    /**
1186
+     * Set the permissions of an item for a specific user or group
1187
+     * @param string $itemType
1188
+     * @param string $itemSource
1189
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1190
+     * @param string $shareWith User or group the item is being shared with
1191
+     * @param int $permissions CRUDS permissions
1192
+     * @return boolean true on success or false on failure
1193
+     * @throws \Exception when trying to grant more permissions then the user has himself
1194
+     */
1195
+    public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
1196
+        $l = \OC::$server->getL10N('lib');
1197
+        $connection = \OC::$server->getDatabaseConnection();
1198
+
1199
+        $intArrayToLiteralArray = function($intArray, $eb) {
1200
+            return array_map(function($int) use ($eb) {
1201
+                return $eb->literal((int)$int, 'integer');
1202
+            }, $intArray);
1203
+        };
1204
+        $sanitizeItem = function($item) {
1205
+            $item['id'] = (int)$item['id'];
1206
+            $item['premissions'] = (int)$item['permissions'];
1207
+            return $item;
1208
+        };
1209
+
1210
+        if ($rootItem = self::getItems($itemType, $itemSource, $shareType, $shareWith,
1211
+            \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
1212
+            // Check if this item is a reshare and verify that the permissions
1213
+            // granted don't exceed the parent shared item
1214
+            if (isset($rootItem['parent'])) {
1215
+                $qb = $connection->getQueryBuilder();
1216
+                $qb->select('permissions')
1217
+                    ->from('share')
1218
+                    ->where($qb->expr()->eq('id', $qb->createParameter('id')))
1219
+                    ->setParameter(':id', $rootItem['parent']);
1220
+                $dbresult = $qb->execute();
1221
+
1222
+                $result = $dbresult->fetch();
1223
+                $dbresult->closeCursor();
1224
+                if (~(int)$result['permissions'] & $permissions) {
1225
+                    $message = 'Setting permissions for %s failed,'
1226
+                        .' because the permissions exceed permissions granted to %s';
1227
+                    $message_t = $l->t('Setting permissions for %s failed, because the permissions exceed permissions granted to %s', array($itemSource, \OC_User::getUser()));
1228
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, \OC_User::getUser()), \OCP\Util::DEBUG);
1229
+                    throw new \Exception($message_t);
1230
+                }
1231
+            }
1232
+            $qb = $connection->getQueryBuilder();
1233
+            $qb->update('share')
1234
+                ->set('permissions', $qb->createParameter('permissions'))
1235
+                ->where($qb->expr()->eq('id', $qb->createParameter('id')))
1236
+                ->setParameter(':id', $rootItem['id'])
1237
+                ->setParameter(':permissions', $permissions);
1238
+            $qb->execute();
1239
+            if ($itemType === 'file' || $itemType === 'folder') {
1240
+                \OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
1241
+                    'itemType' => $itemType,
1242
+                    'itemSource' => $itemSource,
1243
+                    'shareType' => $shareType,
1244
+                    'shareWith' => $shareWith,
1245
+                    'uidOwner' => \OC_User::getUser(),
1246
+                    'permissions' => $permissions,
1247
+                    'path' => $rootItem['path'],
1248
+                    'share' => $rootItem
1249
+                ));
1250
+            }
1251
+
1252
+            // Share id's to update with the new permissions
1253
+            $ids = [];
1254
+            $items = [];
1255
+
1256
+            // Check if permissions were removed
1257
+            if ((int)$rootItem['permissions'] & ~$permissions) {
1258
+                // If share permission is removed all reshares must be deleted
1259
+                if (($rootItem['permissions'] & \OCP\Constants::PERMISSION_SHARE) && (~$permissions & \OCP\Constants::PERMISSION_SHARE)) {
1260
+                    // delete all shares, keep parent and group children
1261
+                    Helper::delete($rootItem['id'], true, null, null, true);
1262
+                }
1263
+
1264
+                // Remove permission from all children
1265
+                $parents = [$rootItem['id']];
1266
+                while (!empty($parents)) {
1267
+                    $parents = $intArrayToLiteralArray($parents, $qb->expr());
1268
+                    $qb = $connection->getQueryBuilder();
1269
+                    $qb->select('id', 'permissions', 'item_type')
1270
+                        ->from('share')
1271
+                        ->where($qb->expr()->in('parent', $parents));
1272
+                    $result = $qb->execute();
1273
+                    // Reset parents array, only go through loop again if
1274
+                    // items are found that need permissions removed
1275
+                    $parents = [];
1276
+                    while ($item = $result->fetch()) {
1277
+                        $item = $sanitizeItem($item);
1278
+
1279
+                        $items[] = $item;
1280
+                        // Check if permissions need to be removed
1281
+                        if ($item['permissions'] & ~$permissions) {
1282
+                            // Add to list of items that need permissions removed
1283
+                            $ids[] = $item['id'];
1284
+                            $parents[] = $item['id'];
1285
+                        }
1286
+                    }
1287
+                    $result->closeCursor();
1288
+                }
1289
+
1290
+                // Remove the permissions for all reshares of this item
1291
+                if (!empty($ids)) {
1292
+                    $ids = "'".implode("','", $ids)."'";
1293
+                    // TODO this should be done with Doctrine platform objects
1294
+                    if (\OC::$server->getConfig()->getSystemValue("dbtype") === 'oci') {
1295
+                        $andOp = 'BITAND(`permissions`, ?)';
1296
+                    } else {
1297
+                        $andOp = '`permissions` & ?';
1298
+                    }
1299
+                    $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp
1300
+                        .' WHERE `id` IN ('.$ids.')');
1301
+                    $query->execute(array($permissions));
1302
+                }
1303
+
1304
+            }
1305
+
1306
+            /*
1307 1307
 			 * Permissions were added
1308 1308
 			 * Update all USERGROUP shares. (So group shares where the user moved their mountpoint).
1309 1309
 			 */
1310
-			if ($permissions & ~(int)$rootItem['permissions']) {
1311
-				$qb = $connection->getQueryBuilder();
1312
-				$qb->select('id', 'permissions', 'item_type')
1313
-					->from('share')
1314
-					->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
1315
-					->andWhere($qb->expr()->eq('share_type', $qb->createParameter('share_type')))
1316
-					->andWhere($qb->expr()->neq('permissions', $qb->createParameter('shareDeleted')))
1317
-					->setParameter(':parent', (int)$rootItem['id'])
1318
-					->setParameter(':share_type', 2)
1319
-					->setParameter(':shareDeleted', 0);
1320
-				$result = $qb->execute();
1321
-
1322
-				$ids = [];
1323
-				while ($item = $result->fetch()) {
1324
-					$item = $sanitizeItem($item);
1325
-					$items[] = $item;
1326
-					$ids[] = $item['id'];
1327
-				}
1328
-				$result->closeCursor();
1329
-
1330
-				// Add permssions for all USERGROUP shares of this item
1331
-				if (!empty($ids)) {
1332
-					$ids = $intArrayToLiteralArray($ids, $qb->expr());
1333
-
1334
-					$qb = $connection->getQueryBuilder();
1335
-					$qb->update('share')
1336
-						->set('permissions', $qb->createParameter('permissions'))
1337
-						->where($qb->expr()->in('id', $ids))
1338
-						->setParameter(':permissions', $permissions);
1339
-					$qb->execute();
1340
-				}
1341
-			}
1342
-
1343
-			foreach ($items as $item) {
1344
-				\OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
1345
-			}
1346
-
1347
-			return true;
1348
-		}
1349
-		$message = 'Setting permissions for %s failed, because the item was not found';
1350
-		$message_t = $l->t('Setting permissions for %s failed, because the item was not found', array($itemSource));
1351
-
1352
-		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
1353
-		throw new \Exception($message_t);
1354
-	}
1355
-
1356
-	/**
1357
-	 * validate expiration date if it meets all constraints
1358
-	 *
1359
-	 * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
1360
-	 * @param string $shareTime timestamp when the file was shared
1361
-	 * @param string $itemType
1362
-	 * @param string $itemSource
1363
-	 * @return \DateTime validated date
1364
-	 * @throws \Exception when the expire date is in the past or further in the future then the enforced date
1365
-	 */
1366
-	private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
1367
-		$l = \OC::$server->getL10N('lib');
1368
-		$date = new \DateTime($expireDate);
1369
-		$today = new \DateTime('now');
1370
-
1371
-		// if the user doesn't provide a share time we need to get it from the database
1372
-		// fall-back mode to keep API stable, because the $shareTime parameter was added later
1373
-		$defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
1374
-		if ($defaultExpireDateEnforced && $shareTime === null) {
1375
-			$items = self::getItemShared($itemType, $itemSource);
1376
-			$firstItem = reset($items);
1377
-			$shareTime = (int)$firstItem['stime'];
1378
-		}
1379
-
1380
-		if ($defaultExpireDateEnforced) {
1381
-			// initialize max date with share time
1382
-			$maxDate = new \DateTime();
1383
-			$maxDate->setTimestamp($shareTime);
1384
-			$maxDays = \OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
1385
-			$maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
1386
-			if ($date > $maxDate) {
1387
-				$warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
1388
-				$warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
1389
-				\OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
1390
-				throw new \Exception($warning_t);
1391
-			}
1392
-		}
1393
-
1394
-		if ($date < $today) {
1395
-			$message = 'Cannot set expiration date. Expiration date is in the past';
1396
-			$message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
1397
-			\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN);
1398
-			throw new \Exception($message_t);
1399
-		}
1400
-
1401
-		return $date;
1402
-	}
1403
-
1404
-	/**
1405
-	 * Set expiration date for a share
1406
-	 * @param string $itemType
1407
-	 * @param string $itemSource
1408
-	 * @param string $date expiration date
1409
-	 * @param int $shareTime timestamp from when the file was shared
1410
-	 * @return boolean
1411
-	 * @throws \Exception when the expire date is not set, in the past or further in the future then the enforced date
1412
-	 */
1413
-	public static function setExpirationDate($itemType, $itemSource, $date, $shareTime = null) {
1414
-		$user = \OC_User::getUser();
1415
-		$l = \OC::$server->getL10N('lib');
1416
-
1417
-		if ($date == '') {
1418
-			if (\OCP\Util::isDefaultExpireDateEnforced()) {
1419
-				$warning = 'Cannot clear expiration date. Shares are required to have an expiration date.';
1420
-				$warning_t = $l->t('Cannot clear expiration date. Shares are required to have an expiration date.');
1421
-				\OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
1422
-				throw new \Exception($warning_t);
1423
-			} else {
1424
-				$date = null;
1425
-			}
1426
-		} else {
1427
-			$date = self::validateExpireDate($date, $shareTime, $itemType, $itemSource);
1428
-		}
1429
-		$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ?  AND `uid_owner` = ? AND `share_type` = ?');
1430
-		$query->bindValue(1, $date, 'datetime');
1431
-		$query->bindValue(2, $itemType);
1432
-		$query->bindValue(3, $itemSource);
1433
-		$query->bindValue(4, $user);
1434
-		$query->bindValue(5, \OCP\Share::SHARE_TYPE_LINK);
1435
-
1436
-		$query->execute();
1437
-
1438
-		\OC_Hook::emit('OCP\Share', 'post_set_expiration_date', array(
1439
-			'itemType' => $itemType,
1440
-			'itemSource' => $itemSource,
1441
-			'date' => $date,
1442
-			'uidOwner' => $user
1443
-		));
1444
-
1445
-		return true;
1446
-	}
1447
-
1448
-	/**
1449
-	 * Retrieve the owner of a connection
1450
-	 *
1451
-	 * @param IDBConnection $connection
1452
-	 * @param int $shareId
1453
-	 * @throws \Exception
1454
-	 * @return string uid of share owner
1455
-	 */
1456
-	private static function getShareOwner(IDBConnection $connection, $shareId) {
1457
-		$qb = $connection->getQueryBuilder();
1458
-
1459
-		$qb->select('uid_owner')
1460
-			->from('share')
1461
-			->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
1462
-			->setParameter(':shareId', $shareId);
1463
-		$result = $qb->execute();
1464
-		$result = $result->fetch();
1465
-
1466
-		if (empty($result)) {
1467
-			throw new \Exception('Share not found');
1468
-		}
1469
-
1470
-		return $result['uid_owner'];
1471
-	}
1472
-
1473
-	/**
1474
-	 * Set password for a public link share
1475
-	 *
1476
-	 * @param IUserSession $userSession
1477
-	 * @param IDBConnection $connection
1478
-	 * @param IConfig $config
1479
-	 * @param int $shareId
1480
-	 * @param string $password
1481
-	 * @throws \Exception
1482
-	 * @return boolean
1483
-	 */
1484
-	public static function setPassword(IUserSession $userSession,
1485
-	                                   IDBConnection $connection,
1486
-	                                   IConfig $config,
1487
-	                                   $shareId, $password) {
1488
-		$user = $userSession->getUser();
1489
-		if (is_null($user)) {
1490
-			throw new \Exception("User not logged in");
1491
-		}
1492
-
1493
-		$uid = self::getShareOwner($connection, $shareId);
1494
-
1495
-		if ($uid !== $user->getUID()) {
1496
-			throw new \Exception('Cannot update share of a different user');
1497
-		}
1498
-
1499
-		if ($password === '') {
1500
-			$password = null;
1501
-		}
1502
-
1503
-		//If passwords are enforced the password can't be null
1504
-		if (self::enforcePassword($config) && is_null($password)) {
1505
-			throw new \Exception('Cannot remove password');
1506
-		}
1507
-
1508
-		self::verifyPassword($password);
1509
-
1510
-		$qb = $connection->getQueryBuilder();
1511
-		$qb->update('share')
1512
-			->set('share_with', $qb->createParameter('pass'))
1513
-			->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
1514
-			->setParameter(':pass', is_null($password) ? null : \OC::$server->getHasher()->hash($password))
1515
-			->setParameter(':shareId', $shareId);
1516
-
1517
-		$qb->execute();
1518
-
1519
-		return true;
1520
-	}
1521
-
1522
-	/**
1523
-	 * Checks whether a share has expired, calls unshareItem() if yes.
1524
-	 * @param array $item Share data (usually database row)
1525
-	 * @return boolean True if item was expired, false otherwise.
1526
-	 */
1527
-	protected static function expireItem(array $item) {
1528
-
1529
-		$result = false;
1530
-
1531
-		// only use default expiration date for link shares
1532
-		if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
1533
-
1534
-			// calculate expiration date
1535
-			if (!empty($item['expiration'])) {
1536
-				$userDefinedExpire = new \DateTime($item['expiration']);
1537
-				$expires = $userDefinedExpire->getTimestamp();
1538
-			} else {
1539
-				$expires = null;
1540
-			}
1541
-
1542
-
1543
-			// get default expiration settings
1544
-			$defaultSettings = Helper::getDefaultExpireSetting();
1545
-			$expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
1546
-
1547
-
1548
-			if (is_int($expires)) {
1549
-				$now = time();
1550
-				if ($now > $expires) {
1551
-					self::unshareItem($item);
1552
-					$result = true;
1553
-				}
1554
-			}
1555
-		}
1556
-		return $result;
1557
-	}
1558
-
1559
-	/**
1560
-	 * Unshares a share given a share data array
1561
-	 * @param array $item Share data (usually database row)
1562
-	 * @param int $newParent parent ID
1563
-	 * @return null
1564
-	 */
1565
-	protected static function unshareItem(array $item, $newParent = null) {
1566
-
1567
-		$shareType = (int)$item['share_type'];
1568
-		$shareWith = null;
1569
-		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
1570
-			$shareWith = $item['share_with'];
1571
-		}
1572
-
1573
-		// Pass all the vars we have for now, they may be useful
1574
-		$hookParams = array(
1575
-			'id'            => $item['id'],
1576
-			'itemType'      => $item['item_type'],
1577
-			'itemSource'    => $item['item_source'],
1578
-			'shareType'     => $shareType,
1579
-			'shareWith'     => $shareWith,
1580
-			'itemParent'    => $item['parent'],
1581
-			'uidOwner'      => $item['uid_owner'],
1582
-		);
1583
-		if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
1584
-			$hookParams['fileSource'] = $item['file_source'];
1585
-			$hookParams['fileTarget'] = $item['file_target'];
1586
-		}
1587
-
1588
-		\OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
1589
-		$deletedShares = Helper::delete($item['id'], false, null, $newParent);
1590
-		$deletedShares[] = $hookParams;
1591
-		$hookParams['deletedShares'] = $deletedShares;
1592
-		\OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
1593
-		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
1594
-			list(, $remote) = Helper::splitUserRemote($item['share_with']);
1595
-			self::sendRemoteUnshare($remote, $item['id'], $item['token']);
1596
-		}
1597
-	}
1598
-
1599
-	/**
1600
-	 * Get the backend class for the specified item type
1601
-	 * @param string $itemType
1602
-	 * @throws \Exception
1603
-	 * @return \OCP\Share_Backend
1604
-	 */
1605
-	public static function getBackend($itemType) {
1606
-		$l = \OC::$server->getL10N('lib');
1607
-		if (isset(self::$backends[$itemType])) {
1608
-			return self::$backends[$itemType];
1609
-		} else if (isset(self::$backendTypes[$itemType]['class'])) {
1610
-			$class = self::$backendTypes[$itemType]['class'];
1611
-			if (class_exists($class)) {
1612
-				self::$backends[$itemType] = new $class;
1613
-				if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
1614
-					$message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
1615
-					$message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
1616
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
1617
-					throw new \Exception($message_t);
1618
-				}
1619
-				return self::$backends[$itemType];
1620
-			} else {
1621
-				$message = 'Sharing backend %s not found';
1622
-				$message_t = $l->t('Sharing backend %s not found', array($class));
1623
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
1624
-				throw new \Exception($message_t);
1625
-			}
1626
-		}
1627
-		$message = 'Sharing backend for %s not found';
1628
-		$message_t = $l->t('Sharing backend for %s not found', array($itemType));
1629
-		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), \OCP\Util::ERROR);
1630
-		throw new \Exception($message_t);
1631
-	}
1632
-
1633
-	/**
1634
-	 * Check if resharing is allowed
1635
-	 * @return boolean true if allowed or false
1636
-	 *
1637
-	 * Resharing is allowed by default if not configured
1638
-	 */
1639
-	public static function isResharingAllowed() {
1640
-		if (!isset(self::$isResharingAllowed)) {
1641
-			if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
1642
-				self::$isResharingAllowed = true;
1643
-			} else {
1644
-				self::$isResharingAllowed = false;
1645
-			}
1646
-		}
1647
-		return self::$isResharingAllowed;
1648
-	}
1649
-
1650
-	/**
1651
-	 * Get a list of collection item types for the specified item type
1652
-	 * @param string $itemType
1653
-	 * @return array
1654
-	 */
1655
-	private static function getCollectionItemTypes($itemType) {
1656
-		$collectionTypes = array($itemType);
1657
-		foreach (self::$backendTypes as $type => $backend) {
1658
-			if (in_array($backend['collectionOf'], $collectionTypes)) {
1659
-				$collectionTypes[] = $type;
1660
-			}
1661
-		}
1662
-		// TODO Add option for collections to be collection of themselves, only 'folder' does it now...
1663
-		if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
1664
-			unset($collectionTypes[0]);
1665
-		}
1666
-		// Return array if collections were found or the item type is a
1667
-		// collection itself - collections can be inside collections
1668
-		if (count($collectionTypes) > 0) {
1669
-			return $collectionTypes;
1670
-		}
1671
-		return false;
1672
-	}
1673
-
1674
-	/**
1675
-	 * Get the owners of items shared with a user.
1676
-	 *
1677
-	 * @param string $user The user the items are shared with.
1678
-	 * @param string $type The type of the items shared with the user.
1679
-	 * @param boolean $includeCollections Include collection item types (optional)
1680
-	 * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
1681
-	 * @return array
1682
-	 */
1683
-	public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
1684
-		// First, we find out if $type is part of a collection (and if that collection is part of
1685
-		// another one and so on).
1686
-		$collectionTypes = array();
1687
-		if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
1688
-			$collectionTypes[] = $type;
1689
-		}
1690
-
1691
-		// Of these collection types, along with our original $type, we make a
1692
-		// list of the ones for which a sharing backend has been registered.
1693
-		// FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
1694
-		// with its $includeCollections parameter set to true. Unfortunately, this fails currently.
1695
-		$allMaybeSharedItems = array();
1696
-		foreach ($collectionTypes as $collectionType) {
1697
-			if (isset(self::$backends[$collectionType])) {
1698
-				$allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
1699
-					$collectionType,
1700
-					$user,
1701
-					self::FORMAT_NONE
1702
-				);
1703
-			}
1704
-		}
1705
-
1706
-		$owners = array();
1707
-		if ($includeOwner) {
1708
-			$owners[] = $user;
1709
-		}
1710
-
1711
-		// We take a look at all shared items of the given $type (or of the collections it is part of)
1712
-		// and find out their owners. Then, we gather the tags for the original $type from all owners,
1713
-		// and return them as elements of a list that look like "Tag (owner)".
1714
-		foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
1715
-			foreach ($maybeSharedItems as $sharedItem) {
1716
-				if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
1717
-					$owners[] = $sharedItem['uid_owner'];
1718
-				}
1719
-			}
1720
-		}
1721
-
1722
-		return $owners;
1723
-	}
1724
-
1725
-	/**
1726
-	 * Get shared items from the database
1727
-	 * @param string $itemType
1728
-	 * @param string $item Item source or target (optional)
1729
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
1730
-	 * @param string $shareWith User or group the item is being shared with
1731
-	 * @param string $uidOwner User that is the owner of shared items (optional)
1732
-	 * @param int $format Format to convert items to with formatItems() (optional)
1733
-	 * @param mixed $parameters to pass to formatItems() (optional)
1734
-	 * @param int $limit Number of items to return, -1 to return all matches (optional)
1735
-	 * @param boolean $includeCollections Include collection item types (optional)
1736
-	 * @param boolean $itemShareWithBySource (optional)
1737
-	 * @param boolean $checkExpireDate
1738
-	 * @return array
1739
-	 *
1740
-	 * See public functions getItem(s)... for parameter usage
1741
-	 *
1742
-	 */
1743
-	public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
1744
-									$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
1745
-									$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
1746
-		if (!self::isEnabled()) {
1747
-			return array();
1748
-		}
1749
-		$backend = self::getBackend($itemType);
1750
-		$collectionTypes = false;
1751
-		// Get filesystem root to add it to the file target and remove from the
1752
-		// file source, match file_source with the file cache
1753
-		if ($itemType == 'file' || $itemType == 'folder') {
1754
-			if(!is_null($uidOwner)) {
1755
-				$root = \OC\Files\Filesystem::getRoot();
1756
-			} else {
1757
-				$root = '';
1758
-			}
1759
-			$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
1760
-			if (!isset($item)) {
1761
-				$where .= ' AND `file_target` IS NOT NULL ';
1762
-			}
1763
-			$where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1764
-			$fileDependent = true;
1765
-			$queryArgs = array();
1766
-		} else {
1767
-			$fileDependent = false;
1768
-			$root = '';
1769
-			$collectionTypes = self::getCollectionItemTypes($itemType);
1770
-			if ($includeCollections && !isset($item) && $collectionTypes) {
1771
-				// If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1772
-				if (!in_array($itemType, $collectionTypes)) {
1773
-					$itemTypes = array_merge(array($itemType), $collectionTypes);
1774
-				} else {
1775
-					$itemTypes = $collectionTypes;
1776
-				}
1777
-				$placeholders = join(',', array_fill(0, count($itemTypes), '?'));
1778
-				$where = ' WHERE `item_type` IN ('.$placeholders.'))';
1779
-				$queryArgs = $itemTypes;
1780
-			} else {
1781
-				$where = ' WHERE `item_type` = ?';
1782
-				$queryArgs = array($itemType);
1783
-			}
1784
-		}
1785
-		if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1786
-			$where .= ' AND `share_type` != ?';
1787
-			$queryArgs[] = self::SHARE_TYPE_LINK;
1788
-		}
1789
-		if (isset($shareType)) {
1790
-			// Include all user and group items
1791
-			if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1792
-				$where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1793
-				$queryArgs[] = self::SHARE_TYPE_USER;
1794
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
1795
-				$queryArgs[] = $shareWith;
1796
-
1797
-				$user = \OC::$server->getUserManager()->get($shareWith);
1798
-				$groups = [];
1799
-				if ($user) {
1800
-					$groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1801
-				}
1802
-				if (!empty($groups)) {
1803
-					$placeholders = join(',', array_fill(0, count($groups), '?'));
1804
-					$where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1805
-					$queryArgs[] = self::SHARE_TYPE_GROUP;
1806
-					$queryArgs = array_merge($queryArgs, $groups);
1807
-				}
1808
-				$where .= ')';
1809
-				// Don't include own group shares
1810
-				$where .= ' AND `uid_owner` != ?';
1811
-				$queryArgs[] = $shareWith;
1812
-			} else {
1813
-				$where .= ' AND `share_type` = ?';
1814
-				$queryArgs[] = $shareType;
1815
-				if (isset($shareWith)) {
1816
-					$where .= ' AND `share_with` = ?';
1817
-					$queryArgs[] = $shareWith;
1818
-				}
1819
-			}
1820
-		}
1821
-		if (isset($uidOwner)) {
1822
-			$where .= ' AND `uid_owner` = ?';
1823
-			$queryArgs[] = $uidOwner;
1824
-			if (!isset($shareType)) {
1825
-				// Prevent unique user targets for group shares from being selected
1826
-				$where .= ' AND `share_type` != ?';
1827
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
1828
-			}
1829
-			if ($fileDependent) {
1830
-				$column = 'file_source';
1831
-			} else {
1832
-				$column = 'item_source';
1833
-			}
1834
-		} else {
1835
-			if ($fileDependent) {
1836
-				$column = 'file_target';
1837
-			} else {
1838
-				$column = 'item_target';
1839
-			}
1840
-		}
1841
-		if (isset($item)) {
1842
-			$collectionTypes = self::getCollectionItemTypes($itemType);
1843
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1844
-				$where .= ' AND (';
1845
-			} else {
1846
-				$where .= ' AND';
1847
-			}
1848
-			// If looking for own shared items, check item_source else check item_target
1849
-			if (isset($uidOwner) || $itemShareWithBySource) {
1850
-				// If item type is a file, file source needs to be checked in case the item was converted
1851
-				if ($fileDependent) {
1852
-					$where .= ' `file_source` = ?';
1853
-					$column = 'file_source';
1854
-				} else {
1855
-					$where .= ' `item_source` = ?';
1856
-					$column = 'item_source';
1857
-				}
1858
-			} else {
1859
-				if ($fileDependent) {
1860
-					$where .= ' `file_target` = ?';
1861
-					$item = \OC\Files\Filesystem::normalizePath($item);
1862
-				} else {
1863
-					$where .= ' `item_target` = ?';
1864
-				}
1865
-			}
1866
-			$queryArgs[] = $item;
1867
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1868
-				$placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
1869
-				$where .= ' OR `item_type` IN ('.$placeholders.'))';
1870
-				$queryArgs = array_merge($queryArgs, $collectionTypes);
1871
-			}
1872
-		}
1873
-
1874
-		if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1875
-			// Make sure the unique user target is returned if it exists,
1876
-			// unique targets should follow the group share in the database
1877
-			// If the limit is not 1, the filtering can be done later
1878
-			$where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1879
-		} else {
1880
-			$where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1881
-		}
1882
-
1883
-		if ($limit != -1 && !$includeCollections) {
1884
-			// The limit must be at least 3, because filtering needs to be done
1885
-			if ($limit < 3) {
1886
-				$queryLimit = 3;
1887
-			} else {
1888
-				$queryLimit = $limit;
1889
-			}
1890
-		} else {
1891
-			$queryLimit = null;
1892
-		}
1893
-		$select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1894
-		$root = strlen($root);
1895
-		$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1896
-		$result = $query->execute($queryArgs);
1897
-		if ($result === false) {
1898
-			\OCP\Util::writeLog('OCP\Share',
1899
-				\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1900
-				\OCP\Util::ERROR);
1901
-		}
1902
-		$items = array();
1903
-		$targets = array();
1904
-		$switchedItems = array();
1905
-		$mounts = array();
1906
-		while ($row = $result->fetchRow()) {
1907
-			self::transformDBResults($row);
1908
-			// Filter out duplicate group shares for users with unique targets
1909
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1910
-				continue;
1911
-			}
1912
-			if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1913
-				$row['share_type'] = self::SHARE_TYPE_GROUP;
1914
-				$row['unique_name'] = true; // remember that we use a unique name for this user
1915
-				$row['share_with'] = $items[$row['parent']]['share_with'];
1916
-				// if the group share was unshared from the user we keep the permission, otherwise
1917
-				// we take the permission from the parent because this is always the up-to-date
1918
-				// permission for the group share
1919
-				if ($row['permissions'] > 0) {
1920
-					$row['permissions'] = $items[$row['parent']]['permissions'];
1921
-				}
1922
-				// Remove the parent group share
1923
-				unset($items[$row['parent']]);
1924
-				if ($row['permissions'] == 0) {
1925
-					continue;
1926
-				}
1927
-			} else if (!isset($uidOwner)) {
1928
-				// Check if the same target already exists
1929
-				if (isset($targets[$row['id']])) {
1930
-					// Check if the same owner shared with the user twice
1931
-					// through a group and user share - this is allowed
1932
-					$id = $targets[$row['id']];
1933
-					if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1934
-						// Switch to group share type to ensure resharing conditions aren't bypassed
1935
-						if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1936
-							$items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1937
-							$items[$id]['share_with'] = $row['share_with'];
1938
-						}
1939
-						// Switch ids if sharing permission is granted on only
1940
-						// one share to ensure correct parent is used if resharing
1941
-						if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1942
-							&& (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1943
-							$items[$row['id']] = $items[$id];
1944
-							$switchedItems[$id] = $row['id'];
1945
-							unset($items[$id]);
1946
-							$id = $row['id'];
1947
-						}
1948
-						$items[$id]['permissions'] |= (int)$row['permissions'];
1949
-
1950
-					}
1951
-					continue;
1952
-				} elseif (!empty($row['parent'])) {
1953
-					$targets[$row['parent']] = $row['id'];
1954
-				}
1955
-			}
1956
-			// Remove root from file source paths if retrieving own shared items
1957
-			if (isset($uidOwner) && isset($row['path'])) {
1958
-				if (isset($row['parent'])) {
1959
-					$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1960
-					$parentResult = $query->execute(array($row['parent']));
1961
-					if ($result === false) {
1962
-						\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
1963
-							\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1964
-							\OCP\Util::ERROR);
1965
-					} else {
1966
-						$parentRow = $parentResult->fetchRow();
1967
-						$tmpPath = $parentRow['file_target'];
1968
-						// find the right position where the row path continues from the target path
1969
-						$pos = strrpos($row['path'], $parentRow['file_target']);
1970
-						$subPath = substr($row['path'], $pos);
1971
-						$splitPath = explode('/', $subPath);
1972
-						foreach (array_slice($splitPath, 2) as $pathPart) {
1973
-							$tmpPath = $tmpPath . '/' . $pathPart;
1974
-						}
1975
-						$row['path'] = $tmpPath;
1976
-					}
1977
-				} else {
1978
-					if (!isset($mounts[$row['storage']])) {
1979
-						$mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1980
-						if (is_array($mountPoints) && !empty($mountPoints)) {
1981
-							$mounts[$row['storage']] = current($mountPoints);
1982
-						}
1983
-					}
1984
-					if (!empty($mounts[$row['storage']])) {
1985
-						$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1986
-						$relPath = substr($path, $root); // path relative to data/user
1987
-						$row['path'] = rtrim($relPath, '/');
1988
-					}
1989
-				}
1990
-			}
1991
-
1992
-			if($checkExpireDate) {
1993
-				if (self::expireItem($row)) {
1994
-					continue;
1995
-				}
1996
-			}
1997
-			// Check if resharing is allowed, if not remove share permission
1998
-			if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
1999
-				$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
2000
-			}
2001
-			// Add display names to result
2002
-			$row['share_with_displayname'] = $row['share_with'];
2003
-			if ( isset($row['share_with']) && $row['share_with'] != '' &&
2004
-				$row['share_type'] === self::SHARE_TYPE_USER) {
2005
-				$row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']);
2006
-			} else if(isset($row['share_with']) && $row['share_with'] != '' &&
2007
-				$row['share_type'] === self::SHARE_TYPE_REMOTE) {
2008
-				$addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
2009
-				foreach ($addressBookEntries as $entry) {
2010
-					foreach ($entry['CLOUD'] as $cloudID) {
2011
-						if ($cloudID === $row['share_with']) {
2012
-							$row['share_with_displayname'] = $entry['FN'];
2013
-						}
2014
-					}
2015
-				}
2016
-			}
2017
-			if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
2018
-				$row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']);
2019
-			}
2020
-
2021
-			if ($row['permissions'] > 0) {
2022
-				$items[$row['id']] = $row;
2023
-			}
2024
-
2025
-		}
2026
-
2027
-		// group items if we are looking for items shared with the current user
2028
-		if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
2029
-			$items = self::groupItems($items, $itemType);
2030
-		}
2031
-
2032
-		if (!empty($items)) {
2033
-			$collectionItems = array();
2034
-			foreach ($items as &$row) {
2035
-				// Return only the item instead of a 2-dimensional array
2036
-				if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
2037
-					if ($format == self::FORMAT_NONE) {
2038
-						return $row;
2039
-					} else {
2040
-						break;
2041
-					}
2042
-				}
2043
-				// Check if this is a collection of the requested item type
2044
-				if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
2045
-					if (($collectionBackend = self::getBackend($row['item_type']))
2046
-						&& $collectionBackend instanceof \OCP\Share_Backend_Collection) {
2047
-						// Collections can be inside collections, check if the item is a collection
2048
-						if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
2049
-							$collectionItems[] = $row;
2050
-						} else {
2051
-							$collection = array();
2052
-							$collection['item_type'] = $row['item_type'];
2053
-							if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
2054
-								$collection['path'] = basename($row['path']);
2055
-							}
2056
-							$row['collection'] = $collection;
2057
-							// Fetch all of the children sources
2058
-							$children = $collectionBackend->getChildren($row[$column]);
2059
-							foreach ($children as $child) {
2060
-								$childItem = $row;
2061
-								$childItem['item_type'] = $itemType;
2062
-								if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
2063
-									$childItem['item_source'] = $child['source'];
2064
-									$childItem['item_target'] = $child['target'];
2065
-								}
2066
-								if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
2067
-									if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
2068
-										$childItem['file_source'] = $child['source'];
2069
-									} else { // TODO is this really needed if we already know that we use the file backend?
2070
-										$meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
2071
-										$childItem['file_source'] = $meta['fileid'];
2072
-									}
2073
-									$childItem['file_target'] =
2074
-										\OC\Files\Filesystem::normalizePath($child['file_path']);
2075
-								}
2076
-								if (isset($item)) {
2077
-									if ($childItem[$column] == $item) {
2078
-										// Return only the item instead of a 2-dimensional array
2079
-										if ($limit == 1) {
2080
-											if ($format == self::FORMAT_NONE) {
2081
-												return $childItem;
2082
-											} else {
2083
-												// Unset the items array and break out of both loops
2084
-												$items = array();
2085
-												$items[] = $childItem;
2086
-												break 2;
2087
-											}
2088
-										} else {
2089
-											$collectionItems[] = $childItem;
2090
-										}
2091
-									}
2092
-								} else {
2093
-									$collectionItems[] = $childItem;
2094
-								}
2095
-							}
2096
-						}
2097
-					}
2098
-					// Remove collection item
2099
-					$toRemove = $row['id'];
2100
-					if (array_key_exists($toRemove, $switchedItems)) {
2101
-						$toRemove = $switchedItems[$toRemove];
2102
-					}
2103
-					unset($items[$toRemove]);
2104
-				} elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
2105
-					// FIXME: Thats a dirty hack to improve file sharing performance,
2106
-					// see github issue #10588 for more details
2107
-					// Need to find a solution which works for all back-ends
2108
-					$collectionBackend = self::getBackend($row['item_type']);
2109
-					$sharedParents = $collectionBackend->getParents($row['item_source']);
2110
-					foreach ($sharedParents as $parent) {
2111
-						$collectionItems[] = $parent;
2112
-					}
2113
-				}
2114
-			}
2115
-			if (!empty($collectionItems)) {
2116
-				$collectionItems = array_unique($collectionItems, SORT_REGULAR);
2117
-				$items = array_merge($items, $collectionItems);
2118
-			}
2119
-
2120
-			// filter out invalid items, these can appear when subshare entries exist
2121
-			// for a group in which the requested user isn't a member any more
2122
-			$items = array_filter($items, function($item) {
2123
-				return $item['share_type'] !== self::$shareTypeGroupUserUnique;
2124
-			});
2125
-
2126
-			return self::formatResult($items, $column, $backend, $format, $parameters);
2127
-		} elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
2128
-			// FIXME: Thats a dirty hack to improve file sharing performance,
2129
-			// see github issue #10588 for more details
2130
-			// Need to find a solution which works for all back-ends
2131
-			$collectionItems = array();
2132
-			$collectionBackend = self::getBackend('folder');
2133
-			$sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
2134
-			foreach ($sharedParents as $parent) {
2135
-				$collectionItems[] = $parent;
2136
-			}
2137
-			if ($limit === 1) {
2138
-				return reset($collectionItems);
2139
-			}
2140
-			return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
2141
-		}
2142
-
2143
-		return array();
2144
-	}
2145
-
2146
-	/**
2147
-	 * group items with link to the same source
2148
-	 *
2149
-	 * @param array $items
2150
-	 * @param string $itemType
2151
-	 * @return array of grouped items
2152
-	 */
2153
-	protected static function groupItems($items, $itemType) {
2154
-
2155
-		$fileSharing = ($itemType === 'file' || $itemType === 'folder') ? true : false;
2156
-
2157
-		$result = array();
2158
-
2159
-		foreach ($items as $item) {
2160
-			$grouped = false;
2161
-			foreach ($result as $key => $r) {
2162
-				// for file/folder shares we need to compare file_source, otherwise we compare item_source
2163
-				// only group shares if they already point to the same target, otherwise the file where shared
2164
-				// before grouping of shares was added. In this case we don't group them toi avoid confusions
2165
-				if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
2166
-					(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
2167
-					// add the first item to the list of grouped shares
2168
-					if (!isset($result[$key]['grouped'])) {
2169
-						$result[$key]['grouped'][] = $result[$key];
2170
-					}
2171
-					$result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
2172
-					$result[$key]['grouped'][] = $item;
2173
-					$grouped = true;
2174
-					break;
2175
-				}
2176
-			}
2177
-
2178
-			if (!$grouped) {
2179
-				$result[] = $item;
2180
-			}
2181
-
2182
-		}
2183
-
2184
-		return $result;
2185
-	}
2186
-
2187
-	/**
2188
-	 * Put shared item into the database
2189
-	 * @param string $itemType Item type
2190
-	 * @param string $itemSource Item source
2191
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
2192
-	 * @param string $shareWith User or group the item is being shared with
2193
-	 * @param string $uidOwner User that is the owner of shared item
2194
-	 * @param int $permissions CRUDS permissions
2195
-	 * @param boolean|array $parentFolder Parent folder target (optional)
2196
-	 * @param string $token (optional)
2197
-	 * @param string $itemSourceName name of the source item (optional)
2198
-	 * @param \DateTime $expirationDate (optional)
2199
-	 * @throws \Exception
2200
-	 * @return mixed id of the new share or false
2201
-	 */
2202
-	private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
2203
-								$permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
2204
-
2205
-		$queriesToExecute = array();
2206
-		$suggestedItemTarget = null;
2207
-		$groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
2208
-		$groupItemTarget = $itemTarget = $fileSource = $parent = 0;
2209
-
2210
-		$result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
2211
-		if(!empty($result)) {
2212
-			$parent = $result['parent'];
2213
-			$itemSource = $result['itemSource'];
2214
-			$fileSource = $result['fileSource'];
2215
-			$suggestedItemTarget = $result['suggestedItemTarget'];
2216
-			$suggestedFileTarget = $result['suggestedFileTarget'];
2217
-			$filePath = $result['filePath'];
2218
-		}
2219
-
2220
-		$isGroupShare = false;
2221
-		if ($shareType == self::SHARE_TYPE_GROUP) {
2222
-			$isGroupShare = true;
2223
-			if (isset($shareWith['users'])) {
2224
-				$users = $shareWith['users'];
2225
-			} else {
2226
-				$group = \OC::$server->getGroupManager()->get($shareWith['group']);
2227
-				if ($group) {
2228
-					$users = $group->searchUsers('', -1, 0);
2229
-					$userIds = [];
2230
-					foreach ($users as $user) {
2231
-						$userIds[] = $user->getUID();
2232
-					}
2233
-					$users = $userIds;
2234
-				} else {
2235
-					$users = [];
2236
-				}
2237
-			}
2238
-			// remove current user from list
2239
-			if (in_array(\OCP\User::getUser(), $users)) {
2240
-				unset($users[array_search(\OCP\User::getUser(), $users)]);
2241
-			}
2242
-			$groupItemTarget = Helper::generateTarget($itemType, $itemSource,
2243
-				$shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
2244
-			$groupFileTarget = Helper::generateTarget($itemType, $itemSource,
2245
-				$shareType, $shareWith['group'], $uidOwner, $filePath);
2246
-
2247
-			// add group share to table and remember the id as parent
2248
-			$queriesToExecute['groupShare'] = array(
2249
-				'itemType'			=> $itemType,
2250
-				'itemSource'		=> $itemSource,
2251
-				'itemTarget'		=> $groupItemTarget,
2252
-				'shareType'			=> $shareType,
2253
-				'shareWith'			=> $shareWith['group'],
2254
-				'uidOwner'			=> $uidOwner,
2255
-				'permissions'		=> $permissions,
2256
-				'shareTime'			=> time(),
2257
-				'fileSource'		=> $fileSource,
2258
-				'fileTarget'		=> $groupFileTarget,
2259
-				'token'				=> $token,
2260
-				'parent'			=> $parent,
2261
-				'expiration'		=> $expirationDate,
2262
-			);
2263
-
2264
-		} else {
2265
-			$users = array($shareWith);
2266
-			$itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
2267
-				$suggestedItemTarget);
2268
-		}
2269
-
2270
-		$run = true;
2271
-		$error = '';
2272
-		$preHookData = array(
2273
-			'itemType' => $itemType,
2274
-			'itemSource' => $itemSource,
2275
-			'shareType' => $shareType,
2276
-			'uidOwner' => $uidOwner,
2277
-			'permissions' => $permissions,
2278
-			'fileSource' => $fileSource,
2279
-			'expiration' => $expirationDate,
2280
-			'token' => $token,
2281
-			'run' => &$run,
2282
-			'error' => &$error
2283
-		);
2284
-
2285
-		$preHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
2286
-		$preHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
2287
-
2288
-		\OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
2289
-
2290
-		if ($run === false) {
2291
-			throw new \Exception($error);
2292
-		}
2293
-
2294
-		foreach ($users as $user) {
2295
-			$sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
2296
-			$sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
2297
-
2298
-			$userShareType = ($isGroupShare) ? self::$shareTypeGroupUserUnique : $shareType;
2299
-
2300
-			if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
2301
-				$fileTarget = $sourceExists['file_target'];
2302
-				$itemTarget = $sourceExists['item_target'];
2303
-
2304
-				// for group shares we don't need a additional entry if the target is the same
2305
-				if($isGroupShare && $groupItemTarget === $itemTarget) {
2306
-					continue;
2307
-				}
2308
-
2309
-			} elseif(!$sourceExists && !$isGroupShare)  {
2310
-
2311
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
2312
-					$uidOwner, $suggestedItemTarget, $parent);
2313
-				if (isset($fileSource)) {
2314
-					if ($parentFolder) {
2315
-						if ($parentFolder === true) {
2316
-							$fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
2317
-								$uidOwner, $suggestedFileTarget, $parent);
2318
-							if ($fileTarget != $groupFileTarget) {
2319
-								$parentFolders[$user]['folder'] = $fileTarget;
2320
-							}
2321
-						} else if (isset($parentFolder[$user])) {
2322
-							$fileTarget = $parentFolder[$user]['folder'].$itemSource;
2323
-							$parent = $parentFolder[$user]['id'];
2324
-						}
2325
-					} else {
2326
-						$fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
2327
-							$user, $uidOwner, $suggestedFileTarget, $parent);
2328
-					}
2329
-				} else {
2330
-					$fileTarget = null;
2331
-				}
2332
-
2333
-			} else {
2334
-
2335
-				// group share which doesn't exists until now, check if we need a unique target for this user
2336
-
2337
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
2338
-					$uidOwner, $suggestedItemTarget, $parent);
2339
-
2340
-				// do we also need a file target
2341
-				if (isset($fileSource)) {
2342
-					$fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
2343
-						$uidOwner, $suggestedFileTarget, $parent);
2344
-				} else {
2345
-					$fileTarget = null;
2346
-				}
2347
-
2348
-				if (($itemTarget === $groupItemTarget) &&
2349
-					(!isset($fileSource) || $fileTarget === $groupFileTarget)) {
2350
-					continue;
2351
-				}
2352
-			}
2353
-
2354
-			$queriesToExecute[] = array(
2355
-				'itemType'			=> $itemType,
2356
-				'itemSource'		=> $itemSource,
2357
-				'itemTarget'		=> $itemTarget,
2358
-				'shareType'			=> $userShareType,
2359
-				'shareWith'			=> $user,
2360
-				'uidOwner'			=> $uidOwner,
2361
-				'permissions'		=> $permissions,
2362
-				'shareTime'			=> time(),
2363
-				'fileSource'		=> $fileSource,
2364
-				'fileTarget'		=> $fileTarget,
2365
-				'token'				=> $token,
2366
-				'parent'			=> $parent,
2367
-				'expiration'		=> $expirationDate,
2368
-			);
2369
-
2370
-		}
2371
-
2372
-		$id = false;
2373
-		if ($isGroupShare) {
2374
-			$id = self::insertShare($queriesToExecute['groupShare']);
2375
-			// Save this id, any extra rows for this group share will need to reference it
2376
-			$parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
2377
-			unset($queriesToExecute['groupShare']);
2378
-		}
2379
-
2380
-		foreach ($queriesToExecute as $shareQuery) {
2381
-			$shareQuery['parent'] = $parent;
2382
-			$id = self::insertShare($shareQuery);
2383
-		}
2384
-
2385
-		$postHookData = array(
2386
-			'itemType' => $itemType,
2387
-			'itemSource' => $itemSource,
2388
-			'parent' => $parent,
2389
-			'shareType' => $shareType,
2390
-			'uidOwner' => $uidOwner,
2391
-			'permissions' => $permissions,
2392
-			'fileSource' => $fileSource,
2393
-			'id' => $parent,
2394
-			'token' => $token,
2395
-			'expirationDate' => $expirationDate,
2396
-		);
2397
-
2398
-		$postHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
2399
-		$postHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
2400
-		$postHookData['fileTarget'] = ($isGroupShare) ? $groupFileTarget : $fileTarget;
2401
-
2402
-		\OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
2403
-
2404
-
2405
-		return $id ? $id : false;
2406
-	}
2407
-
2408
-	/**
2409
-	 * @param string $itemType
2410
-	 * @param string $itemSource
2411
-	 * @param int $shareType
2412
-	 * @param string $shareWith
2413
-	 * @param string $uidOwner
2414
-	 * @param int $permissions
2415
-	 * @param string|null $itemSourceName
2416
-	 * @param null|\DateTime $expirationDate
2417
-	 */
2418
-	private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
2419
-		$backend = self::getBackend($itemType);
2420
-
2421
-		$l = \OC::$server->getL10N('lib');
2422
-		$result = array();
2423
-
2424
-		$column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
2425
-
2426
-		$checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
2427
-		if ($checkReshare) {
2428
-			// Check if attempting to share back to owner
2429
-			if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
2430
-				$message = 'Sharing %s failed, because the user %s is the original sharer';
2431
-				$message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
2432
-
2433
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
2434
-				throw new \Exception($message_t);
2435
-			}
2436
-		}
2437
-
2438
-		if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
2439
-			// Check if share permissions is granted
2440
-			if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
2441
-				if (~(int)$checkReshare['permissions'] & $permissions) {
2442
-					$message = 'Sharing %s failed, because the permissions exceed permissions granted to %s';
2443
-					$message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner));
2444
-
2445
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), \OCP\Util::DEBUG);
2446
-					throw new \Exception($message_t);
2447
-				} else {
2448
-					// TODO Don't check if inside folder
2449
-					$result['parent'] = $checkReshare['id'];
2450
-
2451
-					$result['expirationDate'] = $expirationDate;
2452
-					// $checkReshare['expiration'] could be null and then is always less than any value
2453
-					if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
2454
-						$result['expirationDate'] = $checkReshare['expiration'];
2455
-					}
2456
-
2457
-					// only suggest the same name as new target if it is a reshare of the
2458
-					// same file/folder and not the reshare of a child
2459
-					if ($checkReshare[$column] === $itemSource) {
2460
-						$result['filePath'] = $checkReshare['file_target'];
2461
-						$result['itemSource'] = $checkReshare['item_source'];
2462
-						$result['fileSource'] = $checkReshare['file_source'];
2463
-						$result['suggestedItemTarget'] = $checkReshare['item_target'];
2464
-						$result['suggestedFileTarget'] = $checkReshare['file_target'];
2465
-					} else {
2466
-						$result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
2467
-						$result['suggestedItemTarget'] = null;
2468
-						$result['suggestedFileTarget'] = null;
2469
-						$result['itemSource'] = $itemSource;
2470
-						$result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
2471
-					}
2472
-				}
2473
-			} else {
2474
-				$message = 'Sharing %s failed, because resharing is not allowed';
2475
-				$message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
2476
-
2477
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
2478
-				throw new \Exception($message_t);
2479
-			}
2480
-		} else {
2481
-			$result['parent'] = null;
2482
-			$result['suggestedItemTarget'] = null;
2483
-			$result['suggestedFileTarget'] = null;
2484
-			$result['itemSource'] = $itemSource;
2485
-			$result['expirationDate'] = $expirationDate;
2486
-			if (!$backend->isValidSource($itemSource, $uidOwner)) {
2487
-				$message = 'Sharing %s failed, because the sharing backend for '
2488
-					.'%s could not find its source';
2489
-				$message_t = $l->t('Sharing %s failed, because the sharing backend for %s could not find its source', array($itemSource, $itemType));
2490
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), \OCP\Util::DEBUG);
2491
-				throw new \Exception($message_t);
2492
-			}
2493
-			if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
2494
-				$result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
2495
-				if ($itemType == 'file' || $itemType == 'folder') {
2496
-					$result['fileSource'] = $itemSource;
2497
-				} else {
2498
-					$meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
2499
-					$result['fileSource'] = $meta['fileid'];
2500
-				}
2501
-				if ($result['fileSource'] == -1) {
2502
-					$message = 'Sharing %s failed, because the file could not be found in the file cache';
2503
-					$message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
2504
-
2505
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
2506
-					throw new \Exception($message_t);
2507
-				}
2508
-			} else {
2509
-				$result['filePath'] = null;
2510
-				$result['fileSource'] = null;
2511
-			}
2512
-		}
2513
-
2514
-		return $result;
2515
-	}
2516
-
2517
-	/**
2518
-	 *
2519
-	 * @param array $shareData
2520
-	 * @return mixed false in case of a failure or the id of the new share
2521
-	 */
2522
-	private static function insertShare(array $shareData) {
2523
-
2524
-		$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
2525
-			.' `item_type`, `item_source`, `item_target`, `share_type`,'
2526
-			.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
2527
-			.' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
2528
-		$query->bindValue(1, $shareData['itemType']);
2529
-		$query->bindValue(2, $shareData['itemSource']);
2530
-		$query->bindValue(3, $shareData['itemTarget']);
2531
-		$query->bindValue(4, $shareData['shareType']);
2532
-		$query->bindValue(5, $shareData['shareWith']);
2533
-		$query->bindValue(6, $shareData['uidOwner']);
2534
-		$query->bindValue(7, $shareData['permissions']);
2535
-		$query->bindValue(8, $shareData['shareTime']);
2536
-		$query->bindValue(9, $shareData['fileSource']);
2537
-		$query->bindValue(10, $shareData['fileTarget']);
2538
-		$query->bindValue(11, $shareData['token']);
2539
-		$query->bindValue(12, $shareData['parent']);
2540
-		$query->bindValue(13, $shareData['expiration'], 'datetime');
2541
-		$result = $query->execute();
2542
-
2543
-		$id = false;
2544
-		if ($result) {
2545
-			$id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
2546
-		}
2547
-
2548
-		return $id;
2549
-
2550
-	}
2551
-
2552
-	/**
2553
-	 * Delete all shares with type SHARE_TYPE_LINK
2554
-	 */
2555
-	public static function removeAllLinkShares() {
2556
-		// Delete any link shares
2557
-		$query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ?');
2558
-		$result = $query->execute(array(self::SHARE_TYPE_LINK));
2559
-		while ($item = $result->fetchRow()) {
2560
-			Helper::delete($item['id']);
2561
-		}
2562
-	}
2563
-
2564
-	/**
2565
-	 * In case a password protected link is not yet authenticated this function will return false
2566
-	 *
2567
-	 * @param array $linkItem
2568
-	 * @return boolean
2569
-	 */
2570
-	public static function checkPasswordProtectedShare(array $linkItem) {
2571
-		if (!isset($linkItem['share_with'])) {
2572
-			return true;
2573
-		}
2574
-		if (!isset($linkItem['share_type'])) {
2575
-			return true;
2576
-		}
2577
-		if (!isset($linkItem['id'])) {
2578
-			return true;
2579
-		}
2580
-
2581
-		if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
2582
-			return true;
2583
-		}
2584
-
2585
-		if ( \OC::$server->getSession()->exists('public_link_authenticated')
2586
-			&& \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
2587
-			return true;
2588
-		}
2589
-
2590
-		return false;
2591
-	}
2592
-
2593
-	/**
2594
-	 * construct select statement
2595
-	 * @param int $format
2596
-	 * @param boolean $fileDependent ist it a file/folder share or a generla share
2597
-	 * @param string $uidOwner
2598
-	 * @return string select statement
2599
-	 */
2600
-	private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
2601
-		$select = '*';
2602
-		if ($format == self::FORMAT_STATUSES) {
2603
-			if ($fileDependent) {
2604
-				$select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
2605
-					. '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
2606
-					. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
2607
-					. '`uid_initiator`';
2608
-			} else {
2609
-				$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
2610
-			}
2611
-		} else {
2612
-			if (isset($uidOwner)) {
2613
-				if ($fileDependent) {
2614
-					$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
2615
-						. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
2616
-						. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
2617
-						. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
2618
-				} else {
2619
-					$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
2620
-						. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
2621
-				}
2622
-			} else {
2623
-				if ($fileDependent) {
2624
-					if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
2625
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
2626
-							. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
2627
-							. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
2628
-							. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
2629
-					} else {
2630
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
2631
-							. '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
2632
-							. '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
2633
-						    . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
2634
-							. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
2635
-					}
2636
-				}
2637
-			}
2638
-		}
2639
-		return $select;
2640
-	}
2641
-
2642
-
2643
-	/**
2644
-	 * transform db results
2645
-	 * @param array $row result
2646
-	 */
2647
-	private static function transformDBResults(&$row) {
2648
-		if (isset($row['id'])) {
2649
-			$row['id'] = (int) $row['id'];
2650
-		}
2651
-		if (isset($row['share_type'])) {
2652
-			$row['share_type'] = (int) $row['share_type'];
2653
-		}
2654
-		if (isset($row['parent'])) {
2655
-			$row['parent'] = (int) $row['parent'];
2656
-		}
2657
-		if (isset($row['file_parent'])) {
2658
-			$row['file_parent'] = (int) $row['file_parent'];
2659
-		}
2660
-		if (isset($row['file_source'])) {
2661
-			$row['file_source'] = (int) $row['file_source'];
2662
-		}
2663
-		if (isset($row['permissions'])) {
2664
-			$row['permissions'] = (int) $row['permissions'];
2665
-		}
2666
-		if (isset($row['storage'])) {
2667
-			$row['storage'] = (int) $row['storage'];
2668
-		}
2669
-		if (isset($row['stime'])) {
2670
-			$row['stime'] = (int) $row['stime'];
2671
-		}
2672
-		if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
2673
-			// discard expiration date for non-link shares, which might have been
2674
-			// set by ancient bugs
2675
-			$row['expiration'] = null;
2676
-		}
2677
-	}
2678
-
2679
-	/**
2680
-	 * format result
2681
-	 * @param array $items result
2682
-	 * @param string $column is it a file share or a general share ('file_target' or 'item_target')
2683
-	 * @param \OCP\Share_Backend $backend sharing backend
2684
-	 * @param int $format
2685
-	 * @param array $parameters additional format parameters
2686
-	 * @return array format result
2687
-	 */
2688
-	private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
2689
-		if ($format === self::FORMAT_NONE) {
2690
-			return $items;
2691
-		} else if ($format === self::FORMAT_STATUSES) {
2692
-			$statuses = array();
2693
-			foreach ($items as $item) {
2694
-				if ($item['share_type'] === self::SHARE_TYPE_LINK) {
2695
-					if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
2696
-						continue;
2697
-					}
2698
-					$statuses[$item[$column]]['link'] = true;
2699
-				} else if (!isset($statuses[$item[$column]])) {
2700
-					$statuses[$item[$column]]['link'] = false;
2701
-				}
2702
-				if (!empty($item['file_target'])) {
2703
-					$statuses[$item[$column]]['path'] = $item['path'];
2704
-				}
2705
-			}
2706
-			return $statuses;
2707
-		} else {
2708
-			return $backend->formatItems($items, $format, $parameters);
2709
-		}
2710
-	}
2711
-
2712
-	/**
2713
-	 * remove protocol from URL
2714
-	 *
2715
-	 * @param string $url
2716
-	 * @return string
2717
-	 */
2718
-	public static function removeProtocolFromUrl($url) {
2719
-		if (strpos($url, 'https://') === 0) {
2720
-			return substr($url, strlen('https://'));
2721
-		} else if (strpos($url, 'http://') === 0) {
2722
-			return substr($url, strlen('http://'));
2723
-		}
2724
-
2725
-		return $url;
2726
-	}
2727
-
2728
-	/**
2729
-	 * try http post first with https and then with http as a fallback
2730
-	 *
2731
-	 * @param string $remoteDomain
2732
-	 * @param string $urlSuffix
2733
-	 * @param array $fields post parameters
2734
-	 * @return array
2735
-	 */
2736
-	private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
2737
-		$protocol = 'https://';
2738
-		$result = [
2739
-			'success' => false,
2740
-			'result' => '',
2741
-		];
2742
-		$try = 0;
2743
-		$discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
2744
-		while ($result['success'] === false && $try < 2) {
2745
-			$federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
2746
-			$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
2747
-			$result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields);
2748
-			$try++;
2749
-			$protocol = 'http://';
2750
-		}
2751
-
2752
-		return $result;
2753
-	}
2754
-
2755
-	/**
2756
-	 * send server-to-server share to remote server
2757
-	 *
2758
-	 * @param string $token
2759
-	 * @param string $shareWith
2760
-	 * @param string $name
2761
-	 * @param int $remote_id
2762
-	 * @param string $owner
2763
-	 * @return bool
2764
-	 */
2765
-	private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2766
-
2767
-		list($user, $remote) = Helper::splitUserRemote($shareWith);
2768
-
2769
-		if ($user && $remote) {
2770
-			$url = $remote;
2771
-
2772
-			$local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2773
-
2774
-			$fields = array(
2775
-				'shareWith' => $user,
2776
-				'token' => $token,
2777
-				'name' => $name,
2778
-				'remoteId' => $remote_id,
2779
-				'owner' => $owner,
2780
-				'remote' => $local,
2781
-			);
2782
-
2783
-			$url = self::removeProtocolFromUrl($url);
2784
-			$result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2785
-			$status = json_decode($result['result'], true);
2786
-
2787
-			if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2788
-				\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
2789
-				return true;
2790
-			}
2791
-
2792
-		}
2793
-
2794
-		return false;
2795
-	}
2796
-
2797
-	/**
2798
-	 * send server-to-server unshare to remote server
2799
-	 *
2800
-	 * @param string $remote url
2801
-	 * @param int $id share id
2802
-	 * @param string $token
2803
-	 * @return bool
2804
-	 */
2805
-	private static function sendRemoteUnshare($remote, $id, $token) {
2806
-		$url = rtrim($remote, '/');
2807
-		$fields = array('token' => $token, 'format' => 'json');
2808
-		$url = self::removeProtocolFromUrl($url);
2809
-		$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2810
-		$status = json_decode($result['result'], true);
2811
-
2812
-		return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2813
-	}
2814
-
2815
-	/**
2816
-	 * check if user can only share with group members
2817
-	 * @return bool
2818
-	 */
2819
-	public static function shareWithGroupMembersOnly() {
2820
-		$value = \OC::$server->getAppConfig()->getValue('core', 'shareapi_only_share_with_group_members', 'no');
2821
-		return ($value === 'yes') ? true : false;
2822
-	}
2823
-
2824
-	/**
2825
-	 * @return bool
2826
-	 */
2827
-	public static function isDefaultExpireDateEnabled() {
2828
-		$defaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
2829
-		return ($defaultExpireDateEnabled === "yes") ? true : false;
2830
-	}
2831
-
2832
-	/**
2833
-	 * @return bool
2834
-	 */
2835
-	public static function enforceDefaultExpireDate() {
2836
-		$enforceDefaultExpireDate = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
2837
-		return ($enforceDefaultExpireDate === "yes") ? true : false;
2838
-	}
2839
-
2840
-	/**
2841
-	 * @return int
2842
-	 */
2843
-	public static function getExpireInterval() {
2844
-		return (int)\OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
2845
-	}
2846
-
2847
-	/**
2848
-	 * Checks whether the given path is reachable for the given owner
2849
-	 *
2850
-	 * @param string $path path relative to files
2851
-	 * @param string $ownerStorageId storage id of the owner
2852
-	 *
2853
-	 * @return boolean true if file is reachable, false otherwise
2854
-	 */
2855
-	private static function isFileReachable($path, $ownerStorageId) {
2856
-		// if outside the home storage, file is always considered reachable
2857
-		if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2858
-			substr($ownerStorageId, 0, 13) === 'object::user:'
2859
-		)) {
2860
-			return true;
2861
-		}
2862
-
2863
-		// if inside the home storage, the file has to be under "/files/"
2864
-		$path = ltrim($path, '/');
2865
-		if (substr($path, 0, 6) === 'files/') {
2866
-			return true;
2867
-		}
2868
-
2869
-		return false;
2870
-	}
2871
-
2872
-	/**
2873
-	 * @param IConfig $config
2874
-	 * @return bool
2875
-	 */
2876
-	public static function enforcePassword(IConfig $config) {
2877
-		$enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
2878
-		return ($enforcePassword === "yes") ? true : false;
2879
-	}
2880
-
2881
-	/**
2882
-	 * Get all share entries, including non-unique group items
2883
-	 *
2884
-	 * @param string $owner
2885
-	 * @return array
2886
-	 */
2887
-	public static function getAllSharesForOwner($owner) {
2888
-		$query = 'SELECT * FROM `*PREFIX*share` WHERE `uid_owner` = ?';
2889
-		$result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$owner]);
2890
-		return $result->fetchAll();
2891
-	}
2892
-
2893
-	/**
2894
-	 * Get all share entries, including non-unique group items for a file
2895
-	 *
2896
-	 * @param int $id
2897
-	 * @return array
2898
-	 */
2899
-	public static function getAllSharesForFileId($id) {
2900
-		$query = 'SELECT * FROM `*PREFIX*share` WHERE `file_source` = ?';
2901
-		$result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$id]);
2902
-		return $result->fetchAll();
2903
-	}
2904
-
2905
-	/**
2906
-	 * @param string $password
2907
-	 * @throws \Exception
2908
-	 */
2909
-	private static function verifyPassword($password) {
2910
-
2911
-		$accepted = true;
2912
-		$message = '';
2913
-		\OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2914
-			'password' => $password,
2915
-			'accepted' => &$accepted,
2916
-			'message' => &$message
2917
-		]);
2918
-
2919
-		if (!$accepted) {
2920
-			throw new \Exception($message);
2921
-		}
2922
-	}
1310
+            if ($permissions & ~(int)$rootItem['permissions']) {
1311
+                $qb = $connection->getQueryBuilder();
1312
+                $qb->select('id', 'permissions', 'item_type')
1313
+                    ->from('share')
1314
+                    ->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
1315
+                    ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('share_type')))
1316
+                    ->andWhere($qb->expr()->neq('permissions', $qb->createParameter('shareDeleted')))
1317
+                    ->setParameter(':parent', (int)$rootItem['id'])
1318
+                    ->setParameter(':share_type', 2)
1319
+                    ->setParameter(':shareDeleted', 0);
1320
+                $result = $qb->execute();
1321
+
1322
+                $ids = [];
1323
+                while ($item = $result->fetch()) {
1324
+                    $item = $sanitizeItem($item);
1325
+                    $items[] = $item;
1326
+                    $ids[] = $item['id'];
1327
+                }
1328
+                $result->closeCursor();
1329
+
1330
+                // Add permssions for all USERGROUP shares of this item
1331
+                if (!empty($ids)) {
1332
+                    $ids = $intArrayToLiteralArray($ids, $qb->expr());
1333
+
1334
+                    $qb = $connection->getQueryBuilder();
1335
+                    $qb->update('share')
1336
+                        ->set('permissions', $qb->createParameter('permissions'))
1337
+                        ->where($qb->expr()->in('id', $ids))
1338
+                        ->setParameter(':permissions', $permissions);
1339
+                    $qb->execute();
1340
+                }
1341
+            }
1342
+
1343
+            foreach ($items as $item) {
1344
+                \OC_Hook::emit('OCP\Share', 'post_update_permissions', ['share' => $item]);
1345
+            }
1346
+
1347
+            return true;
1348
+        }
1349
+        $message = 'Setting permissions for %s failed, because the item was not found';
1350
+        $message_t = $l->t('Setting permissions for %s failed, because the item was not found', array($itemSource));
1351
+
1352
+        \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
1353
+        throw new \Exception($message_t);
1354
+    }
1355
+
1356
+    /**
1357
+     * validate expiration date if it meets all constraints
1358
+     *
1359
+     * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
1360
+     * @param string $shareTime timestamp when the file was shared
1361
+     * @param string $itemType
1362
+     * @param string $itemSource
1363
+     * @return \DateTime validated date
1364
+     * @throws \Exception when the expire date is in the past or further in the future then the enforced date
1365
+     */
1366
+    private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
1367
+        $l = \OC::$server->getL10N('lib');
1368
+        $date = new \DateTime($expireDate);
1369
+        $today = new \DateTime('now');
1370
+
1371
+        // if the user doesn't provide a share time we need to get it from the database
1372
+        // fall-back mode to keep API stable, because the $shareTime parameter was added later
1373
+        $defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
1374
+        if ($defaultExpireDateEnforced && $shareTime === null) {
1375
+            $items = self::getItemShared($itemType, $itemSource);
1376
+            $firstItem = reset($items);
1377
+            $shareTime = (int)$firstItem['stime'];
1378
+        }
1379
+
1380
+        if ($defaultExpireDateEnforced) {
1381
+            // initialize max date with share time
1382
+            $maxDate = new \DateTime();
1383
+            $maxDate->setTimestamp($shareTime);
1384
+            $maxDays = \OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
1385
+            $maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
1386
+            if ($date > $maxDate) {
1387
+                $warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
1388
+                $warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
1389
+                \OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
1390
+                throw new \Exception($warning_t);
1391
+            }
1392
+        }
1393
+
1394
+        if ($date < $today) {
1395
+            $message = 'Cannot set expiration date. Expiration date is in the past';
1396
+            $message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
1397
+            \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN);
1398
+            throw new \Exception($message_t);
1399
+        }
1400
+
1401
+        return $date;
1402
+    }
1403
+
1404
+    /**
1405
+     * Set expiration date for a share
1406
+     * @param string $itemType
1407
+     * @param string $itemSource
1408
+     * @param string $date expiration date
1409
+     * @param int $shareTime timestamp from when the file was shared
1410
+     * @return boolean
1411
+     * @throws \Exception when the expire date is not set, in the past or further in the future then the enforced date
1412
+     */
1413
+    public static function setExpirationDate($itemType, $itemSource, $date, $shareTime = null) {
1414
+        $user = \OC_User::getUser();
1415
+        $l = \OC::$server->getL10N('lib');
1416
+
1417
+        if ($date == '') {
1418
+            if (\OCP\Util::isDefaultExpireDateEnforced()) {
1419
+                $warning = 'Cannot clear expiration date. Shares are required to have an expiration date.';
1420
+                $warning_t = $l->t('Cannot clear expiration date. Shares are required to have an expiration date.');
1421
+                \OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
1422
+                throw new \Exception($warning_t);
1423
+            } else {
1424
+                $date = null;
1425
+            }
1426
+        } else {
1427
+            $date = self::validateExpireDate($date, $shareTime, $itemType, $itemSource);
1428
+        }
1429
+        $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ?  AND `uid_owner` = ? AND `share_type` = ?');
1430
+        $query->bindValue(1, $date, 'datetime');
1431
+        $query->bindValue(2, $itemType);
1432
+        $query->bindValue(3, $itemSource);
1433
+        $query->bindValue(4, $user);
1434
+        $query->bindValue(5, \OCP\Share::SHARE_TYPE_LINK);
1435
+
1436
+        $query->execute();
1437
+
1438
+        \OC_Hook::emit('OCP\Share', 'post_set_expiration_date', array(
1439
+            'itemType' => $itemType,
1440
+            'itemSource' => $itemSource,
1441
+            'date' => $date,
1442
+            'uidOwner' => $user
1443
+        ));
1444
+
1445
+        return true;
1446
+    }
1447
+
1448
+    /**
1449
+     * Retrieve the owner of a connection
1450
+     *
1451
+     * @param IDBConnection $connection
1452
+     * @param int $shareId
1453
+     * @throws \Exception
1454
+     * @return string uid of share owner
1455
+     */
1456
+    private static function getShareOwner(IDBConnection $connection, $shareId) {
1457
+        $qb = $connection->getQueryBuilder();
1458
+
1459
+        $qb->select('uid_owner')
1460
+            ->from('share')
1461
+            ->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
1462
+            ->setParameter(':shareId', $shareId);
1463
+        $result = $qb->execute();
1464
+        $result = $result->fetch();
1465
+
1466
+        if (empty($result)) {
1467
+            throw new \Exception('Share not found');
1468
+        }
1469
+
1470
+        return $result['uid_owner'];
1471
+    }
1472
+
1473
+    /**
1474
+     * Set password for a public link share
1475
+     *
1476
+     * @param IUserSession $userSession
1477
+     * @param IDBConnection $connection
1478
+     * @param IConfig $config
1479
+     * @param int $shareId
1480
+     * @param string $password
1481
+     * @throws \Exception
1482
+     * @return boolean
1483
+     */
1484
+    public static function setPassword(IUserSession $userSession,
1485
+                                        IDBConnection $connection,
1486
+                                        IConfig $config,
1487
+                                        $shareId, $password) {
1488
+        $user = $userSession->getUser();
1489
+        if (is_null($user)) {
1490
+            throw new \Exception("User not logged in");
1491
+        }
1492
+
1493
+        $uid = self::getShareOwner($connection, $shareId);
1494
+
1495
+        if ($uid !== $user->getUID()) {
1496
+            throw new \Exception('Cannot update share of a different user');
1497
+        }
1498
+
1499
+        if ($password === '') {
1500
+            $password = null;
1501
+        }
1502
+
1503
+        //If passwords are enforced the password can't be null
1504
+        if (self::enforcePassword($config) && is_null($password)) {
1505
+            throw new \Exception('Cannot remove password');
1506
+        }
1507
+
1508
+        self::verifyPassword($password);
1509
+
1510
+        $qb = $connection->getQueryBuilder();
1511
+        $qb->update('share')
1512
+            ->set('share_with', $qb->createParameter('pass'))
1513
+            ->where($qb->expr()->eq('id', $qb->createParameter('shareId')))
1514
+            ->setParameter(':pass', is_null($password) ? null : \OC::$server->getHasher()->hash($password))
1515
+            ->setParameter(':shareId', $shareId);
1516
+
1517
+        $qb->execute();
1518
+
1519
+        return true;
1520
+    }
1521
+
1522
+    /**
1523
+     * Checks whether a share has expired, calls unshareItem() if yes.
1524
+     * @param array $item Share data (usually database row)
1525
+     * @return boolean True if item was expired, false otherwise.
1526
+     */
1527
+    protected static function expireItem(array $item) {
1528
+
1529
+        $result = false;
1530
+
1531
+        // only use default expiration date for link shares
1532
+        if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
1533
+
1534
+            // calculate expiration date
1535
+            if (!empty($item['expiration'])) {
1536
+                $userDefinedExpire = new \DateTime($item['expiration']);
1537
+                $expires = $userDefinedExpire->getTimestamp();
1538
+            } else {
1539
+                $expires = null;
1540
+            }
1541
+
1542
+
1543
+            // get default expiration settings
1544
+            $defaultSettings = Helper::getDefaultExpireSetting();
1545
+            $expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
1546
+
1547
+
1548
+            if (is_int($expires)) {
1549
+                $now = time();
1550
+                if ($now > $expires) {
1551
+                    self::unshareItem($item);
1552
+                    $result = true;
1553
+                }
1554
+            }
1555
+        }
1556
+        return $result;
1557
+    }
1558
+
1559
+    /**
1560
+     * Unshares a share given a share data array
1561
+     * @param array $item Share data (usually database row)
1562
+     * @param int $newParent parent ID
1563
+     * @return null
1564
+     */
1565
+    protected static function unshareItem(array $item, $newParent = null) {
1566
+
1567
+        $shareType = (int)$item['share_type'];
1568
+        $shareWith = null;
1569
+        if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
1570
+            $shareWith = $item['share_with'];
1571
+        }
1572
+
1573
+        // Pass all the vars we have for now, they may be useful
1574
+        $hookParams = array(
1575
+            'id'            => $item['id'],
1576
+            'itemType'      => $item['item_type'],
1577
+            'itemSource'    => $item['item_source'],
1578
+            'shareType'     => $shareType,
1579
+            'shareWith'     => $shareWith,
1580
+            'itemParent'    => $item['parent'],
1581
+            'uidOwner'      => $item['uid_owner'],
1582
+        );
1583
+        if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
1584
+            $hookParams['fileSource'] = $item['file_source'];
1585
+            $hookParams['fileTarget'] = $item['file_target'];
1586
+        }
1587
+
1588
+        \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
1589
+        $deletedShares = Helper::delete($item['id'], false, null, $newParent);
1590
+        $deletedShares[] = $hookParams;
1591
+        $hookParams['deletedShares'] = $deletedShares;
1592
+        \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
1593
+        if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
1594
+            list(, $remote) = Helper::splitUserRemote($item['share_with']);
1595
+            self::sendRemoteUnshare($remote, $item['id'], $item['token']);
1596
+        }
1597
+    }
1598
+
1599
+    /**
1600
+     * Get the backend class for the specified item type
1601
+     * @param string $itemType
1602
+     * @throws \Exception
1603
+     * @return \OCP\Share_Backend
1604
+     */
1605
+    public static function getBackend($itemType) {
1606
+        $l = \OC::$server->getL10N('lib');
1607
+        if (isset(self::$backends[$itemType])) {
1608
+            return self::$backends[$itemType];
1609
+        } else if (isset(self::$backendTypes[$itemType]['class'])) {
1610
+            $class = self::$backendTypes[$itemType]['class'];
1611
+            if (class_exists($class)) {
1612
+                self::$backends[$itemType] = new $class;
1613
+                if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
1614
+                    $message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
1615
+                    $message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
1616
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
1617
+                    throw new \Exception($message_t);
1618
+                }
1619
+                return self::$backends[$itemType];
1620
+            } else {
1621
+                $message = 'Sharing backend %s not found';
1622
+                $message_t = $l->t('Sharing backend %s not found', array($class));
1623
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
1624
+                throw new \Exception($message_t);
1625
+            }
1626
+        }
1627
+        $message = 'Sharing backend for %s not found';
1628
+        $message_t = $l->t('Sharing backend for %s not found', array($itemType));
1629
+        \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), \OCP\Util::ERROR);
1630
+        throw new \Exception($message_t);
1631
+    }
1632
+
1633
+    /**
1634
+     * Check if resharing is allowed
1635
+     * @return boolean true if allowed or false
1636
+     *
1637
+     * Resharing is allowed by default if not configured
1638
+     */
1639
+    public static function isResharingAllowed() {
1640
+        if (!isset(self::$isResharingAllowed)) {
1641
+            if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
1642
+                self::$isResharingAllowed = true;
1643
+            } else {
1644
+                self::$isResharingAllowed = false;
1645
+            }
1646
+        }
1647
+        return self::$isResharingAllowed;
1648
+    }
1649
+
1650
+    /**
1651
+     * Get a list of collection item types for the specified item type
1652
+     * @param string $itemType
1653
+     * @return array
1654
+     */
1655
+    private static function getCollectionItemTypes($itemType) {
1656
+        $collectionTypes = array($itemType);
1657
+        foreach (self::$backendTypes as $type => $backend) {
1658
+            if (in_array($backend['collectionOf'], $collectionTypes)) {
1659
+                $collectionTypes[] = $type;
1660
+            }
1661
+        }
1662
+        // TODO Add option for collections to be collection of themselves, only 'folder' does it now...
1663
+        if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
1664
+            unset($collectionTypes[0]);
1665
+        }
1666
+        // Return array if collections were found or the item type is a
1667
+        // collection itself - collections can be inside collections
1668
+        if (count($collectionTypes) > 0) {
1669
+            return $collectionTypes;
1670
+        }
1671
+        return false;
1672
+    }
1673
+
1674
+    /**
1675
+     * Get the owners of items shared with a user.
1676
+     *
1677
+     * @param string $user The user the items are shared with.
1678
+     * @param string $type The type of the items shared with the user.
1679
+     * @param boolean $includeCollections Include collection item types (optional)
1680
+     * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
1681
+     * @return array
1682
+     */
1683
+    public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
1684
+        // First, we find out if $type is part of a collection (and if that collection is part of
1685
+        // another one and so on).
1686
+        $collectionTypes = array();
1687
+        if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
1688
+            $collectionTypes[] = $type;
1689
+        }
1690
+
1691
+        // Of these collection types, along with our original $type, we make a
1692
+        // list of the ones for which a sharing backend has been registered.
1693
+        // FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
1694
+        // with its $includeCollections parameter set to true. Unfortunately, this fails currently.
1695
+        $allMaybeSharedItems = array();
1696
+        foreach ($collectionTypes as $collectionType) {
1697
+            if (isset(self::$backends[$collectionType])) {
1698
+                $allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
1699
+                    $collectionType,
1700
+                    $user,
1701
+                    self::FORMAT_NONE
1702
+                );
1703
+            }
1704
+        }
1705
+
1706
+        $owners = array();
1707
+        if ($includeOwner) {
1708
+            $owners[] = $user;
1709
+        }
1710
+
1711
+        // We take a look at all shared items of the given $type (or of the collections it is part of)
1712
+        // and find out their owners. Then, we gather the tags for the original $type from all owners,
1713
+        // and return them as elements of a list that look like "Tag (owner)".
1714
+        foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
1715
+            foreach ($maybeSharedItems as $sharedItem) {
1716
+                if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
1717
+                    $owners[] = $sharedItem['uid_owner'];
1718
+                }
1719
+            }
1720
+        }
1721
+
1722
+        return $owners;
1723
+    }
1724
+
1725
+    /**
1726
+     * Get shared items from the database
1727
+     * @param string $itemType
1728
+     * @param string $item Item source or target (optional)
1729
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
1730
+     * @param string $shareWith User or group the item is being shared with
1731
+     * @param string $uidOwner User that is the owner of shared items (optional)
1732
+     * @param int $format Format to convert items to with formatItems() (optional)
1733
+     * @param mixed $parameters to pass to formatItems() (optional)
1734
+     * @param int $limit Number of items to return, -1 to return all matches (optional)
1735
+     * @param boolean $includeCollections Include collection item types (optional)
1736
+     * @param boolean $itemShareWithBySource (optional)
1737
+     * @param boolean $checkExpireDate
1738
+     * @return array
1739
+     *
1740
+     * See public functions getItem(s)... for parameter usage
1741
+     *
1742
+     */
1743
+    public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
1744
+                                    $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
1745
+                                    $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
1746
+        if (!self::isEnabled()) {
1747
+            return array();
1748
+        }
1749
+        $backend = self::getBackend($itemType);
1750
+        $collectionTypes = false;
1751
+        // Get filesystem root to add it to the file target and remove from the
1752
+        // file source, match file_source with the file cache
1753
+        if ($itemType == 'file' || $itemType == 'folder') {
1754
+            if(!is_null($uidOwner)) {
1755
+                $root = \OC\Files\Filesystem::getRoot();
1756
+            } else {
1757
+                $root = '';
1758
+            }
1759
+            $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
1760
+            if (!isset($item)) {
1761
+                $where .= ' AND `file_target` IS NOT NULL ';
1762
+            }
1763
+            $where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1764
+            $fileDependent = true;
1765
+            $queryArgs = array();
1766
+        } else {
1767
+            $fileDependent = false;
1768
+            $root = '';
1769
+            $collectionTypes = self::getCollectionItemTypes($itemType);
1770
+            if ($includeCollections && !isset($item) && $collectionTypes) {
1771
+                // If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1772
+                if (!in_array($itemType, $collectionTypes)) {
1773
+                    $itemTypes = array_merge(array($itemType), $collectionTypes);
1774
+                } else {
1775
+                    $itemTypes = $collectionTypes;
1776
+                }
1777
+                $placeholders = join(',', array_fill(0, count($itemTypes), '?'));
1778
+                $where = ' WHERE `item_type` IN ('.$placeholders.'))';
1779
+                $queryArgs = $itemTypes;
1780
+            } else {
1781
+                $where = ' WHERE `item_type` = ?';
1782
+                $queryArgs = array($itemType);
1783
+            }
1784
+        }
1785
+        if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1786
+            $where .= ' AND `share_type` != ?';
1787
+            $queryArgs[] = self::SHARE_TYPE_LINK;
1788
+        }
1789
+        if (isset($shareType)) {
1790
+            // Include all user and group items
1791
+            if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1792
+                $where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1793
+                $queryArgs[] = self::SHARE_TYPE_USER;
1794
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
1795
+                $queryArgs[] = $shareWith;
1796
+
1797
+                $user = \OC::$server->getUserManager()->get($shareWith);
1798
+                $groups = [];
1799
+                if ($user) {
1800
+                    $groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1801
+                }
1802
+                if (!empty($groups)) {
1803
+                    $placeholders = join(',', array_fill(0, count($groups), '?'));
1804
+                    $where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1805
+                    $queryArgs[] = self::SHARE_TYPE_GROUP;
1806
+                    $queryArgs = array_merge($queryArgs, $groups);
1807
+                }
1808
+                $where .= ')';
1809
+                // Don't include own group shares
1810
+                $where .= ' AND `uid_owner` != ?';
1811
+                $queryArgs[] = $shareWith;
1812
+            } else {
1813
+                $where .= ' AND `share_type` = ?';
1814
+                $queryArgs[] = $shareType;
1815
+                if (isset($shareWith)) {
1816
+                    $where .= ' AND `share_with` = ?';
1817
+                    $queryArgs[] = $shareWith;
1818
+                }
1819
+            }
1820
+        }
1821
+        if (isset($uidOwner)) {
1822
+            $where .= ' AND `uid_owner` = ?';
1823
+            $queryArgs[] = $uidOwner;
1824
+            if (!isset($shareType)) {
1825
+                // Prevent unique user targets for group shares from being selected
1826
+                $where .= ' AND `share_type` != ?';
1827
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
1828
+            }
1829
+            if ($fileDependent) {
1830
+                $column = 'file_source';
1831
+            } else {
1832
+                $column = 'item_source';
1833
+            }
1834
+        } else {
1835
+            if ($fileDependent) {
1836
+                $column = 'file_target';
1837
+            } else {
1838
+                $column = 'item_target';
1839
+            }
1840
+        }
1841
+        if (isset($item)) {
1842
+            $collectionTypes = self::getCollectionItemTypes($itemType);
1843
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1844
+                $where .= ' AND (';
1845
+            } else {
1846
+                $where .= ' AND';
1847
+            }
1848
+            // If looking for own shared items, check item_source else check item_target
1849
+            if (isset($uidOwner) || $itemShareWithBySource) {
1850
+                // If item type is a file, file source needs to be checked in case the item was converted
1851
+                if ($fileDependent) {
1852
+                    $where .= ' `file_source` = ?';
1853
+                    $column = 'file_source';
1854
+                } else {
1855
+                    $where .= ' `item_source` = ?';
1856
+                    $column = 'item_source';
1857
+                }
1858
+            } else {
1859
+                if ($fileDependent) {
1860
+                    $where .= ' `file_target` = ?';
1861
+                    $item = \OC\Files\Filesystem::normalizePath($item);
1862
+                } else {
1863
+                    $where .= ' `item_target` = ?';
1864
+                }
1865
+            }
1866
+            $queryArgs[] = $item;
1867
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1868
+                $placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
1869
+                $where .= ' OR `item_type` IN ('.$placeholders.'))';
1870
+                $queryArgs = array_merge($queryArgs, $collectionTypes);
1871
+            }
1872
+        }
1873
+
1874
+        if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1875
+            // Make sure the unique user target is returned if it exists,
1876
+            // unique targets should follow the group share in the database
1877
+            // If the limit is not 1, the filtering can be done later
1878
+            $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1879
+        } else {
1880
+            $where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1881
+        }
1882
+
1883
+        if ($limit != -1 && !$includeCollections) {
1884
+            // The limit must be at least 3, because filtering needs to be done
1885
+            if ($limit < 3) {
1886
+                $queryLimit = 3;
1887
+            } else {
1888
+                $queryLimit = $limit;
1889
+            }
1890
+        } else {
1891
+            $queryLimit = null;
1892
+        }
1893
+        $select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1894
+        $root = strlen($root);
1895
+        $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1896
+        $result = $query->execute($queryArgs);
1897
+        if ($result === false) {
1898
+            \OCP\Util::writeLog('OCP\Share',
1899
+                \OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1900
+                \OCP\Util::ERROR);
1901
+        }
1902
+        $items = array();
1903
+        $targets = array();
1904
+        $switchedItems = array();
1905
+        $mounts = array();
1906
+        while ($row = $result->fetchRow()) {
1907
+            self::transformDBResults($row);
1908
+            // Filter out duplicate group shares for users with unique targets
1909
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1910
+                continue;
1911
+            }
1912
+            if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1913
+                $row['share_type'] = self::SHARE_TYPE_GROUP;
1914
+                $row['unique_name'] = true; // remember that we use a unique name for this user
1915
+                $row['share_with'] = $items[$row['parent']]['share_with'];
1916
+                // if the group share was unshared from the user we keep the permission, otherwise
1917
+                // we take the permission from the parent because this is always the up-to-date
1918
+                // permission for the group share
1919
+                if ($row['permissions'] > 0) {
1920
+                    $row['permissions'] = $items[$row['parent']]['permissions'];
1921
+                }
1922
+                // Remove the parent group share
1923
+                unset($items[$row['parent']]);
1924
+                if ($row['permissions'] == 0) {
1925
+                    continue;
1926
+                }
1927
+            } else if (!isset($uidOwner)) {
1928
+                // Check if the same target already exists
1929
+                if (isset($targets[$row['id']])) {
1930
+                    // Check if the same owner shared with the user twice
1931
+                    // through a group and user share - this is allowed
1932
+                    $id = $targets[$row['id']];
1933
+                    if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1934
+                        // Switch to group share type to ensure resharing conditions aren't bypassed
1935
+                        if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1936
+                            $items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1937
+                            $items[$id]['share_with'] = $row['share_with'];
1938
+                        }
1939
+                        // Switch ids if sharing permission is granted on only
1940
+                        // one share to ensure correct parent is used if resharing
1941
+                        if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1942
+                            && (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1943
+                            $items[$row['id']] = $items[$id];
1944
+                            $switchedItems[$id] = $row['id'];
1945
+                            unset($items[$id]);
1946
+                            $id = $row['id'];
1947
+                        }
1948
+                        $items[$id]['permissions'] |= (int)$row['permissions'];
1949
+
1950
+                    }
1951
+                    continue;
1952
+                } elseif (!empty($row['parent'])) {
1953
+                    $targets[$row['parent']] = $row['id'];
1954
+                }
1955
+            }
1956
+            // Remove root from file source paths if retrieving own shared items
1957
+            if (isset($uidOwner) && isset($row['path'])) {
1958
+                if (isset($row['parent'])) {
1959
+                    $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1960
+                    $parentResult = $query->execute(array($row['parent']));
1961
+                    if ($result === false) {
1962
+                        \OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
1963
+                            \OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1964
+                            \OCP\Util::ERROR);
1965
+                    } else {
1966
+                        $parentRow = $parentResult->fetchRow();
1967
+                        $tmpPath = $parentRow['file_target'];
1968
+                        // find the right position where the row path continues from the target path
1969
+                        $pos = strrpos($row['path'], $parentRow['file_target']);
1970
+                        $subPath = substr($row['path'], $pos);
1971
+                        $splitPath = explode('/', $subPath);
1972
+                        foreach (array_slice($splitPath, 2) as $pathPart) {
1973
+                            $tmpPath = $tmpPath . '/' . $pathPart;
1974
+                        }
1975
+                        $row['path'] = $tmpPath;
1976
+                    }
1977
+                } else {
1978
+                    if (!isset($mounts[$row['storage']])) {
1979
+                        $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1980
+                        if (is_array($mountPoints) && !empty($mountPoints)) {
1981
+                            $mounts[$row['storage']] = current($mountPoints);
1982
+                        }
1983
+                    }
1984
+                    if (!empty($mounts[$row['storage']])) {
1985
+                        $path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1986
+                        $relPath = substr($path, $root); // path relative to data/user
1987
+                        $row['path'] = rtrim($relPath, '/');
1988
+                    }
1989
+                }
1990
+            }
1991
+
1992
+            if($checkExpireDate) {
1993
+                if (self::expireItem($row)) {
1994
+                    continue;
1995
+                }
1996
+            }
1997
+            // Check if resharing is allowed, if not remove share permission
1998
+            if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
1999
+                $row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
2000
+            }
2001
+            // Add display names to result
2002
+            $row['share_with_displayname'] = $row['share_with'];
2003
+            if ( isset($row['share_with']) && $row['share_with'] != '' &&
2004
+                $row['share_type'] === self::SHARE_TYPE_USER) {
2005
+                $row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']);
2006
+            } else if(isset($row['share_with']) && $row['share_with'] != '' &&
2007
+                $row['share_type'] === self::SHARE_TYPE_REMOTE) {
2008
+                $addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
2009
+                foreach ($addressBookEntries as $entry) {
2010
+                    foreach ($entry['CLOUD'] as $cloudID) {
2011
+                        if ($cloudID === $row['share_with']) {
2012
+                            $row['share_with_displayname'] = $entry['FN'];
2013
+                        }
2014
+                    }
2015
+                }
2016
+            }
2017
+            if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
2018
+                $row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']);
2019
+            }
2020
+
2021
+            if ($row['permissions'] > 0) {
2022
+                $items[$row['id']] = $row;
2023
+            }
2024
+
2025
+        }
2026
+
2027
+        // group items if we are looking for items shared with the current user
2028
+        if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
2029
+            $items = self::groupItems($items, $itemType);
2030
+        }
2031
+
2032
+        if (!empty($items)) {
2033
+            $collectionItems = array();
2034
+            foreach ($items as &$row) {
2035
+                // Return only the item instead of a 2-dimensional array
2036
+                if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
2037
+                    if ($format == self::FORMAT_NONE) {
2038
+                        return $row;
2039
+                    } else {
2040
+                        break;
2041
+                    }
2042
+                }
2043
+                // Check if this is a collection of the requested item type
2044
+                if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
2045
+                    if (($collectionBackend = self::getBackend($row['item_type']))
2046
+                        && $collectionBackend instanceof \OCP\Share_Backend_Collection) {
2047
+                        // Collections can be inside collections, check if the item is a collection
2048
+                        if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
2049
+                            $collectionItems[] = $row;
2050
+                        } else {
2051
+                            $collection = array();
2052
+                            $collection['item_type'] = $row['item_type'];
2053
+                            if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
2054
+                                $collection['path'] = basename($row['path']);
2055
+                            }
2056
+                            $row['collection'] = $collection;
2057
+                            // Fetch all of the children sources
2058
+                            $children = $collectionBackend->getChildren($row[$column]);
2059
+                            foreach ($children as $child) {
2060
+                                $childItem = $row;
2061
+                                $childItem['item_type'] = $itemType;
2062
+                                if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
2063
+                                    $childItem['item_source'] = $child['source'];
2064
+                                    $childItem['item_target'] = $child['target'];
2065
+                                }
2066
+                                if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
2067
+                                    if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
2068
+                                        $childItem['file_source'] = $child['source'];
2069
+                                    } else { // TODO is this really needed if we already know that we use the file backend?
2070
+                                        $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
2071
+                                        $childItem['file_source'] = $meta['fileid'];
2072
+                                    }
2073
+                                    $childItem['file_target'] =
2074
+                                        \OC\Files\Filesystem::normalizePath($child['file_path']);
2075
+                                }
2076
+                                if (isset($item)) {
2077
+                                    if ($childItem[$column] == $item) {
2078
+                                        // Return only the item instead of a 2-dimensional array
2079
+                                        if ($limit == 1) {
2080
+                                            if ($format == self::FORMAT_NONE) {
2081
+                                                return $childItem;
2082
+                                            } else {
2083
+                                                // Unset the items array and break out of both loops
2084
+                                                $items = array();
2085
+                                                $items[] = $childItem;
2086
+                                                break 2;
2087
+                                            }
2088
+                                        } else {
2089
+                                            $collectionItems[] = $childItem;
2090
+                                        }
2091
+                                    }
2092
+                                } else {
2093
+                                    $collectionItems[] = $childItem;
2094
+                                }
2095
+                            }
2096
+                        }
2097
+                    }
2098
+                    // Remove collection item
2099
+                    $toRemove = $row['id'];
2100
+                    if (array_key_exists($toRemove, $switchedItems)) {
2101
+                        $toRemove = $switchedItems[$toRemove];
2102
+                    }
2103
+                    unset($items[$toRemove]);
2104
+                } elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
2105
+                    // FIXME: Thats a dirty hack to improve file sharing performance,
2106
+                    // see github issue #10588 for more details
2107
+                    // Need to find a solution which works for all back-ends
2108
+                    $collectionBackend = self::getBackend($row['item_type']);
2109
+                    $sharedParents = $collectionBackend->getParents($row['item_source']);
2110
+                    foreach ($sharedParents as $parent) {
2111
+                        $collectionItems[] = $parent;
2112
+                    }
2113
+                }
2114
+            }
2115
+            if (!empty($collectionItems)) {
2116
+                $collectionItems = array_unique($collectionItems, SORT_REGULAR);
2117
+                $items = array_merge($items, $collectionItems);
2118
+            }
2119
+
2120
+            // filter out invalid items, these can appear when subshare entries exist
2121
+            // for a group in which the requested user isn't a member any more
2122
+            $items = array_filter($items, function($item) {
2123
+                return $item['share_type'] !== self::$shareTypeGroupUserUnique;
2124
+            });
2125
+
2126
+            return self::formatResult($items, $column, $backend, $format, $parameters);
2127
+        } elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
2128
+            // FIXME: Thats a dirty hack to improve file sharing performance,
2129
+            // see github issue #10588 for more details
2130
+            // Need to find a solution which works for all back-ends
2131
+            $collectionItems = array();
2132
+            $collectionBackend = self::getBackend('folder');
2133
+            $sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
2134
+            foreach ($sharedParents as $parent) {
2135
+                $collectionItems[] = $parent;
2136
+            }
2137
+            if ($limit === 1) {
2138
+                return reset($collectionItems);
2139
+            }
2140
+            return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
2141
+        }
2142
+
2143
+        return array();
2144
+    }
2145
+
2146
+    /**
2147
+     * group items with link to the same source
2148
+     *
2149
+     * @param array $items
2150
+     * @param string $itemType
2151
+     * @return array of grouped items
2152
+     */
2153
+    protected static function groupItems($items, $itemType) {
2154
+
2155
+        $fileSharing = ($itemType === 'file' || $itemType === 'folder') ? true : false;
2156
+
2157
+        $result = array();
2158
+
2159
+        foreach ($items as $item) {
2160
+            $grouped = false;
2161
+            foreach ($result as $key => $r) {
2162
+                // for file/folder shares we need to compare file_source, otherwise we compare item_source
2163
+                // only group shares if they already point to the same target, otherwise the file where shared
2164
+                // before grouping of shares was added. In this case we don't group them toi avoid confusions
2165
+                if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
2166
+                    (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
2167
+                    // add the first item to the list of grouped shares
2168
+                    if (!isset($result[$key]['grouped'])) {
2169
+                        $result[$key]['grouped'][] = $result[$key];
2170
+                    }
2171
+                    $result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
2172
+                    $result[$key]['grouped'][] = $item;
2173
+                    $grouped = true;
2174
+                    break;
2175
+                }
2176
+            }
2177
+
2178
+            if (!$grouped) {
2179
+                $result[] = $item;
2180
+            }
2181
+
2182
+        }
2183
+
2184
+        return $result;
2185
+    }
2186
+
2187
+    /**
2188
+     * Put shared item into the database
2189
+     * @param string $itemType Item type
2190
+     * @param string $itemSource Item source
2191
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
2192
+     * @param string $shareWith User or group the item is being shared with
2193
+     * @param string $uidOwner User that is the owner of shared item
2194
+     * @param int $permissions CRUDS permissions
2195
+     * @param boolean|array $parentFolder Parent folder target (optional)
2196
+     * @param string $token (optional)
2197
+     * @param string $itemSourceName name of the source item (optional)
2198
+     * @param \DateTime $expirationDate (optional)
2199
+     * @throws \Exception
2200
+     * @return mixed id of the new share or false
2201
+     */
2202
+    private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
2203
+                                $permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
2204
+
2205
+        $queriesToExecute = array();
2206
+        $suggestedItemTarget = null;
2207
+        $groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
2208
+        $groupItemTarget = $itemTarget = $fileSource = $parent = 0;
2209
+
2210
+        $result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
2211
+        if(!empty($result)) {
2212
+            $parent = $result['parent'];
2213
+            $itemSource = $result['itemSource'];
2214
+            $fileSource = $result['fileSource'];
2215
+            $suggestedItemTarget = $result['suggestedItemTarget'];
2216
+            $suggestedFileTarget = $result['suggestedFileTarget'];
2217
+            $filePath = $result['filePath'];
2218
+        }
2219
+
2220
+        $isGroupShare = false;
2221
+        if ($shareType == self::SHARE_TYPE_GROUP) {
2222
+            $isGroupShare = true;
2223
+            if (isset($shareWith['users'])) {
2224
+                $users = $shareWith['users'];
2225
+            } else {
2226
+                $group = \OC::$server->getGroupManager()->get($shareWith['group']);
2227
+                if ($group) {
2228
+                    $users = $group->searchUsers('', -1, 0);
2229
+                    $userIds = [];
2230
+                    foreach ($users as $user) {
2231
+                        $userIds[] = $user->getUID();
2232
+                    }
2233
+                    $users = $userIds;
2234
+                } else {
2235
+                    $users = [];
2236
+                }
2237
+            }
2238
+            // remove current user from list
2239
+            if (in_array(\OCP\User::getUser(), $users)) {
2240
+                unset($users[array_search(\OCP\User::getUser(), $users)]);
2241
+            }
2242
+            $groupItemTarget = Helper::generateTarget($itemType, $itemSource,
2243
+                $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
2244
+            $groupFileTarget = Helper::generateTarget($itemType, $itemSource,
2245
+                $shareType, $shareWith['group'], $uidOwner, $filePath);
2246
+
2247
+            // add group share to table and remember the id as parent
2248
+            $queriesToExecute['groupShare'] = array(
2249
+                'itemType'			=> $itemType,
2250
+                'itemSource'		=> $itemSource,
2251
+                'itemTarget'		=> $groupItemTarget,
2252
+                'shareType'			=> $shareType,
2253
+                'shareWith'			=> $shareWith['group'],
2254
+                'uidOwner'			=> $uidOwner,
2255
+                'permissions'		=> $permissions,
2256
+                'shareTime'			=> time(),
2257
+                'fileSource'		=> $fileSource,
2258
+                'fileTarget'		=> $groupFileTarget,
2259
+                'token'				=> $token,
2260
+                'parent'			=> $parent,
2261
+                'expiration'		=> $expirationDate,
2262
+            );
2263
+
2264
+        } else {
2265
+            $users = array($shareWith);
2266
+            $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
2267
+                $suggestedItemTarget);
2268
+        }
2269
+
2270
+        $run = true;
2271
+        $error = '';
2272
+        $preHookData = array(
2273
+            'itemType' => $itemType,
2274
+            'itemSource' => $itemSource,
2275
+            'shareType' => $shareType,
2276
+            'uidOwner' => $uidOwner,
2277
+            'permissions' => $permissions,
2278
+            'fileSource' => $fileSource,
2279
+            'expiration' => $expirationDate,
2280
+            'token' => $token,
2281
+            'run' => &$run,
2282
+            'error' => &$error
2283
+        );
2284
+
2285
+        $preHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
2286
+        $preHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
2287
+
2288
+        \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
2289
+
2290
+        if ($run === false) {
2291
+            throw new \Exception($error);
2292
+        }
2293
+
2294
+        foreach ($users as $user) {
2295
+            $sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
2296
+            $sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
2297
+
2298
+            $userShareType = ($isGroupShare) ? self::$shareTypeGroupUserUnique : $shareType;
2299
+
2300
+            if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
2301
+                $fileTarget = $sourceExists['file_target'];
2302
+                $itemTarget = $sourceExists['item_target'];
2303
+
2304
+                // for group shares we don't need a additional entry if the target is the same
2305
+                if($isGroupShare && $groupItemTarget === $itemTarget) {
2306
+                    continue;
2307
+                }
2308
+
2309
+            } elseif(!$sourceExists && !$isGroupShare)  {
2310
+
2311
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
2312
+                    $uidOwner, $suggestedItemTarget, $parent);
2313
+                if (isset($fileSource)) {
2314
+                    if ($parentFolder) {
2315
+                        if ($parentFolder === true) {
2316
+                            $fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
2317
+                                $uidOwner, $suggestedFileTarget, $parent);
2318
+                            if ($fileTarget != $groupFileTarget) {
2319
+                                $parentFolders[$user]['folder'] = $fileTarget;
2320
+                            }
2321
+                        } else if (isset($parentFolder[$user])) {
2322
+                            $fileTarget = $parentFolder[$user]['folder'].$itemSource;
2323
+                            $parent = $parentFolder[$user]['id'];
2324
+                        }
2325
+                    } else {
2326
+                        $fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
2327
+                            $user, $uidOwner, $suggestedFileTarget, $parent);
2328
+                    }
2329
+                } else {
2330
+                    $fileTarget = null;
2331
+                }
2332
+
2333
+            } else {
2334
+
2335
+                // group share which doesn't exists until now, check if we need a unique target for this user
2336
+
2337
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
2338
+                    $uidOwner, $suggestedItemTarget, $parent);
2339
+
2340
+                // do we also need a file target
2341
+                if (isset($fileSource)) {
2342
+                    $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
2343
+                        $uidOwner, $suggestedFileTarget, $parent);
2344
+                } else {
2345
+                    $fileTarget = null;
2346
+                }
2347
+
2348
+                if (($itemTarget === $groupItemTarget) &&
2349
+                    (!isset($fileSource) || $fileTarget === $groupFileTarget)) {
2350
+                    continue;
2351
+                }
2352
+            }
2353
+
2354
+            $queriesToExecute[] = array(
2355
+                'itemType'			=> $itemType,
2356
+                'itemSource'		=> $itemSource,
2357
+                'itemTarget'		=> $itemTarget,
2358
+                'shareType'			=> $userShareType,
2359
+                'shareWith'			=> $user,
2360
+                'uidOwner'			=> $uidOwner,
2361
+                'permissions'		=> $permissions,
2362
+                'shareTime'			=> time(),
2363
+                'fileSource'		=> $fileSource,
2364
+                'fileTarget'		=> $fileTarget,
2365
+                'token'				=> $token,
2366
+                'parent'			=> $parent,
2367
+                'expiration'		=> $expirationDate,
2368
+            );
2369
+
2370
+        }
2371
+
2372
+        $id = false;
2373
+        if ($isGroupShare) {
2374
+            $id = self::insertShare($queriesToExecute['groupShare']);
2375
+            // Save this id, any extra rows for this group share will need to reference it
2376
+            $parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
2377
+            unset($queriesToExecute['groupShare']);
2378
+        }
2379
+
2380
+        foreach ($queriesToExecute as $shareQuery) {
2381
+            $shareQuery['parent'] = $parent;
2382
+            $id = self::insertShare($shareQuery);
2383
+        }
2384
+
2385
+        $postHookData = array(
2386
+            'itemType' => $itemType,
2387
+            'itemSource' => $itemSource,
2388
+            'parent' => $parent,
2389
+            'shareType' => $shareType,
2390
+            'uidOwner' => $uidOwner,
2391
+            'permissions' => $permissions,
2392
+            'fileSource' => $fileSource,
2393
+            'id' => $parent,
2394
+            'token' => $token,
2395
+            'expirationDate' => $expirationDate,
2396
+        );
2397
+
2398
+        $postHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
2399
+        $postHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
2400
+        $postHookData['fileTarget'] = ($isGroupShare) ? $groupFileTarget : $fileTarget;
2401
+
2402
+        \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
2403
+
2404
+
2405
+        return $id ? $id : false;
2406
+    }
2407
+
2408
+    /**
2409
+     * @param string $itemType
2410
+     * @param string $itemSource
2411
+     * @param int $shareType
2412
+     * @param string $shareWith
2413
+     * @param string $uidOwner
2414
+     * @param int $permissions
2415
+     * @param string|null $itemSourceName
2416
+     * @param null|\DateTime $expirationDate
2417
+     */
2418
+    private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
2419
+        $backend = self::getBackend($itemType);
2420
+
2421
+        $l = \OC::$server->getL10N('lib');
2422
+        $result = array();
2423
+
2424
+        $column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
2425
+
2426
+        $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
2427
+        if ($checkReshare) {
2428
+            // Check if attempting to share back to owner
2429
+            if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
2430
+                $message = 'Sharing %s failed, because the user %s is the original sharer';
2431
+                $message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
2432
+
2433
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
2434
+                throw new \Exception($message_t);
2435
+            }
2436
+        }
2437
+
2438
+        if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
2439
+            // Check if share permissions is granted
2440
+            if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
2441
+                if (~(int)$checkReshare['permissions'] & $permissions) {
2442
+                    $message = 'Sharing %s failed, because the permissions exceed permissions granted to %s';
2443
+                    $message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner));
2444
+
2445
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), \OCP\Util::DEBUG);
2446
+                    throw new \Exception($message_t);
2447
+                } else {
2448
+                    // TODO Don't check if inside folder
2449
+                    $result['parent'] = $checkReshare['id'];
2450
+
2451
+                    $result['expirationDate'] = $expirationDate;
2452
+                    // $checkReshare['expiration'] could be null and then is always less than any value
2453
+                    if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
2454
+                        $result['expirationDate'] = $checkReshare['expiration'];
2455
+                    }
2456
+
2457
+                    // only suggest the same name as new target if it is a reshare of the
2458
+                    // same file/folder and not the reshare of a child
2459
+                    if ($checkReshare[$column] === $itemSource) {
2460
+                        $result['filePath'] = $checkReshare['file_target'];
2461
+                        $result['itemSource'] = $checkReshare['item_source'];
2462
+                        $result['fileSource'] = $checkReshare['file_source'];
2463
+                        $result['suggestedItemTarget'] = $checkReshare['item_target'];
2464
+                        $result['suggestedFileTarget'] = $checkReshare['file_target'];
2465
+                    } else {
2466
+                        $result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
2467
+                        $result['suggestedItemTarget'] = null;
2468
+                        $result['suggestedFileTarget'] = null;
2469
+                        $result['itemSource'] = $itemSource;
2470
+                        $result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
2471
+                    }
2472
+                }
2473
+            } else {
2474
+                $message = 'Sharing %s failed, because resharing is not allowed';
2475
+                $message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
2476
+
2477
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
2478
+                throw new \Exception($message_t);
2479
+            }
2480
+        } else {
2481
+            $result['parent'] = null;
2482
+            $result['suggestedItemTarget'] = null;
2483
+            $result['suggestedFileTarget'] = null;
2484
+            $result['itemSource'] = $itemSource;
2485
+            $result['expirationDate'] = $expirationDate;
2486
+            if (!$backend->isValidSource($itemSource, $uidOwner)) {
2487
+                $message = 'Sharing %s failed, because the sharing backend for '
2488
+                    .'%s could not find its source';
2489
+                $message_t = $l->t('Sharing %s failed, because the sharing backend for %s could not find its source', array($itemSource, $itemType));
2490
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), \OCP\Util::DEBUG);
2491
+                throw new \Exception($message_t);
2492
+            }
2493
+            if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
2494
+                $result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
2495
+                if ($itemType == 'file' || $itemType == 'folder') {
2496
+                    $result['fileSource'] = $itemSource;
2497
+                } else {
2498
+                    $meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
2499
+                    $result['fileSource'] = $meta['fileid'];
2500
+                }
2501
+                if ($result['fileSource'] == -1) {
2502
+                    $message = 'Sharing %s failed, because the file could not be found in the file cache';
2503
+                    $message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
2504
+
2505
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
2506
+                    throw new \Exception($message_t);
2507
+                }
2508
+            } else {
2509
+                $result['filePath'] = null;
2510
+                $result['fileSource'] = null;
2511
+            }
2512
+        }
2513
+
2514
+        return $result;
2515
+    }
2516
+
2517
+    /**
2518
+     *
2519
+     * @param array $shareData
2520
+     * @return mixed false in case of a failure or the id of the new share
2521
+     */
2522
+    private static function insertShare(array $shareData) {
2523
+
2524
+        $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
2525
+            .' `item_type`, `item_source`, `item_target`, `share_type`,'
2526
+            .' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
2527
+            .' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
2528
+        $query->bindValue(1, $shareData['itemType']);
2529
+        $query->bindValue(2, $shareData['itemSource']);
2530
+        $query->bindValue(3, $shareData['itemTarget']);
2531
+        $query->bindValue(4, $shareData['shareType']);
2532
+        $query->bindValue(5, $shareData['shareWith']);
2533
+        $query->bindValue(6, $shareData['uidOwner']);
2534
+        $query->bindValue(7, $shareData['permissions']);
2535
+        $query->bindValue(8, $shareData['shareTime']);
2536
+        $query->bindValue(9, $shareData['fileSource']);
2537
+        $query->bindValue(10, $shareData['fileTarget']);
2538
+        $query->bindValue(11, $shareData['token']);
2539
+        $query->bindValue(12, $shareData['parent']);
2540
+        $query->bindValue(13, $shareData['expiration'], 'datetime');
2541
+        $result = $query->execute();
2542
+
2543
+        $id = false;
2544
+        if ($result) {
2545
+            $id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
2546
+        }
2547
+
2548
+        return $id;
2549
+
2550
+    }
2551
+
2552
+    /**
2553
+     * Delete all shares with type SHARE_TYPE_LINK
2554
+     */
2555
+    public static function removeAllLinkShares() {
2556
+        // Delete any link shares
2557
+        $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ?');
2558
+        $result = $query->execute(array(self::SHARE_TYPE_LINK));
2559
+        while ($item = $result->fetchRow()) {
2560
+            Helper::delete($item['id']);
2561
+        }
2562
+    }
2563
+
2564
+    /**
2565
+     * In case a password protected link is not yet authenticated this function will return false
2566
+     *
2567
+     * @param array $linkItem
2568
+     * @return boolean
2569
+     */
2570
+    public static function checkPasswordProtectedShare(array $linkItem) {
2571
+        if (!isset($linkItem['share_with'])) {
2572
+            return true;
2573
+        }
2574
+        if (!isset($linkItem['share_type'])) {
2575
+            return true;
2576
+        }
2577
+        if (!isset($linkItem['id'])) {
2578
+            return true;
2579
+        }
2580
+
2581
+        if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
2582
+            return true;
2583
+        }
2584
+
2585
+        if ( \OC::$server->getSession()->exists('public_link_authenticated')
2586
+            && \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
2587
+            return true;
2588
+        }
2589
+
2590
+        return false;
2591
+    }
2592
+
2593
+    /**
2594
+     * construct select statement
2595
+     * @param int $format
2596
+     * @param boolean $fileDependent ist it a file/folder share or a generla share
2597
+     * @param string $uidOwner
2598
+     * @return string select statement
2599
+     */
2600
+    private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
2601
+        $select = '*';
2602
+        if ($format == self::FORMAT_STATUSES) {
2603
+            if ($fileDependent) {
2604
+                $select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
2605
+                    . '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
2606
+                    . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
2607
+                    . '`uid_initiator`';
2608
+            } else {
2609
+                $select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
2610
+            }
2611
+        } else {
2612
+            if (isset($uidOwner)) {
2613
+                if ($fileDependent) {
2614
+                    $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
2615
+                        . ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
2616
+                        . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
2617
+                        . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
2618
+                } else {
2619
+                    $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
2620
+                        . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
2621
+                }
2622
+            } else {
2623
+                if ($fileDependent) {
2624
+                    if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
2625
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
2626
+                            . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
2627
+                            . '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
2628
+                            . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
2629
+                    } else {
2630
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
2631
+                            . '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
2632
+                            . '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
2633
+                            . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
2634
+                            . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
2635
+                    }
2636
+                }
2637
+            }
2638
+        }
2639
+        return $select;
2640
+    }
2641
+
2642
+
2643
+    /**
2644
+     * transform db results
2645
+     * @param array $row result
2646
+     */
2647
+    private static function transformDBResults(&$row) {
2648
+        if (isset($row['id'])) {
2649
+            $row['id'] = (int) $row['id'];
2650
+        }
2651
+        if (isset($row['share_type'])) {
2652
+            $row['share_type'] = (int) $row['share_type'];
2653
+        }
2654
+        if (isset($row['parent'])) {
2655
+            $row['parent'] = (int) $row['parent'];
2656
+        }
2657
+        if (isset($row['file_parent'])) {
2658
+            $row['file_parent'] = (int) $row['file_parent'];
2659
+        }
2660
+        if (isset($row['file_source'])) {
2661
+            $row['file_source'] = (int) $row['file_source'];
2662
+        }
2663
+        if (isset($row['permissions'])) {
2664
+            $row['permissions'] = (int) $row['permissions'];
2665
+        }
2666
+        if (isset($row['storage'])) {
2667
+            $row['storage'] = (int) $row['storage'];
2668
+        }
2669
+        if (isset($row['stime'])) {
2670
+            $row['stime'] = (int) $row['stime'];
2671
+        }
2672
+        if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
2673
+            // discard expiration date for non-link shares, which might have been
2674
+            // set by ancient bugs
2675
+            $row['expiration'] = null;
2676
+        }
2677
+    }
2678
+
2679
+    /**
2680
+     * format result
2681
+     * @param array $items result
2682
+     * @param string $column is it a file share or a general share ('file_target' or 'item_target')
2683
+     * @param \OCP\Share_Backend $backend sharing backend
2684
+     * @param int $format
2685
+     * @param array $parameters additional format parameters
2686
+     * @return array format result
2687
+     */
2688
+    private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
2689
+        if ($format === self::FORMAT_NONE) {
2690
+            return $items;
2691
+        } else if ($format === self::FORMAT_STATUSES) {
2692
+            $statuses = array();
2693
+            foreach ($items as $item) {
2694
+                if ($item['share_type'] === self::SHARE_TYPE_LINK) {
2695
+                    if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
2696
+                        continue;
2697
+                    }
2698
+                    $statuses[$item[$column]]['link'] = true;
2699
+                } else if (!isset($statuses[$item[$column]])) {
2700
+                    $statuses[$item[$column]]['link'] = false;
2701
+                }
2702
+                if (!empty($item['file_target'])) {
2703
+                    $statuses[$item[$column]]['path'] = $item['path'];
2704
+                }
2705
+            }
2706
+            return $statuses;
2707
+        } else {
2708
+            return $backend->formatItems($items, $format, $parameters);
2709
+        }
2710
+    }
2711
+
2712
+    /**
2713
+     * remove protocol from URL
2714
+     *
2715
+     * @param string $url
2716
+     * @return string
2717
+     */
2718
+    public static function removeProtocolFromUrl($url) {
2719
+        if (strpos($url, 'https://') === 0) {
2720
+            return substr($url, strlen('https://'));
2721
+        } else if (strpos($url, 'http://') === 0) {
2722
+            return substr($url, strlen('http://'));
2723
+        }
2724
+
2725
+        return $url;
2726
+    }
2727
+
2728
+    /**
2729
+     * try http post first with https and then with http as a fallback
2730
+     *
2731
+     * @param string $remoteDomain
2732
+     * @param string $urlSuffix
2733
+     * @param array $fields post parameters
2734
+     * @return array
2735
+     */
2736
+    private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
2737
+        $protocol = 'https://';
2738
+        $result = [
2739
+            'success' => false,
2740
+            'result' => '',
2741
+        ];
2742
+        $try = 0;
2743
+        $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
2744
+        while ($result['success'] === false && $try < 2) {
2745
+            $federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
2746
+            $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
2747
+            $result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields);
2748
+            $try++;
2749
+            $protocol = 'http://';
2750
+        }
2751
+
2752
+        return $result;
2753
+    }
2754
+
2755
+    /**
2756
+     * send server-to-server share to remote server
2757
+     *
2758
+     * @param string $token
2759
+     * @param string $shareWith
2760
+     * @param string $name
2761
+     * @param int $remote_id
2762
+     * @param string $owner
2763
+     * @return bool
2764
+     */
2765
+    private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2766
+
2767
+        list($user, $remote) = Helper::splitUserRemote($shareWith);
2768
+
2769
+        if ($user && $remote) {
2770
+            $url = $remote;
2771
+
2772
+            $local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2773
+
2774
+            $fields = array(
2775
+                'shareWith' => $user,
2776
+                'token' => $token,
2777
+                'name' => $name,
2778
+                'remoteId' => $remote_id,
2779
+                'owner' => $owner,
2780
+                'remote' => $local,
2781
+            );
2782
+
2783
+            $url = self::removeProtocolFromUrl($url);
2784
+            $result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2785
+            $status = json_decode($result['result'], true);
2786
+
2787
+            if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2788
+                \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
2789
+                return true;
2790
+            }
2791
+
2792
+        }
2793
+
2794
+        return false;
2795
+    }
2796
+
2797
+    /**
2798
+     * send server-to-server unshare to remote server
2799
+     *
2800
+     * @param string $remote url
2801
+     * @param int $id share id
2802
+     * @param string $token
2803
+     * @return bool
2804
+     */
2805
+    private static function sendRemoteUnshare($remote, $id, $token) {
2806
+        $url = rtrim($remote, '/');
2807
+        $fields = array('token' => $token, 'format' => 'json');
2808
+        $url = self::removeProtocolFromUrl($url);
2809
+        $result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2810
+        $status = json_decode($result['result'], true);
2811
+
2812
+        return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2813
+    }
2814
+
2815
+    /**
2816
+     * check if user can only share with group members
2817
+     * @return bool
2818
+     */
2819
+    public static function shareWithGroupMembersOnly() {
2820
+        $value = \OC::$server->getAppConfig()->getValue('core', 'shareapi_only_share_with_group_members', 'no');
2821
+        return ($value === 'yes') ? true : false;
2822
+    }
2823
+
2824
+    /**
2825
+     * @return bool
2826
+     */
2827
+    public static function isDefaultExpireDateEnabled() {
2828
+        $defaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
2829
+        return ($defaultExpireDateEnabled === "yes") ? true : false;
2830
+    }
2831
+
2832
+    /**
2833
+     * @return bool
2834
+     */
2835
+    public static function enforceDefaultExpireDate() {
2836
+        $enforceDefaultExpireDate = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
2837
+        return ($enforceDefaultExpireDate === "yes") ? true : false;
2838
+    }
2839
+
2840
+    /**
2841
+     * @return int
2842
+     */
2843
+    public static function getExpireInterval() {
2844
+        return (int)\OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
2845
+    }
2846
+
2847
+    /**
2848
+     * Checks whether the given path is reachable for the given owner
2849
+     *
2850
+     * @param string $path path relative to files
2851
+     * @param string $ownerStorageId storage id of the owner
2852
+     *
2853
+     * @return boolean true if file is reachable, false otherwise
2854
+     */
2855
+    private static function isFileReachable($path, $ownerStorageId) {
2856
+        // if outside the home storage, file is always considered reachable
2857
+        if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2858
+            substr($ownerStorageId, 0, 13) === 'object::user:'
2859
+        )) {
2860
+            return true;
2861
+        }
2862
+
2863
+        // if inside the home storage, the file has to be under "/files/"
2864
+        $path = ltrim($path, '/');
2865
+        if (substr($path, 0, 6) === 'files/') {
2866
+            return true;
2867
+        }
2868
+
2869
+        return false;
2870
+    }
2871
+
2872
+    /**
2873
+     * @param IConfig $config
2874
+     * @return bool
2875
+     */
2876
+    public static function enforcePassword(IConfig $config) {
2877
+        $enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
2878
+        return ($enforcePassword === "yes") ? true : false;
2879
+    }
2880
+
2881
+    /**
2882
+     * Get all share entries, including non-unique group items
2883
+     *
2884
+     * @param string $owner
2885
+     * @return array
2886
+     */
2887
+    public static function getAllSharesForOwner($owner) {
2888
+        $query = 'SELECT * FROM `*PREFIX*share` WHERE `uid_owner` = ?';
2889
+        $result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$owner]);
2890
+        return $result->fetchAll();
2891
+    }
2892
+
2893
+    /**
2894
+     * Get all share entries, including non-unique group items for a file
2895
+     *
2896
+     * @param int $id
2897
+     * @return array
2898
+     */
2899
+    public static function getAllSharesForFileId($id) {
2900
+        $query = 'SELECT * FROM `*PREFIX*share` WHERE `file_source` = ?';
2901
+        $result = \OC::$server->getDatabaseConnection()->executeQuery($query, [$id]);
2902
+        return $result->fetchAll();
2903
+    }
2904
+
2905
+    /**
2906
+     * @param string $password
2907
+     * @throws \Exception
2908
+     */
2909
+    private static function verifyPassword($password) {
2910
+
2911
+        $accepted = true;
2912
+        $message = '';
2913
+        \OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2914
+            'password' => $password,
2915
+            'accepted' => &$accepted,
2916
+            'message' => &$message
2917
+        ]);
2918
+
2919
+        if (!$accepted) {
2920
+            throw new \Exception($message);
2921
+        }
2922
+    }
2923 2923
 }
Please login to merge, or discard this patch.
apps/sharebymail/lib/ShareByMailProvider.php 2 patches
Indentation   +998 added lines, -998 removed lines patch added patch discarded remove patch
@@ -52,1016 +52,1016 @@
 block discarded – undo
52 52
  */
53 53
 class ShareByMailProvider implements IShareProvider {
54 54
 
55
-	/** @var  IDBConnection */
56
-	private $dbConnection;
57
-
58
-	/** @var ILogger */
59
-	private $logger;
60
-
61
-	/** @var ISecureRandom */
62
-	private $secureRandom;
63
-
64
-	/** @var IUserManager */
65
-	private $userManager;
66
-
67
-	/** @var IRootFolder */
68
-	private $rootFolder;
69
-
70
-	/** @var IL10N */
71
-	private $l;
72
-
73
-	/** @var IMailer */
74
-	private $mailer;
75
-
76
-	/** @var IURLGenerator */
77
-	private $urlGenerator;
78
-
79
-	/** @var IManager  */
80
-	private $activityManager;
81
-
82
-	/** @var SettingsManager */
83
-	private $settingsManager;
84
-
85
-	/** @var Defaults */
86
-	private $defaults;
87
-
88
-	/** @var IHasher */
89
-	private $hasher;
90
-
91
-	/** @var  CapabilitiesManager */
92
-	private $capabilitiesManager;
93
-
94
-	/**
95
-	 * Return the identifier of this provider.
96
-	 *
97
-	 * @return string Containing only [a-zA-Z0-9]
98
-	 */
99
-	public function identifier() {
100
-		return 'ocMailShare';
101
-	}
102
-
103
-	/**
104
-	 * DefaultShareProvider constructor.
105
-	 *
106
-	 * @param IDBConnection $connection
107
-	 * @param ISecureRandom $secureRandom
108
-	 * @param IUserManager $userManager
109
-	 * @param IRootFolder $rootFolder
110
-	 * @param IL10N $l
111
-	 * @param ILogger $logger
112
-	 * @param IMailer $mailer
113
-	 * @param IURLGenerator $urlGenerator
114
-	 * @param IManager $activityManager
115
-	 * @param SettingsManager $settingsManager
116
-	 * @param Defaults $defaults
117
-	 * @param IHasher $hasher
118
-	 * @param CapabilitiesManager $capabilitiesManager
119
-	 */
120
-	public function __construct(
121
-		IDBConnection $connection,
122
-		ISecureRandom $secureRandom,
123
-		IUserManager $userManager,
124
-		IRootFolder $rootFolder,
125
-		IL10N $l,
126
-		ILogger $logger,
127
-		IMailer $mailer,
128
-		IURLGenerator $urlGenerator,
129
-		IManager $activityManager,
130
-		SettingsManager $settingsManager,
131
-		Defaults $defaults,
132
-		IHasher $hasher,
133
-		CapabilitiesManager $capabilitiesManager
134
-	) {
135
-		$this->dbConnection = $connection;
136
-		$this->secureRandom = $secureRandom;
137
-		$this->userManager = $userManager;
138
-		$this->rootFolder = $rootFolder;
139
-		$this->l = $l;
140
-		$this->logger = $logger;
141
-		$this->mailer = $mailer;
142
-		$this->urlGenerator = $urlGenerator;
143
-		$this->activityManager = $activityManager;
144
-		$this->settingsManager = $settingsManager;
145
-		$this->defaults = $defaults;
146
-		$this->hasher = $hasher;
147
-		$this->capabilitiesManager = $capabilitiesManager;
148
-	}
149
-
150
-	/**
151
-	 * Share a path
152
-	 *
153
-	 * @param IShare $share
154
-	 * @return IShare The share object
155
-	 * @throws ShareNotFound
156
-	 * @throws \Exception
157
-	 */
158
-	public function create(IShare $share) {
159
-
160
-		$shareWith = $share->getSharedWith();
161
-		/*
55
+    /** @var  IDBConnection */
56
+    private $dbConnection;
57
+
58
+    /** @var ILogger */
59
+    private $logger;
60
+
61
+    /** @var ISecureRandom */
62
+    private $secureRandom;
63
+
64
+    /** @var IUserManager */
65
+    private $userManager;
66
+
67
+    /** @var IRootFolder */
68
+    private $rootFolder;
69
+
70
+    /** @var IL10N */
71
+    private $l;
72
+
73
+    /** @var IMailer */
74
+    private $mailer;
75
+
76
+    /** @var IURLGenerator */
77
+    private $urlGenerator;
78
+
79
+    /** @var IManager  */
80
+    private $activityManager;
81
+
82
+    /** @var SettingsManager */
83
+    private $settingsManager;
84
+
85
+    /** @var Defaults */
86
+    private $defaults;
87
+
88
+    /** @var IHasher */
89
+    private $hasher;
90
+
91
+    /** @var  CapabilitiesManager */
92
+    private $capabilitiesManager;
93
+
94
+    /**
95
+     * Return the identifier of this provider.
96
+     *
97
+     * @return string Containing only [a-zA-Z0-9]
98
+     */
99
+    public function identifier() {
100
+        return 'ocMailShare';
101
+    }
102
+
103
+    /**
104
+     * DefaultShareProvider constructor.
105
+     *
106
+     * @param IDBConnection $connection
107
+     * @param ISecureRandom $secureRandom
108
+     * @param IUserManager $userManager
109
+     * @param IRootFolder $rootFolder
110
+     * @param IL10N $l
111
+     * @param ILogger $logger
112
+     * @param IMailer $mailer
113
+     * @param IURLGenerator $urlGenerator
114
+     * @param IManager $activityManager
115
+     * @param SettingsManager $settingsManager
116
+     * @param Defaults $defaults
117
+     * @param IHasher $hasher
118
+     * @param CapabilitiesManager $capabilitiesManager
119
+     */
120
+    public function __construct(
121
+        IDBConnection $connection,
122
+        ISecureRandom $secureRandom,
123
+        IUserManager $userManager,
124
+        IRootFolder $rootFolder,
125
+        IL10N $l,
126
+        ILogger $logger,
127
+        IMailer $mailer,
128
+        IURLGenerator $urlGenerator,
129
+        IManager $activityManager,
130
+        SettingsManager $settingsManager,
131
+        Defaults $defaults,
132
+        IHasher $hasher,
133
+        CapabilitiesManager $capabilitiesManager
134
+    ) {
135
+        $this->dbConnection = $connection;
136
+        $this->secureRandom = $secureRandom;
137
+        $this->userManager = $userManager;
138
+        $this->rootFolder = $rootFolder;
139
+        $this->l = $l;
140
+        $this->logger = $logger;
141
+        $this->mailer = $mailer;
142
+        $this->urlGenerator = $urlGenerator;
143
+        $this->activityManager = $activityManager;
144
+        $this->settingsManager = $settingsManager;
145
+        $this->defaults = $defaults;
146
+        $this->hasher = $hasher;
147
+        $this->capabilitiesManager = $capabilitiesManager;
148
+    }
149
+
150
+    /**
151
+     * Share a path
152
+     *
153
+     * @param IShare $share
154
+     * @return IShare The share object
155
+     * @throws ShareNotFound
156
+     * @throws \Exception
157
+     */
158
+    public function create(IShare $share) {
159
+
160
+        $shareWith = $share->getSharedWith();
161
+        /*
162 162
 		 * Check if file is not already shared with the remote user
163 163
 		 */
164
-		$alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0);
165
-		if (!empty($alreadyShared)) {
166
-			$message = 'Sharing %s failed, this item is already shared with %s';
167
-			$message_t = $this->l->t('Sharing %s failed, this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
168
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
169
-			throw new \Exception($message_t);
170
-		}
171
-
172
-		// if the admin enforces a password for all mail shares we create a
173
-		// random password and send it to the recipient
174
-		$password = '';
175
-		$passwordEnforced = $this->settingsManager->enforcePasswordProtection();
176
-		if ($passwordEnforced) {
177
-			$password = $this->autoGeneratePassword($share);
178
-		}
179
-
180
-		$shareId = $this->createMailShare($share);
181
-		$send = $this->sendPassword($share, $password);
182
-		if ($passwordEnforced && $send === false) {
183
-			$this->sendPasswordToOwner($share, $password);
184
-		}
185
-
186
-		$this->createShareActivity($share);
187
-		$data = $this->getRawShare($shareId);
188
-
189
-		return $this->createShareObject($data);
190
-
191
-	}
192
-
193
-	/**
194
-	 * auto generate password in case of password enforcement on mail shares
195
-	 *
196
-	 * @param IShare $share
197
-	 * @return string
198
-	 * @throws \Exception
199
-	 */
200
-	protected function autoGeneratePassword($share) {
201
-		$initiatorUser = $this->userManager->get($share->getSharedBy());
202
-		$initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
203
-		$allowPasswordByMail = $this->settingsManager->sendPasswordByMail();
204
-
205
-		if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
206
-			throw new \Exception(
207
-				$this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
208
-			);
209
-		}
210
-
211
-		$passwordPolicy = $this->getPasswordPolicy();
212
-		$passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS;
213
-		$passwordLength = 8;
214
-		if (!empty($passwordPolicy)) {
215
-			$passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength;
216
-			$passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : '';
217
-		}
218
-
219
-		$password = $this->secureRandom->generate($passwordLength, $passwordCharset);
220
-
221
-		$share->setPassword($this->hasher->hash($password));
222
-
223
-		return $password;
224
-	}
225
-
226
-	/**
227
-	 * get password policy
228
-	 *
229
-	 * @return array
230
-	 */
231
-	protected function getPasswordPolicy() {
232
-		$capabilities = $this->capabilitiesManager->getCapabilities();
233
-		if (isset($capabilities['password_policy'])) {
234
-			return $capabilities['password_policy'];
235
-		}
236
-
237
-		return [];
238
-	}
239
-
240
-	/**
241
-	 * create activity if a file/folder was shared by mail
242
-	 *
243
-	 * @param IShare $share
244
-	 */
245
-	protected function createShareActivity(IShare $share) {
246
-
247
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
248
-
249
-		$this->publishActivity(
250
-			Activity::SUBJECT_SHARED_EMAIL_SELF,
251
-			[$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
252
-			$share->getSharedBy(),
253
-			$share->getNode()->getId(),
254
-			$userFolder->getRelativePath($share->getNode()->getPath())
255
-		);
256
-
257
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
258
-			$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
259
-			$fileId = $share->getNode()->getId();
260
-			$nodes = $ownerFolder->getById($fileId);
261
-			$ownerPath = $nodes[0]->getPath();
262
-			$this->publishActivity(
263
-				Activity::SUBJECT_SHARED_EMAIL_BY,
264
-				[$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
265
-				$share->getShareOwner(),
266
-				$fileId,
267
-				$ownerFolder->getRelativePath($ownerPath)
268
-			);
269
-		}
270
-
271
-	}
272
-
273
-	/**
274
-	 * create activity if a file/folder was shared by mail
275
-	 *
276
-	 * @param IShare $share
277
-	 * @param string $sharedWith
278
-	 * @param bool $sendToSelf
279
-	 */
280
-	protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {
281
-
282
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
283
-
284
-		if ($sendToSelf) {
285
-			$this->publishActivity(
286
-				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
287
-				[$userFolder->getRelativePath($share->getNode()->getPath())],
288
-				$share->getSharedBy(),
289
-				$share->getNode()->getId(),
290
-				$userFolder->getRelativePath($share->getNode()->getPath())
291
-			);
292
-		} else {
293
-			$this->publishActivity(
294
-				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
295
-				[$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
296
-				$share->getSharedBy(),
297
-				$share->getNode()->getId(),
298
-				$userFolder->getRelativePath($share->getNode()->getPath())
299
-			);
300
-		}
301
-	}
302
-
303
-
304
-	/**
305
-	 * publish activity if a file/folder was shared by mail
306
-	 *
307
-	 * @param $subject
308
-	 * @param $parameters
309
-	 * @param $affectedUser
310
-	 * @param $fileId
311
-	 * @param $filePath
312
-	 */
313
-	protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) {
314
-		$event = $this->activityManager->generateEvent();
315
-		$event->setApp('sharebymail')
316
-			->setType('shared')
317
-			->setSubject($subject, $parameters)
318
-			->setAffectedUser($affectedUser)
319
-			->setObject('files', $fileId, $filePath);
320
-		$this->activityManager->publish($event);
321
-
322
-	}
323
-
324
-	/**
325
-	 * @param IShare $share
326
-	 * @return int
327
-	 * @throws \Exception
328
-	 */
329
-	protected function createMailShare(IShare $share) {
330
-		$share->setToken($this->generateToken());
331
-		$shareId = $this->addShareToDB(
332
-			$share->getNodeId(),
333
-			$share->getNodeType(),
334
-			$share->getSharedWith(),
335
-			$share->getSharedBy(),
336
-			$share->getShareOwner(),
337
-			$share->getPermissions(),
338
-			$share->getToken(),
339
-			$share->getPassword()
340
-		);
341
-
342
-		try {
343
-			$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
344
-				['token' => $share->getToken()]);
345
-			$this->sendMailNotification(
346
-				$share->getNode()->getName(),
347
-				$link,
348
-				$share->getSharedBy(),
349
-				$share->getSharedWith()
350
-			);
351
-		} catch (HintException $hintException) {
352
-			$this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
353
-			$this->removeShareFromTable($shareId);
354
-			throw $hintException;
355
-		} catch (\Exception $e) {
356
-			$this->logger->error('Failed to send share by email: ' . $e->getMessage());
357
-			$this->removeShareFromTable($shareId);
358
-			throw new HintException('Failed to send share by mail',
359
-				$this->l->t('Failed to send share by email'));
360
-		}
361
-
362
-		return $shareId;
363
-
364
-	}
365
-
366
-	/**
367
-	 * @param string $filename
368
-	 * @param string $link
369
-	 * @param string $initiator
370
-	 * @param string $shareWith
371
-	 * @throws \Exception If mail couldn't be sent
372
-	 */
373
-	protected function sendMailNotification($filename,
374
-											$link,
375
-											$initiator,
376
-											$shareWith) {
377
-		$initiatorUser = $this->userManager->get($initiator);
378
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
379
-		$subject = (string)$this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename));
380
-
381
-		$message = $this->mailer->createMessage();
382
-
383
-		$emailTemplate = $this->mailer->createEMailTemplate();
384
-
385
-		$emailTemplate->addHeader();
386
-		$emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
387
-		$text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
388
-
389
-		$emailTemplate->addBodyText(
390
-			$text . ' ' . $this->l->t('Click the button below to open it.'),
391
-			$text
392
-		);
393
-		$emailTemplate->addBodyButton(
394
-			$this->l->t('Open »%s«', [$filename]),
395
-			$link
396
-		);
397
-
398
-		$message->setTo([$shareWith]);
399
-
400
-		// The "From" contains the sharers name
401
-		$instanceName = $this->defaults->getName();
402
-		$senderName = $this->l->t(
403
-			'%s via %s',
404
-			[
405
-				$initiatorDisplayName,
406
-				$instanceName
407
-			]
408
-		);
409
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
410
-
411
-		// The "Reply-To" is set to the sharer if an mail address is configured
412
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
413
-		$initiatorEmail = $initiatorUser->getEMailAddress();
414
-		if($initiatorEmail !== null) {
415
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
416
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
417
-		} else {
418
-			$emailTemplate->addFooter();
419
-		}
420
-
421
-		$message->setSubject($subject);
422
-		$message->setPlainBody($emailTemplate->renderText());
423
-		$message->setHtmlBody($emailTemplate->renderHtml());
424
-		$this->mailer->send($message);
425
-	}
426
-
427
-	/**
428
-	 * send password to recipient of a mail share
429
-	 *
430
-	 * @param IShare $share
431
-	 * @param string $password
432
-	 * @return bool
433
-	 */
434
-	protected function sendPassword(IShare $share, $password) {
435
-
436
-		$filename = $share->getNode()->getName();
437
-		$initiator = $share->getSharedBy();
438
-		$shareWith = $share->getSharedWith();
439
-
440
-		if ($password === '' || $this->settingsManager->sendPasswordByMail() === false) {
441
-			return false;
442
-		}
443
-
444
-		$initiatorUser = $this->userManager->get($initiator);
445
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
446
-		$initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
447
-
448
-		$subject = (string)$this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
449
-		$plainBodyPart = $this->l->t("%s shared »%s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
450
-		$htmlBodyPart = $this->l->t('%s shared »%s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
451
-
452
-		$message = $this->mailer->createMessage();
453
-
454
-		$emailTemplate = $this->mailer->createEMailTemplate();
455
-		$emailTemplate->addHeader();
456
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
457
-		$emailTemplate->addBodyText($htmlBodyPart, $plainBodyPart);
458
-		$emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));
459
-
460
-		// The "From" contains the sharers name
461
-		$instanceName = $this->defaults->getName();
462
-		$senderName = $this->l->t(
463
-			'%s via %s',
464
-			[
465
-				$initiatorDisplayName,
466
-				$instanceName
467
-			]
468
-		);
469
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
470
-		if ($initiatorEmailAddress !== null) {
471
-			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
472
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
473
-		} else {
474
-			$emailTemplate->addFooter();
475
-		}
476
-
477
-		$message->setTo([$shareWith]);
478
-		$message->setSubject($subject);
479
-		$message->setBody($emailTemplate->renderText(), 'text/plain');
480
-		$message->setHtmlBody($emailTemplate->renderHtml());
481
-		$this->mailer->send($message);
482
-
483
-		$this->createPasswordSendActivity($share, $shareWith, false);
484
-
485
-		return true;
486
-	}
487
-
488
-	/**
489
-	 * send auto generated password to the owner. This happens if the admin enforces
490
-	 * a password for mail shares and forbid to send the password by mail to the recipient
491
-	 *
492
-	 * @param IShare $share
493
-	 * @param string $password
494
-	 * @return bool
495
-	 * @throws \Exception
496
-	 */
497
-	protected function sendPasswordToOwner(IShare $share, $password) {
498
-
499
-		$filename = $share->getNode()->getName();
500
-		$initiator = $this->userManager->get($share->getSharedBy());
501
-		$initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
502
-		$initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
503
-		$shareWith = $share->getSharedWith();
504
-
505
-		if ($initiatorEMailAddress === null) {
506
-			throw new \Exception(
507
-				$this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
508
-			);
509
-		}
510
-
511
-		$subject = (string)$this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]);
512
-		$bodyPart = $this->l->t("You just shared »%s« with %s. The share was already send to the recipient. Due to the security policies defined by the administrator of %s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.", [$filename, $shareWith, $this->defaults->getName()]);
513
-
514
-		$message = $this->mailer->createMessage();
515
-		$emailTemplate = $this->mailer->createEMailTemplate();
516
-
517
-		$emailTemplate->addHeader();
518
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
519
-		$emailTemplate->addBodyText($bodyPart);
520
-		$emailTemplate->addBodyText($this->l->t('This is the password: %s', [$password]));
521
-		$emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
522
-		$emailTemplate->addFooter();
523
-
524
-		if ($initiatorEMailAddress) {
525
-			$message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]);
526
-		}
527
-		$message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
528
-		$message->setSubject($subject);
529
-		$message->setBody($emailTemplate->renderText(), 'text/plain');
530
-		$message->setHtmlBody($emailTemplate->renderHtml());
531
-		$this->mailer->send($message);
532
-
533
-		$this->createPasswordSendActivity($share, $shareWith, true);
534
-
535
-		return true;
536
-	}
537
-
538
-	/**
539
-	 * generate share token
540
-	 *
541
-	 * @return string
542
-	 */
543
-	protected function generateToken($size = 15) {
544
-		$token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
545
-		return $token;
546
-	}
547
-
548
-	/**
549
-	 * Get all children of this share
550
-	 *
551
-	 * @param IShare $parent
552
-	 * @return IShare[]
553
-	 */
554
-	public function getChildren(IShare $parent) {
555
-		$children = [];
556
-
557
-		$qb = $this->dbConnection->getQueryBuilder();
558
-		$qb->select('*')
559
-			->from('share')
560
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
561
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
562
-			->orderBy('id');
563
-
564
-		$cursor = $qb->execute();
565
-		while($data = $cursor->fetch()) {
566
-			$children[] = $this->createShareObject($data);
567
-		}
568
-		$cursor->closeCursor();
569
-
570
-		return $children;
571
-	}
572
-
573
-	/**
574
-	 * add share to the database and return the ID
575
-	 *
576
-	 * @param int $itemSource
577
-	 * @param string $itemType
578
-	 * @param string $shareWith
579
-	 * @param string $sharedBy
580
-	 * @param string $uidOwner
581
-	 * @param int $permissions
582
-	 * @param string $token
583
-	 * @return int
584
-	 */
585
-	protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password) {
586
-		$qb = $this->dbConnection->getQueryBuilder();
587
-		$qb->insert('share')
588
-			->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
589
-			->setValue('item_type', $qb->createNamedParameter($itemType))
590
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
591
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
592
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
593
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
594
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
595
-			->setValue('permissions', $qb->createNamedParameter($permissions))
596
-			->setValue('token', $qb->createNamedParameter($token))
597
-			->setValue('password', $qb->createNamedParameter($password))
598
-			->setValue('stime', $qb->createNamedParameter(time()));
599
-
600
-		/*
164
+        $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0);
165
+        if (!empty($alreadyShared)) {
166
+            $message = 'Sharing %s failed, this item is already shared with %s';
167
+            $message_t = $this->l->t('Sharing %s failed, this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
168
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
169
+            throw new \Exception($message_t);
170
+        }
171
+
172
+        // if the admin enforces a password for all mail shares we create a
173
+        // random password and send it to the recipient
174
+        $password = '';
175
+        $passwordEnforced = $this->settingsManager->enforcePasswordProtection();
176
+        if ($passwordEnforced) {
177
+            $password = $this->autoGeneratePassword($share);
178
+        }
179
+
180
+        $shareId = $this->createMailShare($share);
181
+        $send = $this->sendPassword($share, $password);
182
+        if ($passwordEnforced && $send === false) {
183
+            $this->sendPasswordToOwner($share, $password);
184
+        }
185
+
186
+        $this->createShareActivity($share);
187
+        $data = $this->getRawShare($shareId);
188
+
189
+        return $this->createShareObject($data);
190
+
191
+    }
192
+
193
+    /**
194
+     * auto generate password in case of password enforcement on mail shares
195
+     *
196
+     * @param IShare $share
197
+     * @return string
198
+     * @throws \Exception
199
+     */
200
+    protected function autoGeneratePassword($share) {
201
+        $initiatorUser = $this->userManager->get($share->getSharedBy());
202
+        $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
203
+        $allowPasswordByMail = $this->settingsManager->sendPasswordByMail();
204
+
205
+        if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
206
+            throw new \Exception(
207
+                $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
208
+            );
209
+        }
210
+
211
+        $passwordPolicy = $this->getPasswordPolicy();
212
+        $passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS;
213
+        $passwordLength = 8;
214
+        if (!empty($passwordPolicy)) {
215
+            $passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength;
216
+            $passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : '';
217
+        }
218
+
219
+        $password = $this->secureRandom->generate($passwordLength, $passwordCharset);
220
+
221
+        $share->setPassword($this->hasher->hash($password));
222
+
223
+        return $password;
224
+    }
225
+
226
+    /**
227
+     * get password policy
228
+     *
229
+     * @return array
230
+     */
231
+    protected function getPasswordPolicy() {
232
+        $capabilities = $this->capabilitiesManager->getCapabilities();
233
+        if (isset($capabilities['password_policy'])) {
234
+            return $capabilities['password_policy'];
235
+        }
236
+
237
+        return [];
238
+    }
239
+
240
+    /**
241
+     * create activity if a file/folder was shared by mail
242
+     *
243
+     * @param IShare $share
244
+     */
245
+    protected function createShareActivity(IShare $share) {
246
+
247
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
248
+
249
+        $this->publishActivity(
250
+            Activity::SUBJECT_SHARED_EMAIL_SELF,
251
+            [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
252
+            $share->getSharedBy(),
253
+            $share->getNode()->getId(),
254
+            $userFolder->getRelativePath($share->getNode()->getPath())
255
+        );
256
+
257
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
258
+            $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
259
+            $fileId = $share->getNode()->getId();
260
+            $nodes = $ownerFolder->getById($fileId);
261
+            $ownerPath = $nodes[0]->getPath();
262
+            $this->publishActivity(
263
+                Activity::SUBJECT_SHARED_EMAIL_BY,
264
+                [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
265
+                $share->getShareOwner(),
266
+                $fileId,
267
+                $ownerFolder->getRelativePath($ownerPath)
268
+            );
269
+        }
270
+
271
+    }
272
+
273
+    /**
274
+     * create activity if a file/folder was shared by mail
275
+     *
276
+     * @param IShare $share
277
+     * @param string $sharedWith
278
+     * @param bool $sendToSelf
279
+     */
280
+    protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {
281
+
282
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
283
+
284
+        if ($sendToSelf) {
285
+            $this->publishActivity(
286
+                Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
287
+                [$userFolder->getRelativePath($share->getNode()->getPath())],
288
+                $share->getSharedBy(),
289
+                $share->getNode()->getId(),
290
+                $userFolder->getRelativePath($share->getNode()->getPath())
291
+            );
292
+        } else {
293
+            $this->publishActivity(
294
+                Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
295
+                [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
296
+                $share->getSharedBy(),
297
+                $share->getNode()->getId(),
298
+                $userFolder->getRelativePath($share->getNode()->getPath())
299
+            );
300
+        }
301
+    }
302
+
303
+
304
+    /**
305
+     * publish activity if a file/folder was shared by mail
306
+     *
307
+     * @param $subject
308
+     * @param $parameters
309
+     * @param $affectedUser
310
+     * @param $fileId
311
+     * @param $filePath
312
+     */
313
+    protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) {
314
+        $event = $this->activityManager->generateEvent();
315
+        $event->setApp('sharebymail')
316
+            ->setType('shared')
317
+            ->setSubject($subject, $parameters)
318
+            ->setAffectedUser($affectedUser)
319
+            ->setObject('files', $fileId, $filePath);
320
+        $this->activityManager->publish($event);
321
+
322
+    }
323
+
324
+    /**
325
+     * @param IShare $share
326
+     * @return int
327
+     * @throws \Exception
328
+     */
329
+    protected function createMailShare(IShare $share) {
330
+        $share->setToken($this->generateToken());
331
+        $shareId = $this->addShareToDB(
332
+            $share->getNodeId(),
333
+            $share->getNodeType(),
334
+            $share->getSharedWith(),
335
+            $share->getSharedBy(),
336
+            $share->getShareOwner(),
337
+            $share->getPermissions(),
338
+            $share->getToken(),
339
+            $share->getPassword()
340
+        );
341
+
342
+        try {
343
+            $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
344
+                ['token' => $share->getToken()]);
345
+            $this->sendMailNotification(
346
+                $share->getNode()->getName(),
347
+                $link,
348
+                $share->getSharedBy(),
349
+                $share->getSharedWith()
350
+            );
351
+        } catch (HintException $hintException) {
352
+            $this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
353
+            $this->removeShareFromTable($shareId);
354
+            throw $hintException;
355
+        } catch (\Exception $e) {
356
+            $this->logger->error('Failed to send share by email: ' . $e->getMessage());
357
+            $this->removeShareFromTable($shareId);
358
+            throw new HintException('Failed to send share by mail',
359
+                $this->l->t('Failed to send share by email'));
360
+        }
361
+
362
+        return $shareId;
363
+
364
+    }
365
+
366
+    /**
367
+     * @param string $filename
368
+     * @param string $link
369
+     * @param string $initiator
370
+     * @param string $shareWith
371
+     * @throws \Exception If mail couldn't be sent
372
+     */
373
+    protected function sendMailNotification($filename,
374
+                                            $link,
375
+                                            $initiator,
376
+                                            $shareWith) {
377
+        $initiatorUser = $this->userManager->get($initiator);
378
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
379
+        $subject = (string)$this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename));
380
+
381
+        $message = $this->mailer->createMessage();
382
+
383
+        $emailTemplate = $this->mailer->createEMailTemplate();
384
+
385
+        $emailTemplate->addHeader();
386
+        $emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
387
+        $text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
388
+
389
+        $emailTemplate->addBodyText(
390
+            $text . ' ' . $this->l->t('Click the button below to open it.'),
391
+            $text
392
+        );
393
+        $emailTemplate->addBodyButton(
394
+            $this->l->t('Open »%s«', [$filename]),
395
+            $link
396
+        );
397
+
398
+        $message->setTo([$shareWith]);
399
+
400
+        // The "From" contains the sharers name
401
+        $instanceName = $this->defaults->getName();
402
+        $senderName = $this->l->t(
403
+            '%s via %s',
404
+            [
405
+                $initiatorDisplayName,
406
+                $instanceName
407
+            ]
408
+        );
409
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
410
+
411
+        // The "Reply-To" is set to the sharer if an mail address is configured
412
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
413
+        $initiatorEmail = $initiatorUser->getEMailAddress();
414
+        if($initiatorEmail !== null) {
415
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
416
+            $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
417
+        } else {
418
+            $emailTemplate->addFooter();
419
+        }
420
+
421
+        $message->setSubject($subject);
422
+        $message->setPlainBody($emailTemplate->renderText());
423
+        $message->setHtmlBody($emailTemplate->renderHtml());
424
+        $this->mailer->send($message);
425
+    }
426
+
427
+    /**
428
+     * send password to recipient of a mail share
429
+     *
430
+     * @param IShare $share
431
+     * @param string $password
432
+     * @return bool
433
+     */
434
+    protected function sendPassword(IShare $share, $password) {
435
+
436
+        $filename = $share->getNode()->getName();
437
+        $initiator = $share->getSharedBy();
438
+        $shareWith = $share->getSharedWith();
439
+
440
+        if ($password === '' || $this->settingsManager->sendPasswordByMail() === false) {
441
+            return false;
442
+        }
443
+
444
+        $initiatorUser = $this->userManager->get($initiator);
445
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
446
+        $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
447
+
448
+        $subject = (string)$this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
449
+        $plainBodyPart = $this->l->t("%s shared »%s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
450
+        $htmlBodyPart = $this->l->t('%s shared »%s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
451
+
452
+        $message = $this->mailer->createMessage();
453
+
454
+        $emailTemplate = $this->mailer->createEMailTemplate();
455
+        $emailTemplate->addHeader();
456
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
457
+        $emailTemplate->addBodyText($htmlBodyPart, $plainBodyPart);
458
+        $emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));
459
+
460
+        // The "From" contains the sharers name
461
+        $instanceName = $this->defaults->getName();
462
+        $senderName = $this->l->t(
463
+            '%s via %s',
464
+            [
465
+                $initiatorDisplayName,
466
+                $instanceName
467
+            ]
468
+        );
469
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
470
+        if ($initiatorEmailAddress !== null) {
471
+            $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
472
+            $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
473
+        } else {
474
+            $emailTemplate->addFooter();
475
+        }
476
+
477
+        $message->setTo([$shareWith]);
478
+        $message->setSubject($subject);
479
+        $message->setBody($emailTemplate->renderText(), 'text/plain');
480
+        $message->setHtmlBody($emailTemplate->renderHtml());
481
+        $this->mailer->send($message);
482
+
483
+        $this->createPasswordSendActivity($share, $shareWith, false);
484
+
485
+        return true;
486
+    }
487
+
488
+    /**
489
+     * send auto generated password to the owner. This happens if the admin enforces
490
+     * a password for mail shares and forbid to send the password by mail to the recipient
491
+     *
492
+     * @param IShare $share
493
+     * @param string $password
494
+     * @return bool
495
+     * @throws \Exception
496
+     */
497
+    protected function sendPasswordToOwner(IShare $share, $password) {
498
+
499
+        $filename = $share->getNode()->getName();
500
+        $initiator = $this->userManager->get($share->getSharedBy());
501
+        $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
502
+        $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
503
+        $shareWith = $share->getSharedWith();
504
+
505
+        if ($initiatorEMailAddress === null) {
506
+            throw new \Exception(
507
+                $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
508
+            );
509
+        }
510
+
511
+        $subject = (string)$this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]);
512
+        $bodyPart = $this->l->t("You just shared »%s« with %s. The share was already send to the recipient. Due to the security policies defined by the administrator of %s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.", [$filename, $shareWith, $this->defaults->getName()]);
513
+
514
+        $message = $this->mailer->createMessage();
515
+        $emailTemplate = $this->mailer->createEMailTemplate();
516
+
517
+        $emailTemplate->addHeader();
518
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
519
+        $emailTemplate->addBodyText($bodyPart);
520
+        $emailTemplate->addBodyText($this->l->t('This is the password: %s', [$password]));
521
+        $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
522
+        $emailTemplate->addFooter();
523
+
524
+        if ($initiatorEMailAddress) {
525
+            $message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]);
526
+        }
527
+        $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
528
+        $message->setSubject($subject);
529
+        $message->setBody($emailTemplate->renderText(), 'text/plain');
530
+        $message->setHtmlBody($emailTemplate->renderHtml());
531
+        $this->mailer->send($message);
532
+
533
+        $this->createPasswordSendActivity($share, $shareWith, true);
534
+
535
+        return true;
536
+    }
537
+
538
+    /**
539
+     * generate share token
540
+     *
541
+     * @return string
542
+     */
543
+    protected function generateToken($size = 15) {
544
+        $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
545
+        return $token;
546
+    }
547
+
548
+    /**
549
+     * Get all children of this share
550
+     *
551
+     * @param IShare $parent
552
+     * @return IShare[]
553
+     */
554
+    public function getChildren(IShare $parent) {
555
+        $children = [];
556
+
557
+        $qb = $this->dbConnection->getQueryBuilder();
558
+        $qb->select('*')
559
+            ->from('share')
560
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
561
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
562
+            ->orderBy('id');
563
+
564
+        $cursor = $qb->execute();
565
+        while($data = $cursor->fetch()) {
566
+            $children[] = $this->createShareObject($data);
567
+        }
568
+        $cursor->closeCursor();
569
+
570
+        return $children;
571
+    }
572
+
573
+    /**
574
+     * add share to the database and return the ID
575
+     *
576
+     * @param int $itemSource
577
+     * @param string $itemType
578
+     * @param string $shareWith
579
+     * @param string $sharedBy
580
+     * @param string $uidOwner
581
+     * @param int $permissions
582
+     * @param string $token
583
+     * @return int
584
+     */
585
+    protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password) {
586
+        $qb = $this->dbConnection->getQueryBuilder();
587
+        $qb->insert('share')
588
+            ->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
589
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
590
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
591
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
592
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
593
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
594
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
595
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
596
+            ->setValue('token', $qb->createNamedParameter($token))
597
+            ->setValue('password', $qb->createNamedParameter($password))
598
+            ->setValue('stime', $qb->createNamedParameter(time()));
599
+
600
+        /*
601 601
 		 * Added to fix https://github.com/owncloud/core/issues/22215
602 602
 		 * Can be removed once we get rid of ajax/share.php
603 603
 		 */
604
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
604
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
605 605
 
606
-		$qb->execute();
607
-		$id = $qb->getLastInsertId();
606
+        $qb->execute();
607
+        $id = $qb->getLastInsertId();
608 608
 
609
-		return (int)$id;
610
-	}
609
+        return (int)$id;
610
+    }
611 611
 
612
-	/**
613
-	 * Update a share
614
-	 *
615
-	 * @param IShare $share
616
-	 * @param string|null $plainTextPassword
617
-	 * @return IShare The share object
618
-	 */
619
-	public function update(IShare $share, $plainTextPassword = null) {
612
+    /**
613
+     * Update a share
614
+     *
615
+     * @param IShare $share
616
+     * @param string|null $plainTextPassword
617
+     * @return IShare The share object
618
+     */
619
+    public function update(IShare $share, $plainTextPassword = null) {
620 620
 
621
-		$originalShare = $this->getShareById($share->getId());
621
+        $originalShare = $this->getShareById($share->getId());
622 622
 
623
-		// a real password was given
624
-		$validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
623
+        // a real password was given
624
+        $validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
625 625
 
626
-		if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
627
-			$this->sendPassword($share, $plainTextPassword);
628
-		}
629
-		/*
626
+        if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
627
+            $this->sendPassword($share, $plainTextPassword);
628
+        }
629
+        /*
630 630
 		 * We allow updating the permissions and password of mail shares
631 631
 		 */
632
-		$qb = $this->dbConnection->getQueryBuilder();
633
-		$qb->update('share')
634
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
635
-			->set('permissions', $qb->createNamedParameter($share->getPermissions()))
636
-			->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
637
-			->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
638
-			->set('password', $qb->createNamedParameter($share->getPassword()))
639
-			->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
640
-			->execute();
641
-
642
-		return $share;
643
-	}
644
-
645
-	/**
646
-	 * @inheritdoc
647
-	 */
648
-	public function move(IShare $share, $recipient) {
649
-		/**
650
-		 * nothing to do here, mail shares are only outgoing shares
651
-		 */
652
-		return $share;
653
-	}
654
-
655
-	/**
656
-	 * Delete a share (owner unShares the file)
657
-	 *
658
-	 * @param IShare $share
659
-	 */
660
-	public function delete(IShare $share) {
661
-		$this->removeShareFromTable($share->getId());
662
-	}
663
-
664
-	/**
665
-	 * @inheritdoc
666
-	 */
667
-	public function deleteFromSelf(IShare $share, $recipient) {
668
-		// nothing to do here, mail shares are only outgoing shares
669
-		return;
670
-	}
671
-
672
-	/**
673
-	 * @inheritdoc
674
-	 */
675
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
676
-		$qb = $this->dbConnection->getQueryBuilder();
677
-		$qb->select('*')
678
-			->from('share');
679
-
680
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
681
-
682
-		/**
683
-		 * Reshares for this user are shares where they are the owner.
684
-		 */
685
-		if ($reshares === false) {
686
-			//Special case for old shares created via the web UI
687
-			$or1 = $qb->expr()->andX(
688
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
689
-				$qb->expr()->isNull('uid_initiator')
690
-			);
691
-
692
-			$qb->andWhere(
693
-				$qb->expr()->orX(
694
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
695
-					$or1
696
-				)
697
-			);
698
-		} else {
699
-			$qb->andWhere(
700
-				$qb->expr()->orX(
701
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
702
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
703
-				)
704
-			);
705
-		}
706
-
707
-		if ($node !== null) {
708
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
709
-		}
710
-
711
-		if ($limit !== -1) {
712
-			$qb->setMaxResults($limit);
713
-		}
714
-
715
-		$qb->setFirstResult($offset);
716
-		$qb->orderBy('id');
717
-
718
-		$cursor = $qb->execute();
719
-		$shares = [];
720
-		while($data = $cursor->fetch()) {
721
-			$shares[] = $this->createShareObject($data);
722
-		}
723
-		$cursor->closeCursor();
724
-
725
-		return $shares;
726
-	}
727
-
728
-	/**
729
-	 * @inheritdoc
730
-	 */
731
-	public function getShareById($id, $recipientId = null) {
732
-		$qb = $this->dbConnection->getQueryBuilder();
733
-
734
-		$qb->select('*')
735
-			->from('share')
736
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
737
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
738
-
739
-		$cursor = $qb->execute();
740
-		$data = $cursor->fetch();
741
-		$cursor->closeCursor();
742
-
743
-		if ($data === false) {
744
-			throw new ShareNotFound();
745
-		}
746
-
747
-		try {
748
-			$share = $this->createShareObject($data);
749
-		} catch (InvalidShare $e) {
750
-			throw new ShareNotFound();
751
-		}
752
-
753
-		return $share;
754
-	}
755
-
756
-	/**
757
-	 * Get shares for a given path
758
-	 *
759
-	 * @param \OCP\Files\Node $path
760
-	 * @return IShare[]
761
-	 */
762
-	public function getSharesByPath(Node $path) {
763
-		$qb = $this->dbConnection->getQueryBuilder();
764
-
765
-		$cursor = $qb->select('*')
766
-			->from('share')
767
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
768
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
769
-			->execute();
770
-
771
-		$shares = [];
772
-		while($data = $cursor->fetch()) {
773
-			$shares[] = $this->createShareObject($data);
774
-		}
775
-		$cursor->closeCursor();
776
-
777
-		return $shares;
778
-	}
779
-
780
-	/**
781
-	 * @inheritdoc
782
-	 */
783
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
784
-		/** @var IShare[] $shares */
785
-		$shares = [];
786
-
787
-		//Get shares directly with this user
788
-		$qb = $this->dbConnection->getQueryBuilder();
789
-		$qb->select('*')
790
-			->from('share');
791
-
792
-		// Order by id
793
-		$qb->orderBy('id');
794
-
795
-		// Set limit and offset
796
-		if ($limit !== -1) {
797
-			$qb->setMaxResults($limit);
798
-		}
799
-		$qb->setFirstResult($offset);
800
-
801
-		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
802
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
803
-
804
-		// Filter by node if provided
805
-		if ($node !== null) {
806
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
807
-		}
808
-
809
-		$cursor = $qb->execute();
810
-
811
-		while($data = $cursor->fetch()) {
812
-			$shares[] = $this->createShareObject($data);
813
-		}
814
-		$cursor->closeCursor();
815
-
816
-
817
-		return $shares;
818
-	}
819
-
820
-	/**
821
-	 * Get a share by token
822
-	 *
823
-	 * @param string $token
824
-	 * @return IShare
825
-	 * @throws ShareNotFound
826
-	 */
827
-	public function getShareByToken($token) {
828
-		$qb = $this->dbConnection->getQueryBuilder();
829
-
830
-		$cursor = $qb->select('*')
831
-			->from('share')
832
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
833
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
834
-			->execute();
835
-
836
-		$data = $cursor->fetch();
837
-
838
-		if ($data === false) {
839
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
840
-		}
841
-
842
-		try {
843
-			$share = $this->createShareObject($data);
844
-		} catch (InvalidShare $e) {
845
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
846
-		}
847
-
848
-		return $share;
849
-	}
850
-
851
-	/**
852
-	 * remove share from table
853
-	 *
854
-	 * @param string $shareId
855
-	 */
856
-	protected function removeShareFromTable($shareId) {
857
-		$qb = $this->dbConnection->getQueryBuilder();
858
-		$qb->delete('share')
859
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
860
-		$qb->execute();
861
-	}
862
-
863
-	/**
864
-	 * Create a share object from an database row
865
-	 *
866
-	 * @param array $data
867
-	 * @return IShare
868
-	 * @throws InvalidShare
869
-	 * @throws ShareNotFound
870
-	 */
871
-	protected function createShareObject($data) {
872
-
873
-		$share = new Share($this->rootFolder, $this->userManager);
874
-		$share->setId((int)$data['id'])
875
-			->setShareType((int)$data['share_type'])
876
-			->setPermissions((int)$data['permissions'])
877
-			->setTarget($data['file_target'])
878
-			->setMailSend((bool)$data['mail_send'])
879
-			->setToken($data['token']);
880
-
881
-		$shareTime = new \DateTime();
882
-		$shareTime->setTimestamp((int)$data['stime']);
883
-		$share->setShareTime($shareTime);
884
-		$share->setSharedWith($data['share_with']);
885
-		$share->setPassword($data['password']);
886
-
887
-		if ($data['uid_initiator'] !== null) {
888
-			$share->setShareOwner($data['uid_owner']);
889
-			$share->setSharedBy($data['uid_initiator']);
890
-		} else {
891
-			//OLD SHARE
892
-			$share->setSharedBy($data['uid_owner']);
893
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
894
-
895
-			$owner = $path->getOwner();
896
-			$share->setShareOwner($owner->getUID());
897
-		}
898
-
899
-		if ($data['expiration'] !== null) {
900
-			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
901
-			if ($expiration !== false) {
902
-				$share->setExpirationDate($expiration);
903
-			}
904
-		}
905
-
906
-		$share->setNodeId((int)$data['file_source']);
907
-		$share->setNodeType($data['item_type']);
908
-
909
-		$share->setProviderId($this->identifier());
910
-
911
-		return $share;
912
-	}
913
-
914
-	/**
915
-	 * Get the node with file $id for $user
916
-	 *
917
-	 * @param string $userId
918
-	 * @param int $id
919
-	 * @return \OCP\Files\File|\OCP\Files\Folder
920
-	 * @throws InvalidShare
921
-	 */
922
-	private function getNode($userId, $id) {
923
-		try {
924
-			$userFolder = $this->rootFolder->getUserFolder($userId);
925
-		} catch (NotFoundException $e) {
926
-			throw new InvalidShare();
927
-		}
928
-
929
-		$nodes = $userFolder->getById($id);
930
-
931
-		if (empty($nodes)) {
932
-			throw new InvalidShare();
933
-		}
934
-
935
-		return $nodes[0];
936
-	}
937
-
938
-	/**
939
-	 * A user is deleted from the system
940
-	 * So clean up the relevant shares.
941
-	 *
942
-	 * @param string $uid
943
-	 * @param int $shareType
944
-	 */
945
-	public function userDeleted($uid, $shareType) {
946
-		$qb = $this->dbConnection->getQueryBuilder();
947
-
948
-		$qb->delete('share')
949
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
950
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
951
-			->execute();
952
-	}
953
-
954
-	/**
955
-	 * This provider does not support group shares
956
-	 *
957
-	 * @param string $gid
958
-	 */
959
-	public function groupDeleted($gid) {
960
-		return;
961
-	}
962
-
963
-	/**
964
-	 * This provider does not support group shares
965
-	 *
966
-	 * @param string $uid
967
-	 * @param string $gid
968
-	 */
969
-	public function userDeletedFromGroup($uid, $gid) {
970
-		return;
971
-	}
972
-
973
-	/**
974
-	 * get database row of a give share
975
-	 *
976
-	 * @param $id
977
-	 * @return array
978
-	 * @throws ShareNotFound
979
-	 */
980
-	protected function getRawShare($id) {
981
-
982
-		// Now fetch the inserted share and create a complete share object
983
-		$qb = $this->dbConnection->getQueryBuilder();
984
-		$qb->select('*')
985
-			->from('share')
986
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
987
-
988
-		$cursor = $qb->execute();
989
-		$data = $cursor->fetch();
990
-		$cursor->closeCursor();
991
-
992
-		if ($data === false) {
993
-			throw new ShareNotFound;
994
-		}
995
-
996
-		return $data;
997
-	}
998
-
999
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
1000
-		$qb = $this->dbConnection->getQueryBuilder();
1001
-		$qb->select('*')
1002
-			->from('share', 's')
1003
-			->andWhere($qb->expr()->orX(
1004
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1005
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1006
-			))
1007
-			->andWhere(
1008
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
1009
-			);
1010
-
1011
-		/**
1012
-		 * Reshares for this user are shares where they are the owner.
1013
-		 */
1014
-		if ($reshares === false) {
1015
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1016
-		} else {
1017
-			$qb->andWhere(
1018
-				$qb->expr()->orX(
1019
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1020
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1021
-				)
1022
-			);
1023
-		}
1024
-
1025
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1026
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1027
-
1028
-		$qb->orderBy('id');
1029
-
1030
-		$cursor = $qb->execute();
1031
-		$shares = [];
1032
-		while ($data = $cursor->fetch()) {
1033
-			$shares[$data['fileid']][] = $this->createShareObject($data);
1034
-		}
1035
-		$cursor->closeCursor();
1036
-
1037
-		return $shares;
1038
-	}
1039
-
1040
-	/**
1041
-	 * @inheritdoc
1042
-	 */
1043
-	public function getAccessList($nodes, $currentAccess) {
1044
-		$ids = [];
1045
-		foreach ($nodes as $node) {
1046
-			$ids[] = $node->getId();
1047
-		}
1048
-
1049
-		$qb = $this->dbConnection->getQueryBuilder();
1050
-		$qb->select('share_with')
1051
-			->from('share')
1052
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
1053
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1054
-			->andWhere($qb->expr()->orX(
1055
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1056
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1057
-			))
1058
-			->setMaxResults(1);
1059
-		$cursor = $qb->execute();
1060
-
1061
-		$mail = $cursor->fetch() !== false;
1062
-		$cursor->closeCursor();
1063
-
1064
-		return ['public' => $mail];
1065
-	}
632
+        $qb = $this->dbConnection->getQueryBuilder();
633
+        $qb->update('share')
634
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
635
+            ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
636
+            ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
637
+            ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
638
+            ->set('password', $qb->createNamedParameter($share->getPassword()))
639
+            ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
640
+            ->execute();
641
+
642
+        return $share;
643
+    }
644
+
645
+    /**
646
+     * @inheritdoc
647
+     */
648
+    public function move(IShare $share, $recipient) {
649
+        /**
650
+         * nothing to do here, mail shares are only outgoing shares
651
+         */
652
+        return $share;
653
+    }
654
+
655
+    /**
656
+     * Delete a share (owner unShares the file)
657
+     *
658
+     * @param IShare $share
659
+     */
660
+    public function delete(IShare $share) {
661
+        $this->removeShareFromTable($share->getId());
662
+    }
663
+
664
+    /**
665
+     * @inheritdoc
666
+     */
667
+    public function deleteFromSelf(IShare $share, $recipient) {
668
+        // nothing to do here, mail shares are only outgoing shares
669
+        return;
670
+    }
671
+
672
+    /**
673
+     * @inheritdoc
674
+     */
675
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
676
+        $qb = $this->dbConnection->getQueryBuilder();
677
+        $qb->select('*')
678
+            ->from('share');
679
+
680
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
681
+
682
+        /**
683
+         * Reshares for this user are shares where they are the owner.
684
+         */
685
+        if ($reshares === false) {
686
+            //Special case for old shares created via the web UI
687
+            $or1 = $qb->expr()->andX(
688
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
689
+                $qb->expr()->isNull('uid_initiator')
690
+            );
691
+
692
+            $qb->andWhere(
693
+                $qb->expr()->orX(
694
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
695
+                    $or1
696
+                )
697
+            );
698
+        } else {
699
+            $qb->andWhere(
700
+                $qb->expr()->orX(
701
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
702
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
703
+                )
704
+            );
705
+        }
706
+
707
+        if ($node !== null) {
708
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
709
+        }
710
+
711
+        if ($limit !== -1) {
712
+            $qb->setMaxResults($limit);
713
+        }
714
+
715
+        $qb->setFirstResult($offset);
716
+        $qb->orderBy('id');
717
+
718
+        $cursor = $qb->execute();
719
+        $shares = [];
720
+        while($data = $cursor->fetch()) {
721
+            $shares[] = $this->createShareObject($data);
722
+        }
723
+        $cursor->closeCursor();
724
+
725
+        return $shares;
726
+    }
727
+
728
+    /**
729
+     * @inheritdoc
730
+     */
731
+    public function getShareById($id, $recipientId = null) {
732
+        $qb = $this->dbConnection->getQueryBuilder();
733
+
734
+        $qb->select('*')
735
+            ->from('share')
736
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
737
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
738
+
739
+        $cursor = $qb->execute();
740
+        $data = $cursor->fetch();
741
+        $cursor->closeCursor();
742
+
743
+        if ($data === false) {
744
+            throw new ShareNotFound();
745
+        }
746
+
747
+        try {
748
+            $share = $this->createShareObject($data);
749
+        } catch (InvalidShare $e) {
750
+            throw new ShareNotFound();
751
+        }
752
+
753
+        return $share;
754
+    }
755
+
756
+    /**
757
+     * Get shares for a given path
758
+     *
759
+     * @param \OCP\Files\Node $path
760
+     * @return IShare[]
761
+     */
762
+    public function getSharesByPath(Node $path) {
763
+        $qb = $this->dbConnection->getQueryBuilder();
764
+
765
+        $cursor = $qb->select('*')
766
+            ->from('share')
767
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
768
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
769
+            ->execute();
770
+
771
+        $shares = [];
772
+        while($data = $cursor->fetch()) {
773
+            $shares[] = $this->createShareObject($data);
774
+        }
775
+        $cursor->closeCursor();
776
+
777
+        return $shares;
778
+    }
779
+
780
+    /**
781
+     * @inheritdoc
782
+     */
783
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
784
+        /** @var IShare[] $shares */
785
+        $shares = [];
786
+
787
+        //Get shares directly with this user
788
+        $qb = $this->dbConnection->getQueryBuilder();
789
+        $qb->select('*')
790
+            ->from('share');
791
+
792
+        // Order by id
793
+        $qb->orderBy('id');
794
+
795
+        // Set limit and offset
796
+        if ($limit !== -1) {
797
+            $qb->setMaxResults($limit);
798
+        }
799
+        $qb->setFirstResult($offset);
800
+
801
+        $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
802
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
803
+
804
+        // Filter by node if provided
805
+        if ($node !== null) {
806
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
807
+        }
808
+
809
+        $cursor = $qb->execute();
810
+
811
+        while($data = $cursor->fetch()) {
812
+            $shares[] = $this->createShareObject($data);
813
+        }
814
+        $cursor->closeCursor();
815
+
816
+
817
+        return $shares;
818
+    }
819
+
820
+    /**
821
+     * Get a share by token
822
+     *
823
+     * @param string $token
824
+     * @return IShare
825
+     * @throws ShareNotFound
826
+     */
827
+    public function getShareByToken($token) {
828
+        $qb = $this->dbConnection->getQueryBuilder();
829
+
830
+        $cursor = $qb->select('*')
831
+            ->from('share')
832
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
833
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
834
+            ->execute();
835
+
836
+        $data = $cursor->fetch();
837
+
838
+        if ($data === false) {
839
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
840
+        }
841
+
842
+        try {
843
+            $share = $this->createShareObject($data);
844
+        } catch (InvalidShare $e) {
845
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
846
+        }
847
+
848
+        return $share;
849
+    }
850
+
851
+    /**
852
+     * remove share from table
853
+     *
854
+     * @param string $shareId
855
+     */
856
+    protected function removeShareFromTable($shareId) {
857
+        $qb = $this->dbConnection->getQueryBuilder();
858
+        $qb->delete('share')
859
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
860
+        $qb->execute();
861
+    }
862
+
863
+    /**
864
+     * Create a share object from an database row
865
+     *
866
+     * @param array $data
867
+     * @return IShare
868
+     * @throws InvalidShare
869
+     * @throws ShareNotFound
870
+     */
871
+    protected function createShareObject($data) {
872
+
873
+        $share = new Share($this->rootFolder, $this->userManager);
874
+        $share->setId((int)$data['id'])
875
+            ->setShareType((int)$data['share_type'])
876
+            ->setPermissions((int)$data['permissions'])
877
+            ->setTarget($data['file_target'])
878
+            ->setMailSend((bool)$data['mail_send'])
879
+            ->setToken($data['token']);
880
+
881
+        $shareTime = new \DateTime();
882
+        $shareTime->setTimestamp((int)$data['stime']);
883
+        $share->setShareTime($shareTime);
884
+        $share->setSharedWith($data['share_with']);
885
+        $share->setPassword($data['password']);
886
+
887
+        if ($data['uid_initiator'] !== null) {
888
+            $share->setShareOwner($data['uid_owner']);
889
+            $share->setSharedBy($data['uid_initiator']);
890
+        } else {
891
+            //OLD SHARE
892
+            $share->setSharedBy($data['uid_owner']);
893
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
894
+
895
+            $owner = $path->getOwner();
896
+            $share->setShareOwner($owner->getUID());
897
+        }
898
+
899
+        if ($data['expiration'] !== null) {
900
+            $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
901
+            if ($expiration !== false) {
902
+                $share->setExpirationDate($expiration);
903
+            }
904
+        }
905
+
906
+        $share->setNodeId((int)$data['file_source']);
907
+        $share->setNodeType($data['item_type']);
908
+
909
+        $share->setProviderId($this->identifier());
910
+
911
+        return $share;
912
+    }
913
+
914
+    /**
915
+     * Get the node with file $id for $user
916
+     *
917
+     * @param string $userId
918
+     * @param int $id
919
+     * @return \OCP\Files\File|\OCP\Files\Folder
920
+     * @throws InvalidShare
921
+     */
922
+    private function getNode($userId, $id) {
923
+        try {
924
+            $userFolder = $this->rootFolder->getUserFolder($userId);
925
+        } catch (NotFoundException $e) {
926
+            throw new InvalidShare();
927
+        }
928
+
929
+        $nodes = $userFolder->getById($id);
930
+
931
+        if (empty($nodes)) {
932
+            throw new InvalidShare();
933
+        }
934
+
935
+        return $nodes[0];
936
+    }
937
+
938
+    /**
939
+     * A user is deleted from the system
940
+     * So clean up the relevant shares.
941
+     *
942
+     * @param string $uid
943
+     * @param int $shareType
944
+     */
945
+    public function userDeleted($uid, $shareType) {
946
+        $qb = $this->dbConnection->getQueryBuilder();
947
+
948
+        $qb->delete('share')
949
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
950
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
951
+            ->execute();
952
+    }
953
+
954
+    /**
955
+     * This provider does not support group shares
956
+     *
957
+     * @param string $gid
958
+     */
959
+    public function groupDeleted($gid) {
960
+        return;
961
+    }
962
+
963
+    /**
964
+     * This provider does not support group shares
965
+     *
966
+     * @param string $uid
967
+     * @param string $gid
968
+     */
969
+    public function userDeletedFromGroup($uid, $gid) {
970
+        return;
971
+    }
972
+
973
+    /**
974
+     * get database row of a give share
975
+     *
976
+     * @param $id
977
+     * @return array
978
+     * @throws ShareNotFound
979
+     */
980
+    protected function getRawShare($id) {
981
+
982
+        // Now fetch the inserted share and create a complete share object
983
+        $qb = $this->dbConnection->getQueryBuilder();
984
+        $qb->select('*')
985
+            ->from('share')
986
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
987
+
988
+        $cursor = $qb->execute();
989
+        $data = $cursor->fetch();
990
+        $cursor->closeCursor();
991
+
992
+        if ($data === false) {
993
+            throw new ShareNotFound;
994
+        }
995
+
996
+        return $data;
997
+    }
998
+
999
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
1000
+        $qb = $this->dbConnection->getQueryBuilder();
1001
+        $qb->select('*')
1002
+            ->from('share', 's')
1003
+            ->andWhere($qb->expr()->orX(
1004
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1005
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1006
+            ))
1007
+            ->andWhere(
1008
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
1009
+            );
1010
+
1011
+        /**
1012
+         * Reshares for this user are shares where they are the owner.
1013
+         */
1014
+        if ($reshares === false) {
1015
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1016
+        } else {
1017
+            $qb->andWhere(
1018
+                $qb->expr()->orX(
1019
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1020
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1021
+                )
1022
+            );
1023
+        }
1024
+
1025
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1026
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1027
+
1028
+        $qb->orderBy('id');
1029
+
1030
+        $cursor = $qb->execute();
1031
+        $shares = [];
1032
+        while ($data = $cursor->fetch()) {
1033
+            $shares[$data['fileid']][] = $this->createShareObject($data);
1034
+        }
1035
+        $cursor->closeCursor();
1036
+
1037
+        return $shares;
1038
+    }
1039
+
1040
+    /**
1041
+     * @inheritdoc
1042
+     */
1043
+    public function getAccessList($nodes, $currentAccess) {
1044
+        $ids = [];
1045
+        foreach ($nodes as $node) {
1046
+            $ids[] = $node->getId();
1047
+        }
1048
+
1049
+        $qb = $this->dbConnection->getQueryBuilder();
1050
+        $qb->select('share_with')
1051
+            ->from('share')
1052
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
1053
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1054
+            ->andWhere($qb->expr()->orX(
1055
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1056
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1057
+            ))
1058
+            ->setMaxResults(1);
1059
+        $cursor = $qb->execute();
1060
+
1061
+        $mail = $cursor->fetch() !== false;
1062
+        $cursor->closeCursor();
1063
+
1064
+        return ['public' => $mail];
1065
+    }
1066 1066
 
1067 1067
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -209,10 +209,10 @@  discard block
 block discarded – undo
209 209
 		}
210 210
 
211 211
 		$passwordPolicy = $this->getPasswordPolicy();
212
-		$passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS;
212
+		$passwordCharset = ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS;
213 213
 		$passwordLength = 8;
214 214
 		if (!empty($passwordPolicy)) {
215
-			$passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength;
215
+			$passwordLength = (int) $passwordPolicy['minLength'] > 0 ? (int) $passwordPolicy['minLength'] : $passwordLength;
216 216
 			$passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : '';
217 217
 		}
218 218
 
@@ -349,11 +349,11 @@  discard block
 block discarded – undo
349 349
 				$share->getSharedWith()
350 350
 			);
351 351
 		} catch (HintException $hintException) {
352
-			$this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
352
+			$this->logger->error('Failed to send share by mail: '.$hintException->getMessage());
353 353
 			$this->removeShareFromTable($shareId);
354 354
 			throw $hintException;
355 355
 		} catch (\Exception $e) {
356
-			$this->logger->error('Failed to send share by email: ' . $e->getMessage());
356
+			$this->logger->error('Failed to send share by email: '.$e->getMessage());
357 357
 			$this->removeShareFromTable($shareId);
358 358
 			throw new HintException('Failed to send share by mail',
359 359
 				$this->l->t('Failed to send share by email'));
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
 											$shareWith) {
377 377
 		$initiatorUser = $this->userManager->get($initiator);
378 378
 		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
379
-		$subject = (string)$this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename));
379
+		$subject = (string) $this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename));
380 380
 
381 381
 		$message = $this->mailer->createMessage();
382 382
 
@@ -387,7 +387,7 @@  discard block
 block discarded – undo
387 387
 		$text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
388 388
 
389 389
 		$emailTemplate->addBodyText(
390
-			$text . ' ' . $this->l->t('Click the button below to open it.'),
390
+			$text.' '.$this->l->t('Click the button below to open it.'),
391 391
 			$text
392 392
 		);
393 393
 		$emailTemplate->addBodyButton(
@@ -411,9 +411,9 @@  discard block
 block discarded – undo
411 411
 		// The "Reply-To" is set to the sharer if an mail address is configured
412 412
 		// also the default footer contains a "Do not reply" which needs to be adjusted.
413 413
 		$initiatorEmail = $initiatorUser->getEMailAddress();
414
-		if($initiatorEmail !== null) {
414
+		if ($initiatorEmail !== null) {
415 415
 			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
416
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
416
+			$emailTemplate->addFooter($instanceName.' - '.$this->defaults->getSlogan());
417 417
 		} else {
418 418
 			$emailTemplate->addFooter();
419 419
 		}
@@ -445,7 +445,7 @@  discard block
 block discarded – undo
445 445
 		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
446 446
 		$initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
447 447
 
448
-		$subject = (string)$this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
448
+		$subject = (string) $this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
449 449
 		$plainBodyPart = $this->l->t("%s shared »%s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
450 450
 		$htmlBodyPart = $this->l->t('%s shared »%s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
451 451
 
@@ -469,7 +469,7 @@  discard block
 block discarded – undo
469 469
 		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
470 470
 		if ($initiatorEmailAddress !== null) {
471 471
 			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
472
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
472
+			$emailTemplate->addFooter($instanceName.' - '.$this->defaults->getSlogan());
473 473
 		} else {
474 474
 			$emailTemplate->addFooter();
475 475
 		}
@@ -508,7 +508,7 @@  discard block
 block discarded – undo
508 508
 			);
509 509
 		}
510 510
 
511
-		$subject = (string)$this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]);
511
+		$subject = (string) $this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]);
512 512
 		$bodyPart = $this->l->t("You just shared »%s« with %s. The share was already send to the recipient. Due to the security policies defined by the administrator of %s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.", [$filename, $shareWith, $this->defaults->getName()]);
513 513
 
514 514
 		$message = $this->mailer->createMessage();
@@ -562,7 +562,7 @@  discard block
 block discarded – undo
562 562
 			->orderBy('id');
563 563
 
564 564
 		$cursor = $qb->execute();
565
-		while($data = $cursor->fetch()) {
565
+		while ($data = $cursor->fetch()) {
566 566
 			$children[] = $this->createShareObject($data);
567 567
 		}
568 568
 		$cursor->closeCursor();
@@ -606,7 +606,7 @@  discard block
 block discarded – undo
606 606
 		$qb->execute();
607 607
 		$id = $qb->getLastInsertId();
608 608
 
609
-		return (int)$id;
609
+		return (int) $id;
610 610
 	}
611 611
 
612 612
 	/**
@@ -623,7 +623,7 @@  discard block
 block discarded – undo
623 623
 		// a real password was given
624 624
 		$validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
625 625
 
626
-		if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
626
+		if ($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
627 627
 			$this->sendPassword($share, $plainTextPassword);
628 628
 		}
629 629
 		/*
@@ -717,7 +717,7 @@  discard block
 block discarded – undo
717 717
 
718 718
 		$cursor = $qb->execute();
719 719
 		$shares = [];
720
-		while($data = $cursor->fetch()) {
720
+		while ($data = $cursor->fetch()) {
721 721
 			$shares[] = $this->createShareObject($data);
722 722
 		}
723 723
 		$cursor->closeCursor();
@@ -769,7 +769,7 @@  discard block
 block discarded – undo
769 769
 			->execute();
770 770
 
771 771
 		$shares = [];
772
-		while($data = $cursor->fetch()) {
772
+		while ($data = $cursor->fetch()) {
773 773
 			$shares[] = $this->createShareObject($data);
774 774
 		}
775 775
 		$cursor->closeCursor();
@@ -808,7 +808,7 @@  discard block
 block discarded – undo
808 808
 
809 809
 		$cursor = $qb->execute();
810 810
 
811
-		while($data = $cursor->fetch()) {
811
+		while ($data = $cursor->fetch()) {
812 812
 			$shares[] = $this->createShareObject($data);
813 813
 		}
814 814
 		$cursor->closeCursor();
@@ -871,15 +871,15 @@  discard block
 block discarded – undo
871 871
 	protected function createShareObject($data) {
872 872
 
873 873
 		$share = new Share($this->rootFolder, $this->userManager);
874
-		$share->setId((int)$data['id'])
875
-			->setShareType((int)$data['share_type'])
876
-			->setPermissions((int)$data['permissions'])
874
+		$share->setId((int) $data['id'])
875
+			->setShareType((int) $data['share_type'])
876
+			->setPermissions((int) $data['permissions'])
877 877
 			->setTarget($data['file_target'])
878
-			->setMailSend((bool)$data['mail_send'])
878
+			->setMailSend((bool) $data['mail_send'])
879 879
 			->setToken($data['token']);
880 880
 
881 881
 		$shareTime = new \DateTime();
882
-		$shareTime->setTimestamp((int)$data['stime']);
882
+		$shareTime->setTimestamp((int) $data['stime']);
883 883
 		$share->setShareTime($shareTime);
884 884
 		$share->setSharedWith($data['share_with']);
885 885
 		$share->setPassword($data['password']);
@@ -890,7 +890,7 @@  discard block
 block discarded – undo
890 890
 		} else {
891 891
 			//OLD SHARE
892 892
 			$share->setSharedBy($data['uid_owner']);
893
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
893
+			$path = $this->getNode($share->getSharedBy(), (int) $data['file_source']);
894 894
 
895 895
 			$owner = $path->getOwner();
896 896
 			$share->setShareOwner($owner->getUID());
@@ -903,7 +903,7 @@  discard block
 block discarded – undo
903 903
 			}
904 904
 		}
905 905
 
906
-		$share->setNodeId((int)$data['file_source']);
906
+		$share->setNodeId((int) $data['file_source']);
907 907
 		$share->setNodeType($data['item_type']);
908 908
 
909 909
 		$share->setProviderId($this->identifier());
@@ -1022,7 +1022,7 @@  discard block
 block discarded – undo
1022 1022
 			);
1023 1023
 		}
1024 1024
 
1025
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1025
+		$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1026 1026
 		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1027 1027
 
1028 1028
 		$qb->orderBy('id');
Please login to merge, or discard this patch.