diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2019-09-04 18:05:19 +0300 |
---|---|---|
committer | Christoph Wurst <christoph@winzerhof-wurst.at> | 2019-09-05 14:45:50 +0300 |
commit | d18ef16578dc34ffd67e48bc5c61654e55461ce9 (patch) | |
tree | 0fb85d03cba26c56be550b2cba5072dd6aca4e91 /lib/Listener | |
parent | eec81c6c38259c0edc843018581a1f1bd1ab280a (diff) |
Move message sending and draft saving code
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib/Listener')
-rw-r--r-- | lib/Listener/AddressCollectionListener.php | 68 | ||||
-rw-r--r-- | lib/Listener/DeleteDraftListener.php | 144 | ||||
-rw-r--r-- | lib/Listener/DraftMailboxCreatorListener.php | 98 | ||||
-rw-r--r-- | lib/Listener/FlagRepliedMessageListener.php | 98 | ||||
-rw-r--r-- | lib/Listener/SaveSentMessageListener.php | 126 | ||||
-rw-r--r-- | lib/Listener/TrashMailboxCreatorListener.php (renamed from lib/Listener/MessageDeleteTrashCreatorListener.php) | 16 |
6 files changed, 542 insertions, 8 deletions
diff --git a/lib/Listener/AddressCollectionListener.php b/lib/Listener/AddressCollectionListener.php new file mode 100644 index 000000000..c2ae7eee9 --- /dev/null +++ b/lib/Listener/AddressCollectionListener.php @@ -0,0 +1,68 @@ +<?php declare(strict_types=1); + +/** + * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\Mail\Listener; + +use OCA\Mail\Events\MessageSentEvent; +use OCA\Mail\Service\AutoCompletion\AddressCollector; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\ILogger; +use Throwable; + +class AddressCollectionListener implements IEventListener { + + /** @var AddressCollector */ + private $collector; + + /** @var ILogger */ + private $logger; + + public function __construct(AddressCollector $collector, + ILogger $logger) { + $this->collector = $collector; + $this->logger = $logger; + } + + public function handle(Event $event): void { + if (!($event instanceof MessageSentEvent)) { + return; + } + + // Non-essential feature, hence we catch all possible errors + try { + $message = $event->getMessage(); + $addresses = $message->getTo() + ->merge($message->getCC()) + ->merge($message->getBCC()); + + $this->collector->addAddresses($addresses); + } catch (Throwable $e) { + $this->logger->logException($e, [ + 'message' => 'Error while collecting mail addresses', + 'level' => ILogger::WARN, + ]); + } + } + +} diff --git a/lib/Listener/DeleteDraftListener.php b/lib/Listener/DeleteDraftListener.php new file mode 100644 index 000000000..fdc8622cb --- /dev/null +++ b/lib/Listener/DeleteDraftListener.php @@ -0,0 +1,144 @@ +<?php declare(strict_types=1); + +/** + * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\Mail\Listener; + +use Horde_Imap_Client; +use Horde_Imap_Client_Exception; +use Horde_Imap_Client_Exception_NoSupportExtension; +use OCA\Mail\Account; +use OCA\Mail\Db\Mailbox; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Events\DraftSavedEvent; +use OCA\Mail\Events\MessageSentEvent; +use OCA\Mail\Exception\ServiceException; +use OCA\Mail\IMAP\IMAPClientFactory; +use OCA\Mail\IMAP\MailboxSync; +use OCA\Mail\IMAP\MessageMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\ILogger; + +class DeleteDraftListener implements IEventListener { + + /** @var IMAPClientFactory */ + private $imapClientFactory; + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var MessageMapper */ + private $messageMapper; + + /** @var MailboxSync */ + private $mailboxSync; + + /** @var ILogger */ + private $logger; + + public function __construct(IMAPClientFactory $imapClientFactory, + MailboxMapper $mailboxMapper, + MessageMapper $messageMapper, + MailboxSync $mailboxSync, + ILogger $logger) { + $this->imapClientFactory = $imapClientFactory; + $this->mailboxMapper = $mailboxMapper; + $this->messageMapper = $messageMapper; + $this->mailboxSync = $mailboxSync; + $this->logger = $logger; + } + + public function handle(Event $event): void { + if ($event instanceof DraftSavedEvent && $event->getDraftUid() !== null) { + $this->deleteDraft($event->getAccount(), $event->getDraftUid()); + } else if ($event instanceof MessageSentEvent && $event->getDraftUid() !== null) { + $this->deleteDraft($event->getAccount(), $event->getDraftUid()); + } + } + + /** + * @param DraftSavedEvent $event + */ + private function deleteDraft(Account $account, int $draftUid): void { + $client = $this->imapClientFactory->getClient($account); + $draftsMailbox = $this->getDraftsMailbox($account); + + try { + $this->messageMapper->addFlag( + $client, + $draftsMailbox, + $draftUid, + Horde_Imap_Client::FLAG_DELETED + ); + } catch (Horde_Imap_Client_Exception_NoSupportExtension|Horde_Imap_Client_Exception $e) { + $this->logger->logException($e, [ + 'message' => 'Could not flag draft as deleted' + ]); + } + + try { + $client->expunge($draftsMailbox->getName()); + } catch (Horde_Imap_Client_Exception $e) { + $this->logger->logException($e, [ + 'message' => 'Could not expunge drafts folder' + ]); + } + } + + private function getDraftsMailbox(Account $account): Mailbox { + try { + return $this->mailboxMapper->findSpecial($account, 'drafts'); + } catch (DoesNotExistException $e) { + $this->logger->debug('Creating drafts mailbox'); + $this->createDraftsMailbox($account); + $this->logger->debug('Drafts mailbox created'); + } + + return $this->mailboxMapper->findSpecial($account, 'drafts'); + } + + private function createDraftsMailbox(Account $account): void { + $client = $this->imapClientFactory->getClient($account); + + try { + // TODO: localize mailbox name + $client->createMailbox( + 'Drafts', + [ + 'special_use' => [ + \Horde_Imap_Client::SPECIALUSE_DRAFTS, + ], + ] + ); + } catch (Horde_Imap_Client_Exception $e) { + $this->logger->logException($e, [ + 'message' => 'Could not create drafts mailbox', + ]); + } + + // TODO: find a more elegant solution for updating the mailbox cache + $this->mailboxSync->sync($account, true); + } + +} diff --git a/lib/Listener/DraftMailboxCreatorListener.php b/lib/Listener/DraftMailboxCreatorListener.php new file mode 100644 index 000000000..fdb705f1a --- /dev/null +++ b/lib/Listener/DraftMailboxCreatorListener.php @@ -0,0 +1,98 @@ +<?php declare(strict_types=1); + +/** + * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\Mail\Listener; + +use Horde_Imap_Client_Exception; +use OCA\Mail\Account; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Events\SaveDraftEvent; +use OCA\Mail\IMAP\IMAPClientFactory; +use OCA\Mail\IMAP\MailboxSync; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\ILogger; + +class DraftMailboxCreatorListener implements IEventListener { + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var IMAPClientFactory */ + private $imapClientFactory; + + /** @var MailboxSync */ + private $mailboxSync; + + /** @var ILogger */ + private $logger; + + public function __construct(MailboxMapper $mailboxMapper, + IMAPClientFactory $imapClientFactory, + MailboxSync $mailboxSync, + ILogger $logger) { + $this->mailboxMapper = $mailboxMapper; + $this->imapClientFactory = $imapClientFactory; + $this->mailboxSync = $mailboxSync; + $this->logger = $logger; + } + + public function handle(Event $event): void { + if (!($event instanceof SaveDraftEvent)) { + return; + } + + try { + $this->mailboxMapper->findSpecial($event->getAccount(), 'drafts'); + } catch (DoesNotExistException $e) { + $this->logger->debug('Creating drafts mailbox'); + $this->createDraftsMailbox($event->getAccount()); + $this->logger->debug('Drafts mailbox created'); + } + } + + private function createDraftsMailbox(Account $account): void { + $client = $this->imapClientFactory->getClient($account); + + try { + // TODO: localize mailbox name + $client->createMailbox( + 'Drafts', + [ + 'special_use' => [ + \Horde_Imap_Client::SPECIALUSE_DRAFTS, + ], + ] + ); + } catch (Horde_Imap_Client_Exception $e) { + $this->logger->logException($e, [ + 'message' => 'Could not create drafts mailbox', + ]); + } + + // TODO: find a more elegant solution for updating the mailbox cache + $this->mailboxSync->sync($account, true); + } + +} diff --git a/lib/Listener/FlagRepliedMessageListener.php b/lib/Listener/FlagRepliedMessageListener.php new file mode 100644 index 000000000..c52795380 --- /dev/null +++ b/lib/Listener/FlagRepliedMessageListener.php @@ -0,0 +1,98 @@ +<?php declare(strict_types=1); + +/** + * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\Mail\Listener; + +use Horde_Imap_Client; +use Horde_Imap_Client_Exception; +use Horde_Imap_Client_Exception_NoSupportExtension; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Events\MessageSentEvent; +use OCA\Mail\IMAP\IMAPClientFactory; +use OCA\Mail\IMAP\MessageMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\ILogger; + +class FlagRepliedMessageListener implements IEventListener { + + /** @var IMAPClientFactory */ + private $imapClientFactory; + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var MessageMapper */ + private $messageMapper; + + /** @var ILogger */ + private $logger; + + public function __construct(IMAPClientFactory $imapClientFactory, + MailboxMapper $mailboxMapper, + MessageMapper $mapper, + ILogger $logger) { + + $this->imapClientFactory = $imapClientFactory; + $this->mailboxMapper = $mailboxMapper; + $this->messageMapper = $mapper; + $this->logger = $logger; + } + + public function handle(Event $event): void { + if (!($event instanceof MessageSentEvent) || !$event->getRepliedMessageData()->isReply()) { + return; + } + + try { + $mailbox = $this->mailboxMapper->find( + $event->getAccount(), + base64_decode($event->getRepliedMessageData()->getFolderId()) + ); + } catch (DoesNotExistException $e) { + $this->logger->logException($e, [ + 'message' => 'Could not flag the message in reply to', + 'level' => ILogger::WARN, + ]); + // Not critical -> continue + return; + } + + try { + $client = $this->imapClientFactory->getClient($event->getAccount()); + $this->messageMapper->addFlag( + $client, + $mailbox, + $event->getRepliedMessageData()->getId(), + Horde_Imap_Client::FLAG_ANSWERED + ); + } catch (Horde_Imap_Client_Exception_NoSupportExtension|Horde_Imap_Client_Exception $e) { + $this->logger->logException($e, [ + 'message' => 'Could not flag replied message', + 'level' => ILogger::WARN, + ]); + } + } + +} diff --git a/lib/Listener/SaveSentMessageListener.php b/lib/Listener/SaveSentMessageListener.php new file mode 100644 index 000000000..271dee92e --- /dev/null +++ b/lib/Listener/SaveSentMessageListener.php @@ -0,0 +1,126 @@ +<?php declare(strict_types=1); + +/** + * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\Mail\Listener; + +use Horde_Imap_Client_Exception; +use OCA\Mail\Account; +use OCA\Mail\Db\Mailbox; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Events\MessageSentEvent; +use OCA\Mail\Exception\ServiceException; +use OCA\Mail\IMAP\IMAPClientFactory; +use OCA\Mail\IMAP\MailboxSync; +use OCA\Mail\IMAP\MessageMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\ILogger; + +class SaveSentMessageListener implements IEventListener { + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var IMAPClientFactory */ + private $imapClientFactory; + + /** @var MessageMapper */ + private $messageMapper; + + /** @var MailboxSync */ + private $mailboxSync; + + /** @var ILogger */ + private $logger; + + public function __construct(MailboxMapper $mailboxMapper, + IMAPClientFactory $imapClientFactory, + MessageMapper $messageMapper, + MailboxSync $mailboxSync, + ILogger $logger) { + $this->mailboxMapper = $mailboxMapper; + $this->imapClientFactory = $imapClientFactory; + $this->messageMapper = $messageMapper; + $this->mailboxSync = $mailboxSync; + $this->logger = $logger; + } + + public function handle(Event $event): void { + if (!($event instanceof MessageSentEvent)) { + return; + } + + // Save the message in the sent mailbox + try { + $sentMailbox = $this->mailboxMapper->findSpecial($event->getAccount(), 'sent'); + } catch (DoesNotExistException $e) { + $this->logger->debug('creating sent mailbox'); + $sentMailbox = $this->createSentMailbox($event->getAccount()); + $this->logger->debug('sent mailbox created'); + } + + try { + $this->messageMapper->save( + $this->imapClientFactory->getClient($event->getAccount()), + $sentMailbox, + $event->getMail() + ); + } catch (Horde_Imap_Client_Exception $e) { + throw new ServiceException('Could not save sent message on IMAP', 0, $e); + } + } + + /** + * @throws DoesNotExistException + * @throws ServiceException + */ + private function createSentMailbox(Account $account): Mailbox { + $client = $this->imapClientFactory->getClient($account); + + try { + // TODO: localize mailbox name + $client->createMailbox( + 'Sent', + [ + 'special_use' => [ + \Horde_Imap_Client::SPECIALUSE_SENT, + ], + ] + ); + } catch (Horde_Imap_Client_Exception $e) { + // Let's assume this error is caused because the mailbox already exists, + // caused by concurrent requests or out-of-sync mailbox cache + $this->logger->logException($e, [ + 'message' => 'Could not create sent mailbox', + 'level' => ILogger::WARN, + ]); + } + + // TODO: find a more elegant solution for updating the mailbox cache + $this->mailboxSync->sync($account, true); + + return $this->mailboxMapper->findSpecial($account, 'sent'); + } + +} diff --git a/lib/Listener/MessageDeleteTrashCreatorListener.php b/lib/Listener/TrashMailboxCreatorListener.php index c13240458..a3a00b2b1 100644 --- a/lib/Listener/MessageDeleteTrashCreatorListener.php +++ b/lib/Listener/TrashMailboxCreatorListener.php @@ -34,7 +34,7 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\ILogger; -class MessageDeleteTrashCreatorListener implements IEventListener { +class TrashMailboxCreatorListener implements IEventListener { /** @var MailboxMapper */ private $mailboxMapper; @@ -66,7 +66,7 @@ class MessageDeleteTrashCreatorListener implements IEventListener { try { $this->mailboxMapper->findSpecial( $event->getAccount(), - "trash" + 'trash' ); } catch (DoesNotExistException $e) { $this->logger->debug("Creating trash mailbox"); @@ -81,21 +81,21 @@ class MessageDeleteTrashCreatorListener implements IEventListener { try { // TODO: localize mailbox name $client->createMailbox( - "Trash", + 'Trash', [ - "special_use" => [ + 'special_use' => [ \Horde_Imap_Client::SPECIALUSE_TRASH, ], ] ); + + // TODO: find a more elegant solution for updating the mailbox cache + $this->mailboxSync->sync($account, true); } catch (Horde_Imap_Client_Exception $e) { $this->logger->logException($e, [ - "message" => "Could not creat trash mailbox", + 'message' => 'Could not creat trash mailbox', ]); } - - // TODO: find a more elegant solution for updating the mailbox cache - $this->mailboxSync->sync($account, true); } } |