diff --git a/lib/Model/IMAPMessage.php b/lib/Model/IMAPMessage.php index bc229c1246..673b8d6616 100644 --- a/lib/Model/IMAPMessage.php +++ b/lib/Model/IMAPMessage.php @@ -111,6 +111,7 @@ public function __construct($conn, public $plainMessage = ''; public $attachments = []; public $inlineAttachments = []; + public $scheduling = []; private $loadHtmlMessage = false; private $hasHtmlMessage = false; @@ -398,6 +399,44 @@ private function loadMessageBodies(): void { * @return void */ private function getPart(Horde_Mime_Part $p, $partNo): void { + // iMIP messages + // Handle text/calendar parts first because they might be attachments at the same time. + // Otherwise, some of the following if-conditions might break the handling and treat iMIP + // data like regular attachments. + $allContentTypeParameters = $p->getAllContentTypeParameters(); + if ($p->getType() === 'text/calendar') { + // Handle event data like a regular attachment + // Outlook doesn't set a content disposition + // We work around this by checking for the name only + if ($p->getName() !== null) { + $this->attachments[] = [ + 'id' => $p->getMimeId(), + 'messageId' => $this->messageId, + 'fileName' => $p->getName(), + 'mime' => $p->getType(), + 'size' => $p->getBytes(), + 'cid' => $p->getContentId(), + 'disposition' => $p->getDisposition() + ]; + } + + // return if this is an event attachment only + // the method parameter determines if this is a iMIP message + if (!isset($allContentTypeParameters['method'])) { + return; + } + + if (in_array(strtoupper($allContentTypeParameters['method']), ['REQUEST', 'REPLY', 'CANCEL'])) { + $this->scheduling[] = [ + 'id' => $p->getMimeId(), + 'messageId' => $this->messageId, + 'method' => strtoupper($allContentTypeParameters['method']), + 'contents' => $this->loadBodyData($p, $partNo), + ]; + return; + } + } + // Regular attachments if ($p->isAttachment() || $p->getType() === 'message/rfc822') { $this->attachments[] = [ @@ -442,19 +481,6 @@ private function getPart(Horde_Mime_Part $p, $partNo): void { return; } - if ($p->getType() === 'text/calendar') { - $this->attachments[] = [ - 'id' => $p->getMimeId(), - 'messageId' => $this->messageId, - 'fileName' => $p->getName() ?? 'calendar.ics', - 'mime' => $p->getType(), - 'size' => $p->getBytes(), - 'cid' => $p->getContentId(), - 'disposition' => $p->getDisposition() - ]; - return; - } - if ($p->getType() === 'text/html') { $this->handleHtmlMessage($p, $partNo); return; @@ -478,7 +504,6 @@ private function getPart(Horde_Mime_Part $p, $partNo): void { */ public function getFullMessage(int $id): array { $mailBody = $this->plainMessage; - $data = $this->jsonSerialize(); if ($this->hasHtmlMessage) { $data['hasHtmlBody'] = true; @@ -509,6 +534,7 @@ public function jsonSerialize() { 'flags' => $this->getFlags(), 'hasHtmlBody' => $this->hasHtmlMessage, 'dispositionNotificationTo' => $this->getDispositionNotificationTo(), + 'scheduling' => $this->scheduling, ]; } diff --git a/src/components/Imip.vue b/src/components/Imip.vue new file mode 100644 index 0000000000..c7ac715495 --- /dev/null +++ b/src/components/Imip.vue @@ -0,0 +1,181 @@ + + + + + + + diff --git a/src/components/Message.vue b/src/components/Message.vue index f20a174774..94afbbb677 100644 --- a/src/components/Message.vue +++ b/src/components/Message.vue @@ -27,6 +27,12 @@
+
+ +
diff --git a/src/components/imip/EventData.vue b/src/components/imip/EventData.vue new file mode 100644 index 0000000000..f56f63daad --- /dev/null +++ b/src/components/imip/EventData.vue @@ -0,0 +1,222 @@ + + + + + + + diff --git a/src/util/eventAttendee.js b/src/util/eventAttendee.js new file mode 100644 index 0000000000..1a672e416a --- /dev/null +++ b/src/util/eventAttendee.js @@ -0,0 +1,35 @@ +/** + * @copyright Copyright (c) 2022 Richard Steinmetz + * + * @author Richard Steinmetz + * + * @license AGPL-3.0-or-later + * + * 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 . + * + */ + +/* + * Remove the mailto prefix from a URI and return it + * + * @param {string} uri URI to remove the prefix from + * @return {string} URI without a mailto prefix + */ +export function removeMailtoPrefix(uri) { + if (uri.startsWith('mailto:')) { + return uri.substr(7) + } + + return uri +}