From dc2cd0cea5339973fdc8cd2c34fa90c1858d0ac1 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Thu, 17 Oct 2019 17:32:36 +0200 Subject: [PATCH] Store the `references`, `in-reply-to` and the thread root id Signed-off-by: Christoph Wurst --- appinfo/info.xml | 2 +- lib/Db/Message.php | 31 +++++++++++++- lib/Db/MessageMapper.php | 9 +++++ lib/IMAP/MessageMapper.php | 10 +++++ .../Version1050Date20200624101359.php | 40 +++++++++++++++++++ lib/Model/IMAPMessage.php | 18 +++++++++ 6 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 lib/Migration/Version1050Date20200624101359.php diff --git a/appinfo/info.xml b/appinfo/info.xml index d795fab91..f5484259f 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -12,7 +12,7 @@ - **🙈 We’re not reinventing the wheel!** Based on the great [Horde](http://horde.org) libraries. - **📬 Want to host your own mail server?** We don’t have to reimplement this as you could set up [Mail-in-a-Box](https://mailinabox.email)! ]]> - 1.5.0-alpha1 + 1.5.0-alpha2 agpl Christoph Wurst Roeland Jago Douma diff --git a/lib/Db/Message.php b/lib/Db/Message.php index 2edc06c28..bb389d79a 100644 --- a/lib/Db/Message.php +++ b/lib/Db/Message.php @@ -25,16 +25,20 @@ declare(strict_types=1); namespace OCA\Mail\Db; +use Horde_Mail_Rfc822_Identification; use JsonSerializable; use OCA\Mail\AddressList; use OCP\AppFramework\Db\Entity; use function in_array; +use function json_encode; /** * @method void setUid(int $uid) * @method int getUid() - * @method void setMessageId(string $id) * @method string getMessageId() + * @method string|null getReferences() + * @method string|null getInReplyTo() + * @method string|null getThreadRootId() * @method void setMailboxId(int $mailbox) * @method int getMailboxId() * @method void setSubject(string $subject) @@ -83,6 +87,9 @@ class Message extends Entity implements JsonSerializable { protected $uid; protected $messageId; + protected $references; + protected $inReplyTo; + protected $threadRootId; protected $mailboxId; protected $subject; protected $sentAt; @@ -134,6 +141,28 @@ class Message extends Entity implements JsonSerializable { $this->addType('updatedAt', 'integer'); } + public function setMessageId(?string $messageId): void { + $this->setMessageIdFieldIfNotEmpty('messageId', $messageId); + } + + public function setReferences(?string $references): void { + $parsed = new Horde_Mail_Rfc822_Identification($references); + $this->setter('references', [json_encode($parsed->ids)]); + } + + public function setInReplyTo(?string $inReplyTo): void { + $this->setMessageIdFieldIfNotEmpty('inReplyTo', $inReplyTo); + } + + public function setThreadRootId(?string $messageId): void { + $this->setMessageIdFieldIfNotEmpty('threadRootId', $messageId); + } + + private function setMessageIdFieldIfNotEmpty(string $field, ?string $id): void { + $parsed = new Horde_Mail_Rfc822_Identification($id); + $this->setter($field, [$parsed->ids[0] ?? null]); + } + /** * @return AddressList */ diff --git a/lib/Db/MessageMapper.php b/lib/Db/MessageMapper.php index 4989f0798..1c1b57407 100644 --- a/lib/Db/MessageMapper.php +++ b/lib/Db/MessageMapper.php @@ -93,6 +93,9 @@ class MessageMapper extends QBMapper { $qb1->insert($this->getTableName()); $qb1->setValue('uid', $qb1->createParameter('uid')); $qb1->setValue('message_id', $qb1->createParameter('message_id')); + $qb1->setValue('references', $qb1->createParameter('references')); + $qb1->setValue('in_reply_to', $qb1->createParameter('in_reply_to')); + $qb1->setValue('thread_root_id', $qb1->createParameter('thread_root_id')); $qb1->setValue('mailbox_id', $qb1->createParameter('mailbox_id')); $qb1->setValue('subject', $qb1->createParameter('subject')); $qb1->setValue('sent_at', $qb1->createParameter('sent_at')); @@ -116,6 +119,12 @@ class MessageMapper extends QBMapper { foreach ($messages as $message) { $qb1->setParameter('uid', $message->getUid(), IQueryBuilder::PARAM_INT); $qb1->setParameter('message_id', $message->getMessageId(), IQueryBuilder::PARAM_STR); + $inReplyTo = $message->getInReplyTo(); + $qb1->setParameter('in_reply_to', $inReplyTo, $inReplyTo === null ? IQueryBuilder::PARAM_NULL : IQueryBuilder::PARAM_STR); + $references = $message->getReferences(); + $qb1->setParameter('references', $references, $references === null ? IQueryBuilder::PARAM_NULL : IQueryBuilder::PARAM_STR); + $threadRootId = $message->getThreadRootId(); + $qb1->setParameter('thread_root_id', $threadRootId,$threadRootId === null ? IQueryBuilder::PARAM_NULL : IQueryBuilder::PARAM_STR); $qb1->setParameter('mailbox_id', $message->getMailboxId(), IQueryBuilder::PARAM_INT); $qb1->setParameter('subject', $message->getSubject(), IQueryBuilder::PARAM_STR); $qb1->setParameter('sent_at', $message->getSentAt(), IQueryBuilder::PARAM_INT); diff --git a/lib/IMAP/MessageMapper.php b/lib/IMAP/MessageMapper.php index 756cb79ff..2d0f3cee8 100644 --- a/lib/IMAP/MessageMapper.php +++ b/lib/IMAP/MessageMapper.php @@ -200,6 +200,16 @@ class MessageMapper { $query->flags(); $query->uid(); $query->imapDate(); + $query->headers( + 'references', + [ + 'references', + ], + [ + 'cache' => true, + 'peek' => true, + ] + ); $fetchResults = iterator_to_array($client->fetch($mailbox, $query, [ 'ids' => new Horde_Imap_Client_Ids($ids), diff --git a/lib/Migration/Version1050Date20200624101359.php b/lib/Migration/Version1050Date20200624101359.php new file mode 100644 index 000000000..6b96f9b9e --- /dev/null +++ b/lib/Migration/Version1050Date20200624101359.php @@ -0,0 +1,40 @@ +getTable('mail_messages'); + $messagesTable->getColumn('message_id')->setLength(1023); + $messagesTable->addColumn('references', 'text', [ + 'notnull' => false, + ]); + $messagesTable->addColumn('in_reply_to', 'string', [ + 'notnull' => false, + 'length' => 1023, + ]); + $messagesTable->addColumn('thread_root_id', 'string', [ + 'notnull' => false, + 'length' => 1023, + ]); + + return $schema; + } +} diff --git a/lib/Model/IMAPMessage.php b/lib/Model/IMAPMessage.php index df9f4f69f..6d73bcbae 100644 --- a/lib/Model/IMAPMessage.php +++ b/lib/Model/IMAPMessage.php @@ -38,6 +38,7 @@ use Horde_Imap_Client_Fetch_Query; use Horde_Imap_Client_Ids; use Horde_Imap_Client_Mailbox; use Horde_Imap_Client_Socket; +use Horde_Mime_Headers; use Horde_Mime_Part; use JsonSerializable; use OC; @@ -163,6 +164,20 @@ class IMAPMessage implements IMessage, JsonSerializable { return $this->fetch->getEnvelope(); } + private function getRawReferences(): string { + /** @var Horde_Mime_Headers $headers */ + $headers = $this->fetch->getHeaders('references', Horde_Imap_Client_Data_Fetch::HEADER_PARSE); + $header = $headers->getHeader('references'); + if ($header === null) { + return ''; + } + return $header->value_single; + } + + private function getRawInReplyTo(): string { + return $this->fetch->getEnvelope()->in_reply_to; + } + /** * @return AddressList */ @@ -630,6 +645,9 @@ class IMAPMessage implements IMessage, JsonSerializable { $msg->setUid($this->getUid()); $msg->setMessageId($this->getMessageId()); + $msg->setReferences($this->getRawReferences()); + $msg->setThreadRootId($this->getMessageId()); + $msg->setInReplyTo($this->getRawInReplyTo()); $msg->setMailboxId($mailboxId); $msg->setFrom($this->getFrom()); $msg->setTo($this->getTo());