Skip to content

Commit

Permalink
Add a database cache for mailbox data
Browse files Browse the repository at this point in the history
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
  • Loading branch information
ChristophWurst committed Aug 29, 2019
1 parent 3cc08ff commit f40aba3
Show file tree
Hide file tree
Showing 18 changed files with 680 additions and 48 deletions.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<name>Mail</name>
<summary>IMAP web client</summary>
<description>Easy to use email client which connects to your mail server via IMAP and SMTP.</description>
<version>0.15.5</version>
<version>0.15.6</version>
<licence>agpl</licence>
<author>Christoph Wurst</author>
<author>Jan-Christoph Borchardt</author>
Expand Down
4 changes: 4 additions & 0 deletions lib/Account.php
Original file line number Diff line number Diff line change
Expand Up @@ -672,4 +672,8 @@ public function newReplyMessage() {
return new ReplyMessage();
}

public function getLastMailboxSync(): int {
return (int) $this->account->getLastMailboxSync();
}

}
5 changes: 5 additions & 0 deletions lib/Db/MailAccount.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
* @method void setOutboundPassword(string $outboundPassword)
* @method string|null getSignature()
* @method void setSignature(string|null $signature)
* @method int getLastMailboxSync()
* @method void setLastMailboxSync(int $time)
*/
class MailAccount extends Entity {

Expand All @@ -76,6 +78,7 @@ class MailAccount extends Entity {
protected $outboundUser;
protected $outboundPassword;
protected $signature;
protected $lastMailboxSync;

/**
* @param array $params
Expand Down Expand Up @@ -123,6 +126,8 @@ public function __construct(array $params=[]) {
if (isset($params['smtpPassword'])) {
$this->setOutboundPassword($params['smtpPassword']);
}

$this->addType('lastMailboxSync', 'integer');
}

/**
Expand Down
76 changes: 76 additions & 0 deletions lib/Db/Mailbox.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?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\Db;

use OCA\Mail\Folder;
use OCP\AppFramework\Db\Entity;

/**
* @method string getId()
* @method void setId(string $id)
* @method int getAccountId()
* @method void setAccountId(int $accountId)
* @method string getSyncToken()
* @method void setSyncToken(string $syncToken)
* @method string getAttributes()
* @method void setAttributes(string $attributes)
* @method string getDelimiter()
* @method void setDelimiter(string $delimiter)
* @method int getMessages()
* @method void setMessages(int $messages)
* @method int getUnseen()
* @method void setUnseen(int $unseen)
* @method bool getSelectable()
* @method void setSelectable(bool $selectable)
*/
class Mailbox extends Entity {

protected $accountId;
protected $syncToken;
protected $attributes;
protected $delimiter;
protected $messages;
protected $unseen;
protected $selectable;

public function __construct() {
$this->addType('id', 'string');
$this->addType('accountId', 'integer');
$this->addType('messages', 'integer');
$this->addType('unseen', 'integer');
$this->addType('selectable', 'boolean');
}

public function toFolder(): Folder {
$folder = new Folder(
$this->accountId,
new \Horde_Imap_Client_Mailbox($this->id),
json_decode($this->getAttributes() ?? '[]', true) ?? [],
$this->delimiter
);
$folder->setSyncToken($this->getSyncToken());
return $folder;
}

}
51 changes: 51 additions & 0 deletions lib/Db/MailboxMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?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\Db;

use OCA\Mail\Account;
use OCP\AppFramework\Db\QBMapper;
use OCP\IDBConnection;

class MailboxMapper extends QBMapper {

public function __construct(IDBConnection $db) {
parent::__construct($db, 'mail_mailboxes');
}

/**
* @param Account $account
*
* @return Mailbox[]
*/
public function findAll(Account $account): array {
$qb = $this->db->getQueryBuilder();

$select = $qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('account_id', $qb->createNamedParameter($account->getId())));

return $this->findEntities($select);
}

}
20 changes: 14 additions & 6 deletions lib/Folder.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

class Folder implements JsonSerializable {

/** @var Account */
private $account;
/** @var int */
private $accountId;

/** @var Horde_Imap_Client_Mailbox */
private $mailbox;
Expand Down Expand Up @@ -59,8 +59,8 @@ class Folder implements JsonSerializable {
* @param array $attributes
* @param string $delimiter
*/
public function __construct(Account $account, Horde_Imap_Client_Mailbox $mailbox, array $attributes, $delimiter) {
$this->account = $account;
public function __construct(int $accountId, Horde_Imap_Client_Mailbox $mailbox, array $attributes, $delimiter) {
$this->accountId = $accountId;
$this->mailbox = $mailbox;
$this->attributes = $attributes;
$this->delimiter = $delimiter;
Expand Down Expand Up @@ -154,6 +154,10 @@ public function setSyncToken($syncToken) {
$this->syncToken = $syncToken;
}

public function getSyncToken(): ?string {
return $this->syncToken;
}

/**
* @return array
*/
Expand All @@ -164,12 +168,12 @@ public function jsonSerialize() {
}
return [
'id' => base64_encode($this->getMailbox()),
'accountId' => $this->account->getId(),
'accountId' => $this->accountId,
'name' => $this->getDisplayName(),
'unseen' => isset($this->status['unseen']) ? $this->status['unseen'] : 0,
'total' => isset($this->status['messages']) ? (int) $this->status['messages'] : 0,
'isEmpty' => isset($this->status['messages']) ? 0 >= (int) $this->status['messages'] : true,
'noSelect' => in_array('\noselect', $this->attributes),
'noSelect' => !$this->isSelectable(),
'attributes' => $this->attributes,
'delimiter' => $this->delimiter,
'folders' => array_values($folders),
Expand All @@ -179,4 +183,8 @@ public function jsonSerialize() {
];
}

public function isSelectable(): bool {
return !in_array('\noselect', $this->attributes);
}

}
11 changes: 8 additions & 3 deletions lib/IMAP/FolderMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,20 @@ public function getFolders(Account $account, Horde_Imap_Client_Socket $client,
continue;
}

$folder = new Folder($account, $mailbox['mailbox'], $mailbox['attributes'], $mailbox['delimiter']);
$folder = new Folder(
$account->getId(),
$mailbox['mailbox'],
$mailbox['attributes'],
$mailbox['delimiter']
);

if ($folder->isSearchable()) {
$folder->setSyncToken($client->getSyncToken($folder->getMailbox()));
}

$folders[] = $folder;
if ($mailbox['mailbox']->utf8 === 'INBOX') {
$searchFolder = new SearchFolder($account, $mailbox['mailbox'], $mailbox['attributes'], $mailbox['delimiter']);
$searchFolder = new SearchFolder($account->getId(), $mailbox['mailbox'], $mailbox['attributes'], $mailbox['delimiter']);
if ($folder->isSearchable()) {
$searchFolder->setSyncToken($client->getSyncToken($folder->getMailbox()));
}
Expand All @@ -103,7 +108,7 @@ public function createFolder(Horde_Imap_Client_Socket $client,
throw new ServiceException("Created mailbox does not exist");
}

return new Folder($account, $mb['mailbox'], $mb['attributes'], $mb['delimiter']);
return new Folder($account->getId(), $mb['mailbox'], $mb['attributes'], $mb['delimiter']);
}

/**
Expand Down
Loading

0 comments on commit f40aba3

Please sign in to comment.