171 строка
5.9 KiB
PHP
171 строка
5.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Mail App
|
|
*
|
|
* @copyright 2022 Anna Larch <anna.larch@gmx.net>
|
|
*
|
|
* @author Anna Larch <anna.larch@gmx.net>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 of the License, or any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
namespace OCA\Mail\Service;
|
|
|
|
use OCA\Mail\Account;
|
|
use OCA\Mail\Db\Mailbox;
|
|
use OCA\Mail\Db\MailboxMapper;
|
|
use OCA\Mail\Db\Message;
|
|
use OCA\Mail\Db\MessageMapper;
|
|
use OCA\Mail\Exception\ServiceException;
|
|
use OCA\Mail\Model\IMAPMessage;
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use OCP\Calendar\IManager;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class IMipService {
|
|
private AccountService $accountService;
|
|
private IManager $calendarManager;
|
|
private LoggerInterface $logger;
|
|
private MailboxMapper $mailboxMapper;
|
|
private MailManager $mailManager;
|
|
private MessageMapper $messageMapper;
|
|
|
|
public function __construct(
|
|
AccountService $accountService,
|
|
IManager $manager,
|
|
LoggerInterface $logger,
|
|
MailboxMapper $mailboxMapper,
|
|
MailManager $mailManager,
|
|
MessageMapper $messageMapper
|
|
) {
|
|
$this->accountService = $accountService;
|
|
$this->calendarManager = $manager;
|
|
$this->logger = $logger;
|
|
$this->mailboxMapper = $mailboxMapper;
|
|
$this->mailManager = $mailManager;
|
|
$this->messageMapper = $messageMapper;
|
|
}
|
|
|
|
public function process(): void {
|
|
$messages = $this->messageMapper->findIMipMessagesAscending();
|
|
if ($messages === []) {
|
|
$this->logger->info('No iMIP messages to process.');
|
|
return;
|
|
}
|
|
|
|
// Collect all mailboxes in memory
|
|
// possible perf improvement - make this one IN query
|
|
// and JOIN with accounts table
|
|
// although this might not make much of a difference
|
|
// since there are very few messages to process
|
|
$mailboxIds = array_unique(array_map(static function (Message $message) {
|
|
return $message->getMailboxId();
|
|
}, $messages));
|
|
|
|
$mailboxes = array_map(function (int $mailboxId) {
|
|
try {
|
|
return $this->mailboxMapper->findById($mailboxId);
|
|
} catch (DoesNotExistException | ServiceException $e) {
|
|
return null;
|
|
}
|
|
}, $mailboxIds);
|
|
|
|
// Collect all accounts in memory
|
|
$accountIds = array_unique(array_map(static function (Mailbox $mailbox) {
|
|
return $mailbox->getAccountId();
|
|
}, $mailboxes));
|
|
|
|
$accounts = array_combine($accountIds, array_map(function (int $accountId) {
|
|
try {
|
|
return $this->accountService->findById($accountId);
|
|
} catch (DoesNotExistException $e) {
|
|
return null;
|
|
}
|
|
}, $accountIds));
|
|
|
|
/** @var Mailbox $mailbox */
|
|
foreach ($mailboxes as $mailbox) {
|
|
/** @var Account $account */
|
|
$account = $accounts[$mailbox->getAccountId()];
|
|
$filteredMessages = array_filter($messages, static function ($message) use ($mailbox) {
|
|
return $message->getMailboxId() === $mailbox->getId();
|
|
});
|
|
|
|
if ($filteredMessages === []) {
|
|
continue;
|
|
}
|
|
|
|
// Check for accounts or mailboxes that no longer exist,
|
|
// no processing for drafts, sent items, junk or archive
|
|
if ($account === null
|
|
|| $account->getMailAccount()->getArchiveMailboxId() === $mailbox->getId()
|
|
|| $account->getMailAccount()->getTrashMailboxId() === $mailbox->getId()
|
|
|| $account->getMailAccount()->getSentMailboxId() === $mailbox->getId()
|
|
|| $account->getMailAccount()->getDraftsMailboxId() === $mailbox->getId()
|
|
|| $mailbox->isSpecialUse(\Horde_Imap_Client::SPECIALUSE_ARCHIVE)
|
|
) {
|
|
$processedMessages = array_map(static function (Message $message) {
|
|
$message->setImipProcessed(true);
|
|
return $message;
|
|
}, $filteredMessages); // Silently drop from passing to DAV and mark as processed, so we won't run into these messages again.
|
|
$this->messageMapper->updateImipData(...$processedMessages);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$imapMessages = $this->mailManager->getImapMessagesForScheduleProcessing($account, $mailbox, array_map(static function ($message) {
|
|
return $message->getUid();
|
|
}, $filteredMessages));
|
|
} catch (ServiceException $e) {
|
|
$this->logger->error('Could not get IMAP messages form IMAP server', ['exception' => $e]);
|
|
continue;
|
|
}
|
|
|
|
foreach ($filteredMessages as $message) {
|
|
/** @var IMAPMessage $imapMessage */
|
|
$imapMessage = current(array_filter($imapMessages, static function (IMAPMessage $imapMessage) use ($message) {
|
|
return $message->getUid() === $imapMessage->getUid();
|
|
}));
|
|
if (empty($imapMessage->scheduling)) {
|
|
// No scheduling info, maybe the DB is wrong
|
|
$message->setImipError(true);
|
|
continue;
|
|
}
|
|
|
|
$principalUri = 'principals/users/' . $account->getUserId();
|
|
$sender = $imapMessage->getFrom()->first()->getEmail();
|
|
$recipient = $account->getEmail();
|
|
foreach ($imapMessage->scheduling as $schedulingInfo) { // an IMAP message could contain more than one iMIP object
|
|
if ($schedulingInfo['method'] === 'REPLY') {
|
|
$processed = $this->calendarManager->handleIMipReply($principalUri, $sender, $recipient, $schedulingInfo['contents']);
|
|
$message->setImipProcessed($processed);
|
|
$message->setImipError(!$processed);
|
|
} elseif ($schedulingInfo['method'] === 'CANCEL') {
|
|
$replyTo = $imapMessage->getReplyTo()->first();
|
|
$replyTo = !empty($replyTo) ? $replyTo->getEmail() : null;
|
|
$processed = $this->calendarManager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $schedulingInfo['contents']);
|
|
$message->setImipProcessed($processed);
|
|
$message->setImipError(!$processed);
|
|
}
|
|
}
|
|
}
|
|
$this->messageMapper->updateImipData(...$filteredMessages);
|
|
}
|
|
}
|
|
}
|