Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/mail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2016-10-17 13:21:44 +0300
committerJoas Schilling <coding@schilljs.com>2016-10-17 13:22:12 +0300
commit4531545c6102a06fee7ea9a31f65375a866c257c (patch)
tree607948d33f01d70960fe591900da6200d5119578 /lib/Mailbox.php
parent4d6f7675470ccc2657cca7f17578c0e207fcd0ec (diff)
Use PSR-4 loading for normal files
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'lib/Mailbox.php')
-rw-r--r--lib/Mailbox.php482
1 files changed, 482 insertions, 0 deletions
diff --git a/lib/Mailbox.php b/lib/Mailbox.php
new file mode 100644
index 000000000..cf8036083
--- /dev/null
+++ b/lib/Mailbox.php
@@ -0,0 +1,482 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Clement Wong <mail@clement.hk>
+ * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author matiasdelellis <mati86dl@gmail.com>
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ * @author Thomas Imbreckx <zinks@iozero.be>
+ * @author Thomas I <thomas@oatr.be>
+ * @author Thomas Mueller <thomas.mueller@tmit.eu>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Maximilian Zellhofer <max.zellhofer@gmail.com>
+ *
+ * Mail
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Mail;
+
+use Horde_Imap_Client;
+use Horde_Imap_Client_Exception;
+use Horde_Imap_Client_Fetch_Query;
+use Horde_Imap_Client_Ids;
+use Horde_Imap_Client_Mailbox;
+use Horde_Imap_Client_Search_Query;
+use Horde_Imap_Client_Socket;
+use OCA\Mail\Model\IMAPMessage;
+use OCA\Mail\Service\IMailBox;
+
+class Mailbox implements IMailBox {
+
+ /**
+ * @var Horde_Imap_Client_Socket
+ */
+ protected $conn;
+
+ /**
+ * @var array
+ */
+ private $attributes;
+
+ /**
+ * @var string
+ */
+ private $specialRole;
+
+ /**
+ * @var string
+ */
+ private $displayName;
+
+ /**
+ * @var string
+ */
+ private $delimiter;
+
+ /**
+ * @var Horde_Imap_Client_Mailbox
+ */
+ protected $mailBox;
+
+ /**
+ * @param Horde_Imap_Client_Socket $conn
+ * @param Horde_Imap_Client_Mailbox $mailBox
+ * @param array $attributes
+ * @param string $delimiter
+ */
+ public function __construct($conn, $mailBox, $attributes, $delimiter='/') {
+ $this->conn = $conn;
+ $this->mailBox = $mailBox;
+ $this->attributes = $attributes;
+ $this->delimiter = $delimiter;
+ $this->getSpecialRoleFromAttributes();
+ if ($this->specialRole === null) {
+ $this->guessSpecialRole();
+ }
+ $this->makeDisplayName();
+ }
+
+ /**
+ * @param integer $from
+ * @param integer $count
+ * @param string $filter
+ */
+ private function getSearchIds($from, $count, $filter) {
+ if ($filter instanceof Horde_Imap_Client_Search_Query) {
+ $query = $filter;
+ } else {
+ $query = new Horde_Imap_Client_Search_Query();
+ if ($filter) {
+ $query->text($filter, false);
+ }
+ }
+ if ($this->getSpecialRole() !== 'trash') {
+ $query->flag(Horde_Imap_Client::FLAG_DELETED, false);
+ }
+
+ try {
+ $result = $this->conn->search($this->mailBox, $query, ['sort' => [Horde_Imap_Client::SORT_DATE]]);
+ } catch (Horde_Imap_Client_Exception $e) {
+ // maybe the server's advertisment of SORT was a fake
+ // see https://github.com/nextcloud/mail/issues/50
+ // try again without SORT
+ return $this->getFetchIds($from, $count);
+ }
+
+ $ids = array_reverse($result['match']->ids);
+ if ($from >= 0 && $count >= 0) {
+ $ids = array_slice($ids, $from, $count);
+ }
+ return new \Horde_Imap_Client_Ids($ids, false);
+ }
+
+ /**
+ * @param integer $from
+ * @param integer $count
+ */
+ private function getFetchIds($from, $count) {
+ $q = new Horde_Imap_Client_Fetch_Query();
+ $q->uid();
+ $q->imapDate();
+
+ $result = $this->conn->fetch($this->mailBox, $q);
+ $uidMap = [];
+ foreach ($result as $r) {
+ $uidMap[$r->getUid()] = $r->getImapDate()->getTimeStamp();
+ }
+ // sort by time
+ uasort($uidMap, function($a, $b) {
+ return $a < $b;
+ });
+ if ($from >= 0 && $count >= 0) {
+ $uidMap = array_slice($uidMap, $from, $count, true);
+ }
+ return new \Horde_Imap_Client_Ids(array_keys($uidMap), false);
+ }
+
+ public function getMessages($from = 0, $count = 2, $filter = '') {
+ if (!$this->conn->capability->query('SORT') && (is_null($filter) || $filter === '')) {
+ $ids = $this->getFetchIds($from, $count);
+ } else {
+ $ids = $this->getSearchIds($from, $count, $filter);
+ }
+
+ $headers = [];
+
+ $fetch_query = new Horde_Imap_Client_Fetch_Query();
+ $fetch_query->envelope();
+ $fetch_query->flags();
+ $fetch_query->size();
+ $fetch_query->uid();
+ $fetch_query->imapDate();
+ $fetch_query->structure();
+
+ $headers = array_merge($headers, [
+ 'importance',
+ 'list-post',
+ 'x-priority'
+ ]);
+ $headers[] = 'content-type';
+
+ $fetch_query->headers('imp', $headers, [
+ 'cache' => true,
+ 'peek' => true
+ ]);
+
+ $options = ['ids' => $ids];
+ // $list is an array of Horde_Imap_Client_Data_Fetch objects.
+ $headers = $this->conn->fetch($this->mailBox, $fetch_query, $options);
+
+ ob_start(); // fix for Horde warnings
+ $messages = [];
+ foreach ($headers->ids() as $message_id) {
+ $header = $headers[$message_id];
+ $message = new IMAPMessage($this->conn, $this->mailBox, $message_id, $header);
+ $messages[] = $message->jsonSerialize();
+ }
+ ob_get_clean();
+
+ // sort by time
+ usort($messages, function($a, $b) {
+ return $a['dateInt'] < $b['dateInt'];
+ });
+
+ return $messages;
+ }
+
+ /**
+ * @return array
+ */
+ public function attributes() {
+ return $this->attributes;
+ }
+
+ /**
+ * @param string $messageId
+ * @param bool $loadHtmlMessageBody
+ * @return IMAPMessage
+ */
+ public function getMessage($messageId, $loadHtmlMessageBody = false) {
+ return new IMAPMessage($this->conn, $this->mailBox, $messageId, null, $loadHtmlMessageBody);
+ }
+
+ /**
+ * @param int $flags
+ * @return array
+ */
+ public function getStatus($flags = \Horde_Imap_Client::STATUS_ALL) {
+ return $this->conn->status($this->mailBox, $flags);
+ }
+
+ /**
+ * @return int
+ */
+ public function getTotalMessages() {
+ $status = $this->getStatus(\Horde_Imap_Client::STATUS_MESSAGES);
+ return (int) $status['messages'];
+ }
+
+ protected function makeDisplayName() {
+ $parts = explode($this->delimiter, $this->mailBox->utf8, 2);
+
+ if (count($parts) > 1) {
+ $displayName = $parts[1];
+ } elseif (strtolower($this->mailBox->utf8) === 'inbox') {
+ $displayName = 'Inbox';
+ } else {
+ $displayName = $this->mailBox->utf8;
+ }
+
+ $this->displayName = $displayName;
+ }
+
+ public function getFolderId() {
+ return $this->mailBox->utf8;
+ }
+
+ /**
+ * @return string
+ */
+ public function getParent() {
+ $folderId = $this->getFolderId();
+ $parts = explode($this->delimiter, $folderId, 2);
+
+ if (count($parts) > 1) {
+ return $parts[0];
+ }
+
+ return null;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSpecialRole() {
+ return $this->specialRole;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDisplayName() {
+ return $this->displayName;
+ }
+
+ /**
+ * @param string $displayName
+ */
+ public function setDisplayName($displayName) {
+ $this->displayName = $displayName;
+ }
+
+ /**
+ * @param integer $accountId
+ * @return array
+ */
+ public function serialize($accountId, $status = null) {
+ $displayName = $this->getDisplayName();
+ try {
+ if (is_null($status)) {
+ $status = $this->getStatus();
+ }
+ $total = $status['messages'];
+ $specialRole = $this->getSpecialRole();
+ $unseen = ($specialRole === 'trash') ? 0 : $status['unseen'];
+ $isEmpty = ($total === 0);
+ $noSelect = in_array('\\noselect', $this->attributes);
+ $parentId = $this->getParent();
+ $parentId = ($parentId !== null) ? base64_encode($parentId) : null;
+ return [
+ 'id' => base64_encode($this->getFolderId()),
+ 'parent' => $parentId,
+ 'name' => $displayName,
+ 'specialRole' => $specialRole,
+ 'unseen' => $unseen,
+ 'total' => $total,
+ 'isEmpty' => $isEmpty,
+ 'accountId' => $accountId,
+ 'noSelect' => $noSelect,
+ 'uidvalidity' => $status['uidvalidity'],
+ 'uidnext' => $status['uidnext'],
+ 'delimiter' => $this->delimiter
+ ];
+ } catch (Horde_Imap_Client_Exception $e) {
+ return [
+ 'id' => base64_encode($this->getFolderId()),
+ 'parent' => null,
+ 'name' => $displayName,
+ 'specialRole' => null,
+ 'unseen' => 0,
+ 'total' => 0,
+ 'error' => $e->getMessage(),
+ 'isEmpty' => true,
+ 'accountId' => $accountId,
+ 'noSelect' => true
+ ];
+ }
+ }
+ /**
+ * Get the special use role of the mailbox
+ *
+ * This method reads the attributes sent by the server
+ *
+ */
+ protected function getSpecialRoleFromAttributes() {
+ /*
+ * @todo: support multiple attributes on same folder
+ * "any given server or message store may support
+ * any combination of the attributes"
+ * https://tools.ietf.org/html/rfc6154
+ */
+ $result = null;
+ if (is_array($this->attributes)) {
+ /* Convert attributes to lowercase, because gmail
+ * returns them as lowercase (eg. \trash and not \Trash)
+ */
+ $specialUseAttributes = [
+ strtolower(Horde_Imap_Client::SPECIALUSE_ALL),
+ strtolower(Horde_Imap_Client::SPECIALUSE_ARCHIVE),
+ strtolower(Horde_Imap_Client::SPECIALUSE_DRAFTS),
+ strtolower(Horde_Imap_Client::SPECIALUSE_FLAGGED),
+ strtolower(Horde_Imap_Client::SPECIALUSE_JUNK),
+ strtolower(Horde_Imap_Client::SPECIALUSE_SENT),
+ strtolower(Horde_Imap_Client::SPECIALUSE_TRASH)
+ ];
+
+ $attributes = array_map(function($n) {
+ return strtolower($n);
+ }, $this->attributes);
+
+ foreach ($specialUseAttributes as $attr) {
+ if (in_array($attr, $attributes)) {
+ $result = ltrim($attr, '\\');
+ break;
+ }
+ }
+
+ }
+
+ $this->specialRole = $result;
+ }
+
+ /**
+ * Assign a special role to this mailbox based on its name
+ */
+ protected function guessSpecialRole() {
+
+ $specialFoldersDict = [
+ 'inbox' => ['inbox'],
+ 'sent' => ['sent', 'sent items', 'sent messages', 'sent-mail', 'sentmail'],
+ 'drafts' => ['draft', 'drafts'],
+ 'archive' => ['archive', 'archives'],
+ 'trash' => ['deleted messages', 'trash'],
+ 'junk' => ['junk', 'spam', 'bulk mail'],
+ ];
+
+ $lowercaseExplode = explode($this->delimiter, $this->getFolderId(), 2);
+ $lowercaseId = strtolower(array_pop($lowercaseExplode));
+ $result = null;
+ foreach ($specialFoldersDict as $specialRole => $specialNames) {
+ if (in_array($lowercaseId, $specialNames)) {
+ $result = $specialRole;
+ break;
+ }
+ }
+
+ $this->specialRole = $result;
+ }
+
+ /**
+ * @param int $messageId
+ * @param string $attachmentId
+ * @return Attachment
+ */
+ public function getAttachment($messageId, $attachmentId) {
+ return new Attachment($this->conn, $this->mailBox, $messageId, $attachmentId);
+ }
+
+ /**
+ * @param string $rawBody
+ * @param array $flags
+ */
+ public function saveMessage($rawBody, $flags = []) {
+
+ $this->conn->append($this->mailBox, [
+ [
+ 'data' => $rawBody,
+ 'flags' => $flags
+ ]
+ ]);
+ }
+
+ /**
+ * Save draft
+ *
+ * @param string $rawBody
+ * @return int UID of the saved draft
+ */
+ public function saveDraft($rawBody) {
+
+ $uids = $this->conn->append($this->mailBox, [
+ [
+ 'data' => $rawBody,
+ 'flags' => [
+ Horde_Imap_Client::FLAG_DRAFT,
+ Horde_Imap_Client::FLAG_SEEN
+ ]
+ ]
+ ]);
+ return $uids->current();
+ }
+
+ /**
+ * @param int $uid
+ * @param string $flag
+ * @param boolean $add
+ */
+ public function setMessageFlag($uid, $flag, $add) {
+ $options = [
+ 'ids' => new Horde_Imap_Client_Ids($uid)
+ ];
+ if ($add) {
+ $options['add'] = [$flag];
+ } else {
+ $options['remove'] = [$flag];
+ }
+ $this->conn->store($this->mailBox, $options);
+ }
+
+ /**
+ * @param $fromUid
+ * @param $toUid
+ * @return array
+ */
+ public function getMessagesSince($fromUid, $toUid) {
+ $query = new Horde_Imap_Client_Search_Query();
+ $query->ids(new Horde_Imap_Client_Ids("$fromUid:$toUid"));
+ return $this->getMessages(-1, -1, $query);
+ }
+
+ /**
+ * @return Horde_Imap_Client_Mailbox
+ */
+ public function getHordeMailBox() {
+ return $this->mailBox;
+ }
+
+}