summaryrefslogtreecommitdiffstats
path: root/apps/files_external/l10n/de_DE.js
Commit message (Collapse)AuthorAgeFilesLines
* [tx-robot] updated from transifexNextcloud bot2020-04-251-0/+2
|
* [tx-robot] updated from transifexNextcloud bot2020-02-071-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2020-02-061-2/+3
|
* [tx-robot] updated from transifexNextcloud bot2020-02-021-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-11-251-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-10-201-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-10-011-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-09-171-3/+2
|
* [tx-robot] updated from transifexNextcloud bot2019-09-111-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-09-081-2/+2
|
* [tx-robot] updated from transifexNextcloud bot2019-05-271-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-03-211-4/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-02-061-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2019-01-111-2/+2
|
* [tx-robot] updated from transifexNextcloud bot2018-11-231-13/+2
|
* [tx-robot] updated from transifexNextcloud bot2018-10-231-8/+9
|
* [tx-robot] updated from transifexNextcloud bot2018-10-101-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-08-241-0/+3
|
* [tx-robot] updated from transifexNextcloud bot2018-08-231-3/+0
|
* [tx-robot] updated from transifexNextcloud bot2018-08-041-0/+2
|
* [tx-robot] updated from transifexNextcloud bot2018-08-031-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-07-221-0/+2
|
* [tx-robot] updated from transifexNextcloud bot2018-06-271-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-06-221-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-06-121-0/+2
|
* [tx-robot] updated from transifexNextcloud bot2018-06-041-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-05-031-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-03-131-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-03-121-2/+2
|
* [tx-robot] updated from transifexNextcloud bot2018-03-011-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-02-281-0/+3
|
* [tx-robot] updated from transifexNextcloud bot2018-02-271-5/+5
|
* [tx-robot] updated from transifexNextcloud bot2018-02-121-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-02-031-1/+9
|
* [tx-robot] updated from transifexNextcloud bot2018-02-011-11/+1
|
* [tx-robot] updated from transifexNextcloud bot2018-01-091-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2017-10-051-23/+23
|
* [tx-robot] updated from transifexNextcloud bot2017-09-301-0/+2
|
* [tx-robot] updated from transifexNextcloud bot2017-08-221-5/+5
|
* [tx-robot] updated from transifexNextcloud bot2017-08-171-6/+6
|
* [tx-robot] updated from transifexNextcloud bot2017-08-091-1/+0
|
* [tx-robot] updated from transifexNextcloud bot2017-07-211-2/+0
|
* [tx-robot] updated from transifexNextcloud bot2017-07-201-0/+2
|
* [tx-robot] updated from transifexNextcloud bot2017-07-191-2/+2
|
* [tx-robot] updated from transifexNextcloud bot2017-05-291-2/+2
|
* [tx-robot] updated from transifexNextcloud bot2017-05-231-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2017-05-101-0/+1
|
* [tx-robot] updated from transifexNextcloud bot2017-05-081-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2017-04-281-1/+1
|
* [tx-robot] updated from transifexNextcloud bot2017-04-201-0/+2
|
a id='n833' href='#n833'>833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
<?php
/**
 * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

namespace OCA\ShareByMail;

use OC\CapabilitiesManager;
use OC\HintException;
use OC\Share20\Exception\InvalidShare;
use OC\User\NoUserException;
use OCA\ShareByMail\Settings\SettingsManager;
use OCP\Activity\IManager;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Defaults;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Mail\IMailer;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
use OC\Share20\Share;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;

/**
 * Class ShareByMail
 *
 * @package OCA\ShareByMail
 */
class ShareByMailProvider implements IShareProvider {

	/** @var  IDBConnection */
	private $dbConnection;

	/** @var ILogger */
	private $logger;

	/** @var ISecureRandom */
	private $secureRandom;

	/** @var IUserManager */
	private $userManager;

	/** @var IRootFolder */
	private $rootFolder;

	/** @var IL10N */
	private $l;

	/** @var IMailer */
	private $mailer;

	/** @var IURLGenerator */
	private $urlGenerator;

	/** @var IManager  */
	private $activityManager;

	/** @var SettingsManager */
	private $settingsManager;

	/** @var Defaults */
	private $defaults;

	/** @var IHasher */
	private $hasher;

	/** @var  CapabilitiesManager */
	private $capabilitiesManager;

	/**
	 * Return the identifier of this provider.
	 *
	 * @return string Containing only [a-zA-Z0-9]
	 */
	public function identifier() {
		return 'ocMailShare';
	}

	/**
	 * DefaultShareProvider constructor.
	 *
	 * @param IDBConnection $connection
	 * @param ISecureRandom $secureRandom
	 * @param IUserManager $userManager
	 * @param IRootFolder $rootFolder
	 * @param IL10N $l
	 * @param ILogger $logger
	 * @param IMailer $mailer
	 * @param IURLGenerator $urlGenerator
	 * @param IManager $activityManager
	 * @param SettingsManager $settingsManager
	 * @param Defaults $defaults
	 * @param IHasher $hasher
	 * @param CapabilitiesManager $capabilitiesManager
	 */
	public function __construct(
		IDBConnection $connection,
		ISecureRandom $secureRandom,
		IUserManager $userManager,
		IRootFolder $rootFolder,
		IL10N $l,
		ILogger $logger,
		IMailer $mailer,
		IURLGenerator $urlGenerator,
		IManager $activityManager,
		SettingsManager $settingsManager,
		Defaults $defaults,
		IHasher $hasher,
		CapabilitiesManager $capabilitiesManager
	) {
		$this->dbConnection = $connection;
		$this->secureRandom = $secureRandom;
		$this->userManager = $userManager;
		$this->rootFolder = $rootFolder;
		$this->l = $l;
		$this->logger = $logger;
		$this->mailer = $mailer;
		$this->urlGenerator = $urlGenerator;
		$this->activityManager = $activityManager;
		$this->settingsManager = $settingsManager;
		$this->defaults = $defaults;
		$this->hasher = $hasher;
		$this->capabilitiesManager = $capabilitiesManager;
	}

	/**
	 * Share a path
	 *
	 * @param IShare $share
	 * @return IShare The share object
	 * @throws ShareNotFound
	 * @throws \Exception
	 */
	public function create(IShare $share) {

		$shareWith = $share->getSharedWith();
		/*
		 * Check if file is not already shared with the remote user
		 */
		$alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0);
		if (!empty($alreadyShared)) {
			$message = 'Sharing %s failed, this item is already shared with %s';
			$message_t = $this->l->t('Sharing %s failed, this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
			throw new \Exception($message_t);
		}

		// if the admin enforces a password for all mail shares we create a
		// random password and send it to the recipient
		$password = '';
		$passwordEnforced = $this->settingsManager->enforcePasswordProtection();
		if ($passwordEnforced) {
			$password = $this->autoGeneratePassword($share);
		}

		$shareId = $this->createMailShare($share);
		$send = $this->sendPassword($share, $password);
		if ($passwordEnforced && $send === false) {
			$this->sendPasswordToOwner($share, $password);
		}

		$this->createShareActivity($share);
		$data = $this->getRawShare($shareId);

		return $this->createShareObject($data);

	}

	/**
	 * auto generate password in case of password enforcement on mail shares
	 *
	 * @param IShare $share
	 * @return string
	 * @throws \Exception
	 */
	protected function autoGeneratePassword($share) {
		$initiatorUser = $this->userManager->get($share->getSharedBy());
		$initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
		$allowPasswordByMail = $this->settingsManager->sendPasswordByMail();

		if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
			throw new \Exception(
				$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.")
			);
		}

		$passwordPolicy = $this->getPasswordPolicy();
		$passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS;
		$passwordLength = 8;
		if (!empty($passwordPolicy)) {
			$passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength;
			$passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : '';
		}

		$password = $this->secureRandom->generate($passwordLength, $passwordCharset);

		$share->setPassword($this->hasher->hash($password));

		return $password;
	}

	/**
	 * get password policy
	 *
	 * @return array
	 */
	protected function getPasswordPolicy() {
		$capabilities = $this->capabilitiesManager->getCapabilities();
		if (isset($capabilities['password_policy'])) {
			return $capabilities['password_policy'];
		}

		return [];
	}

	/**
	 * create activity if a file/folder was shared by mail
	 *
	 * @param IShare $share
	 */
	protected function createShareActivity(IShare $share) {

		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());

		$this->publishActivity(
			Activity::SUBJECT_SHARED_EMAIL_SELF,
			[$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
			$share->getSharedBy(),
			$share->getNode()->getId(),
			$userFolder->getRelativePath($share->getNode()->getPath())
		);

		if ($share->getShareOwner() !== $share->getSharedBy()) {
			$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
			$fileId = $share->getNode()->getId();
			$nodes = $ownerFolder->getById($fileId);
			$ownerPath = $nodes[0]->getPath();
			$this->publishActivity(
				Activity::SUBJECT_SHARED_EMAIL_BY,
				[$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
				$share->getShareOwner(),
				$fileId,
				$ownerFolder->getRelativePath($ownerPath)
			);
		}

	}

	/**
	 * create activity if a file/folder was shared by mail
	 *
	 * @param IShare $share
	 * @param string $sharedWith
	 * @param bool $sendToSelf
	 */
	protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {

		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());

		if ($sendToSelf) {
			$this->publishActivity(
				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
				[$userFolder->getRelativePath($share->getNode()->getPath())],
				$share->getSharedBy(),
				$share->getNode()->getId(),
				$userFolder->getRelativePath($share->getNode()->getPath())
			);
		} else {
			$this->publishActivity(
				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
				[$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
				$share->getSharedBy(),
				$share->getNode()->getId(),
				$userFolder->getRelativePath($share->getNode()->getPath())
			);
		}
	}


	/**
	 * publish activity if a file/folder was shared by mail
	 *
	 * @param $subject
	 * @param $parameters
	 * @param $affectedUser
	 * @param $fileId
	 * @param $filePath
	 */
	protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) {
		$event = $this->activityManager->generateEvent();
		$event->setApp('sharebymail')
			->setType('shared')
			->setSubject($subject, $parameters)
			->setAffectedUser($affectedUser)
			->setObject('files', $fileId, $filePath);
		$this->activityManager->publish($event);

	}

	/**
	 * @param IShare $share
	 * @return int
	 * @throws \Exception
	 */
	protected function createMailShare(IShare $share) {
		$share->setToken($this->generateToken());
		$shareId = $this->addShareToDB(
			$share->getNodeId(),
			$share->getNodeType(),
			$share->getSharedWith(),
			$share->getSharedBy(),
			$share->getShareOwner(),
			$share->getPermissions(),
			$share->getToken(),
			$share->getPassword()
		);

		try {
			$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
				['token' => $share->getToken()]);
			$this->sendMailNotification(
				$share->getNode()->getName(),
				$link,
				$share->getSharedBy(),
				$share->getSharedWith(),
				$share->getExpirationDate()
			);
		} catch (HintException $hintException) {
			$this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
			$this->removeShareFromTable($shareId);
			throw $hintException;
		} catch (\Exception $e) {
			$this->logger->error('Failed to send share by email: ' . $e->getMessage());
			$this->removeShareFromTable($shareId);
			throw new HintException('Failed to send share by mail',
				$this->l->t('Failed to send share by email'));
		}

		return $shareId;

	}

	/**
	 * @param string $filename
	 * @param string $link
	 * @param string $initiator
	 * @param string $shareWith
	 * @param \DateTime|null $expiration
	 * @throws \Exception If mail couldn't be sent
	 */
	protected function sendMailNotification($filename,
											$link,
											$initiator,
											$shareWith,
											\DateTime $expiration = null) {
		$initiatorUser = $this->userManager->get($initiator);
		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
		$subject = (string)$this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename));

		$message = $this->mailer->createMessage();

		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [
			'filename' => $filename,
			'link' => $link,
			'initiator' => $initiatorDisplayName,
			'expiration' => $expiration,
			'shareWith' => $shareWith,
		]);

		$emailTemplate->addHeader();
		$emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
		$text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);

		$emailTemplate->addBodyText(
			$text . ' ' . $this->l->t('Click the button below to open it.'),
			$text
		);
		$emailTemplate->addBodyButton(
			$this->l->t('Open »%s«', [$filename]),
			$link
		);

		$message->setTo([$shareWith]);

		// The "From" contains the sharers name
		$instanceName = $this->defaults->getName();
		$senderName = $this->l->t(
			'%s via %s',
			[
				$initiatorDisplayName,
				$instanceName
			]
		);
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);

		// The "Reply-To" is set to the sharer if an mail address is configured
		// also the default footer contains a "Do not reply" which needs to be adjusted.
		$initiatorEmail = $initiatorUser->getEMailAddress();
		if($initiatorEmail !== null) {
			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
		} else {
			$emailTemplate->addFooter();
		}

		$message->setSubject($subject);
		$message->setPlainBody($emailTemplate->renderText());
		$message->setHtmlBody($emailTemplate->renderHtml());
		$this->mailer->send($message);
	}

	/**
	 * send password to recipient of a mail share
	 *
	 * @param IShare $share
	 * @param string $password
	 * @return bool
	 */
	protected function sendPassword(IShare $share, $password) {

		$filename = $share->getNode()->getName();
		$initiator = $share->getSharedBy();
		$shareWith = $share->getSharedWith();

		if ($password === '' || $this->settingsManager->sendPasswordByMail() === false) {
			return false;
		}

		$initiatorUser = $this->userManager->get($initiator);
		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
		$initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;

		$subject = (string)$this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
		$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]);
		$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]);

		$message = $this->mailer->createMessage();

		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [
			'filename' => $filename,
			'password' => $password,
			'initiator' => $initiatorDisplayName,
			'initiatorEmail' => $initiatorEmailAddress,
			'shareWith' => $shareWith,
		]);
		$emailTemplate->addHeader();
		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
		$emailTemplate->addBodyText($htmlBodyPart, $plainBodyPart);
		$emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));

		// The "From" contains the sharers name
		$instanceName = $this->defaults->getName();
		$senderName = $this->l->t(
			'%s via %s',
			[
				$initiatorDisplayName,
				$instanceName
			]
		);
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
		if ($initiatorEmailAddress !== null) {
			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
		} else {
			$emailTemplate->addFooter();
		}

		$message->setTo([$shareWith]);
		$message->setSubject($subject);
		$message->setBody($emailTemplate->renderText(), 'text/plain');
		$message->setHtmlBody($emailTemplate->renderHtml());
		$this->mailer->send($message);

		$this->createPasswordSendActivity($share, $shareWith, false);

		return true;
	}

	/**
	 * send auto generated password to the owner. This happens if the admin enforces
	 * a password for mail shares and forbid to send the password by mail to the recipient
	 *
	 * @param IShare $share
	 * @param string $password
	 * @return bool
	 * @throws \Exception
	 */
	protected function sendPasswordToOwner(IShare $share, $password) {

		$filename = $share->getNode()->getName();
		$initiator = $this->userManager->get($share->getSharedBy());
		$initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
		$initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
		$shareWith = $share->getSharedWith();

		if ($initiatorEMailAddress === null) {
			throw new \Exception(
				$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.")
			);
		}

		$subject = (string)$this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]);
		$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()]);

		$message = $this->mailer->createMessage();
		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [
			'filename' => $filename,
			'password' => $password,
			'initiator' => $initiatorDisplayName,
			'initiatorEmail' => $initiatorEMailAddress,
			'shareWith' => $shareWith,
		]);

		$emailTemplate->addHeader();
		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
		$emailTemplate->addBodyText($bodyPart);
		$emailTemplate->addBodyText($this->l->t('This is the password: %s', [$password]));
		$emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
		$emailTemplate->addFooter();

		if ($initiatorEMailAddress) {
			$message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]);
		}
		$message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
		$message->setSubject($subject);
		$message->setBody($emailTemplate->renderText(), 'text/plain');
		$message->setHtmlBody($emailTemplate->renderHtml());
		$this->mailer->send($message);

		$this->createPasswordSendActivity($share, $shareWith, true);

		return true;
	}

	/**
	 * generate share token
	 *
	 * @return string
	 */
	protected function generateToken($size = 15) {
		$token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
		return $token;
	}

	/**
	 * Get all children of this share
	 *
	 * @param IShare $parent
	 * @return IShare[]
	 */
	public function getChildren(IShare $parent) {
		$children = [];

		$qb = $this->dbConnection->getQueryBuilder();
		$qb->select('*')
			->from('share')
			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
			->orderBy('id');

		$cursor = $qb->execute();
		while($data = $cursor->fetch()) {
			$children[] = $this->createShareObject($data);
		}
		$cursor->closeCursor();

		return $children;
	}

	/**
	 * add share to the database and return the ID
	 *
	 * @param int $itemSource
	 * @param string $itemType
	 * @param string $shareWith
	 * @param string $sharedBy
	 * @param string $uidOwner
	 * @param int $permissions
	 * @param string $token
	 * @return int
	 */
	protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password) {
		$qb = $this->dbConnection->getQueryBuilder();
		$qb->insert('share')
			->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
			->setValue('item_type', $qb->createNamedParameter($itemType))
			->setValue('item_source', $qb->createNamedParameter($itemSource))
			->setValue('file_source', $qb->createNamedParameter($itemSource))
			->setValue('share_with', $qb->createNamedParameter($shareWith))
			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
			->setValue('permissions', $qb->createNamedParameter($permissions))
			->setValue('token', $qb->createNamedParameter($token))
			->setValue('password', $qb->createNamedParameter($password))
			->setValue('stime', $qb->createNamedParameter(time()));

		/*
		 * Added to fix https://github.com/owncloud/core/issues/22215
		 * Can be removed once we get rid of ajax/share.php
		 */
		$qb->setValue('file_target', $qb->createNamedParameter(''));

		$qb->execute();
		$id = $qb->getLastInsertId();

		return (int)$id;
	}

	/**
	 * Update a share
	 *
	 * @param IShare $share
	 * @param string|null $plainTextPassword
	 * @return IShare The share object
	 */
	public function update(IShare $share, $plainTextPassword = null) {

		$originalShare = $this->getShareById($share->getId());

		// a real password was given
		$validPassword = $plainTextPassword !== null && $plainTextPassword !== '';

		if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
			$this->sendPassword($share, $plainTextPassword);
		}
		/*
		 * We allow updating the permissions and password of mail shares
		 */
		$qb = $this->dbConnection->getQueryBuilder();
		$qb->update('share')
			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
			->set('permissions', $qb->createNamedParameter($share->getPermissions()))
			->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
			->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
			->set('password', $qb->createNamedParameter($share->getPassword()))
			->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
			->execute();

		return $share;
	}

	/**
	 * @inheritdoc
	 */
	public function move(IShare $share, $recipient) {
		/**
		 * nothing to do here, mail shares are only outgoing shares
		 */
		return $share;
	}

	/**
	 * Delete a share (owner unShares the file)
	 *
	 * @param IShare $share
	 */
	public function delete(IShare $share) {
		$this->removeShareFromTable($share->getId());
	}

	/**
	 * @inheritdoc
	 */
	public function deleteFromSelf(IShare $share, $recipient) {
		// nothing to do here, mail shares are only outgoing shares
		return;
	}

	/**
	 * @inheritdoc
	 */
	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
		$qb = $this->dbConnection->getQueryBuilder();
		$qb->select('*')
			->from('share');

		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));

		/**
		 * Reshares for this user are shares where they are the owner.
		 */
		if ($reshares === false) {
			//Special case for old shares created via the web UI
			$or1 = $qb->expr()->andX(
				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
				$qb->expr()->isNull('uid_initiator')
			);

			$qb->andWhere(
				$qb->expr()->orX(
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
					$or1
				)
			);
		} else {
			$qb->andWhere(
				$qb->expr()->orX(
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
				)
			);
		}

		if ($node !== null) {
			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
		}

		if ($limit !== -1) {
			$qb->setMaxResults($limit);
		}

		$qb->setFirstResult($offset);
		$qb->orderBy('id');

		$cursor = $qb->execute();
		$shares = [];
		while($data = $cursor->fetch()) {
			$shares[] = $this->createShareObject($data);
		}
		$cursor->closeCursor();

		return $shares;
	}

	/**
	 * @inheritdoc
	 */
	public function getShareById($id, $recipientId = null) {
		$qb = $this->dbConnection->getQueryBuilder();

		$qb->select('*')
			->from('share')
			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));

		$cursor = $qb->execute();
		$data = $cursor->fetch();
		$cursor->closeCursor();

		if ($data === false) {
			throw new ShareNotFound();
		}

		try {
			$share = $this->createShareObject($data);
		} catch (InvalidShare $e) {
			throw new ShareNotFound();
		}

		return $share;
	}

	/**
	 * Get shares for a given path
	 *
	 * @param \OCP\Files\Node $path
	 * @return IShare[]
	 */
	public function getSharesByPath(Node $path) {
		$qb = $this->dbConnection->getQueryBuilder();

		$cursor = $qb->select('*')
			->from('share')
			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
			->execute();

		$shares = [];
		while($data = $cursor->fetch()) {
			$shares[] = $this->createShareObject($data);
		}
		$cursor->closeCursor();

		return $shares;
	}

	/**
	 * @inheritdoc
	 */
	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
		/** @var IShare[] $shares */
		$shares = [];

		//Get shares directly with this user
		$qb = $this->dbConnection->getQueryBuilder();
		$qb->select('*')
			->from('share');

		// Order by id
		$qb->orderBy('id');

		// Set limit and offset
		if ($limit !== -1) {
			$qb->setMaxResults($limit);
		}
		$qb->setFirstResult($offset);

		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));

		// Filter by node if provided
		if ($node !== null) {
			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
		}

		$cursor = $qb->execute();

		while($data = $cursor->fetch()) {
			$shares[] = $this->createShareObject($data);
		}
		$cursor->closeCursor();


		return $shares;
	}

	/**
	 * Get a share by token
	 *
	 * @param string $token
	 * @return IShare
	 * @throws ShareNotFound
	 */
	public function getShareByToken($token) {
		$qb = $this->dbConnection->getQueryBuilder();

		$cursor = $qb->select('*')
			->from('share')
			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
			->execute();

		$data = $cursor->fetch();

		if ($data === false) {
			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
		}

		try {
			$share = $this->createShareObject($data);
		} catch (InvalidShare $e) {
			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
		}

		return $share;
	}

	/**
	 * remove share from table
	 *
	 * @param string $shareId
	 */
	protected function removeShareFromTable($shareId) {
		$qb = $this->dbConnection->getQueryBuilder();
		$qb->delete('share')
			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
		$qb->execute();
	}

	/**
	 * Create a share object from an database row
	 *
	 * @param array $data
	 * @return IShare
	 * @throws InvalidShare
	 * @throws ShareNotFound
	 */
	protected function createShareObject($data) {

		$share = new Share($this->rootFolder, $this->userManager);
		$share->setId((int)$data['id'])
			->setShareType((int)$data['share_type'])
			->setPermissions((int)$data['permissions'])
			->setTarget($data['file_target'])
			->setMailSend((bool)$data['mail_send'])
			->setToken($data['token']);

		$shareTime = new \DateTime();
		$shareTime->setTimestamp((int)$data['stime']);
		$share->setShareTime($shareTime);
		$share->setSharedWith($data['share_with']);
		$share->setPassword($data['password']);

		if ($data['uid_initiator'] !== null) {
			$share->setShareOwner($data['uid_owner']);
			$share->setSharedBy($data['uid_initiator']);
		} else {
			//OLD SHARE
			$share->setSharedBy($data['uid_owner']);
			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);

			$owner = $path->getOwner();
			$share->setShareOwner($owner->getUID());
		}

		if ($data['expiration'] !== null) {
			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
			if ($expiration !== false) {
				$share->setExpirationDate($expiration);
			}
		}

		$share->setNodeId((int)$data['file_source']);
		$share->setNodeType($data['item_type']);

		$share->setProviderId($this->identifier());

		return $share;
	}

	/**
	 * Get the node with file $id for $user
	 *
	 * @param string $userId
	 * @param int $id
	 * @return \OCP\Files\File|\OCP\Files\Folder
	 * @throws InvalidShare
	 */
	private function getNode($userId, $id) {
		try {
			$userFolder = $this->rootFolder->getUserFolder($userId);
		} catch (NoUserException $e) {
			throw new InvalidShare();
		}

		$nodes = $userFolder->getById($id);

		if (empty($nodes)) {
			throw new InvalidShare();
		}

		return $nodes[0];
	}

	/**
	 * A user is deleted from the system
	 * So clean up the relevant shares.
	 *
	 * @param string $uid
	 * @param int $shareType
	 */
	public function userDeleted($uid, $shareType) {
		$qb = $this->dbConnection->getQueryBuilder();

		$qb->delete('share')
			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
			->execute();
	}

	/**
	 * This provider does not support group shares
	 *
	 * @param string $gid
	 */
	public function groupDeleted($gid) {
		return;
	}

	/**
	 * This provider does not support group shares
	 *
	 * @param string $uid
	 * @param string $gid
	 */
	public function userDeletedFromGroup($uid, $gid) {
		return;
	}

	/**
	 * get database row of a give share
	 *
	 * @param $id
	 * @return array
	 * @throws ShareNotFound
	 */
	protected function getRawShare($id) {

		// Now fetch the inserted share and create a complete share object
		$qb = $this->dbConnection->getQueryBuilder();
		$qb->select('*')
			->from('share')
			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));

		$cursor = $qb->execute();
		$data = $cursor->fetch();
		$cursor->closeCursor();

		if ($data === false) {
			throw new ShareNotFound;
		}

		return $data;
	}

	public function getSharesInFolder($userId, Folder $node, $reshares) {
		$qb = $this->dbConnection->getQueryBuilder();
		$qb->select('*')
			->from('share', 's')
			->andWhere($qb->expr()->orX(
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
			))
			->andWhere(
				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
			);

		/**
		 * Reshares for this user are shares where they are the owner.
		 */
		if ($reshares === false) {
			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
		} else {
			$qb->andWhere(
				$qb->expr()->orX(
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
				)
			);
		}

		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));

		$qb->orderBy('id');

		$cursor = $qb->execute();
		$shares = [];
		while ($data = $cursor->fetch()) {
			$shares[$data['fileid']][] = $this->createShareObject($data);
		}
		$cursor->closeCursor();

		return $shares;
	}

	/**
	 * @inheritdoc
	 */
	public function getAccessList($nodes, $currentAccess) {
		$ids = [];
		foreach ($nodes as $node) {
			$ids[] = $node->getId();
		}

		$qb = $this->dbConnection->getQueryBuilder();
		$qb->select('share_with')
			->from('share')
			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
			->andWhere($qb->expr()->orX(
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
			))
			->setMaxResults(1);
		$cursor = $qb->execute();

		$mail = $cursor->fetch() !== false;
		$cursor->closeCursor();

		return ['public' => $mail];
	}

}