Skip to content

Commit

Permalink
fix(imap): persist vanished messages immediately on EXAMINE commands
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Steinmetz <[email protected]>
  • Loading branch information
st3iny committed Aug 21, 2024
1 parent 6fc45eb commit f57cc11
Showing 1 changed file with 51 additions and 40 deletions.
91 changes: 51 additions & 40 deletions lib/Cache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,17 @@
use Exception;
use Horde_Imap_Client_Cache_Backend;
use Horde_Imap_Client_Exception;
use InvalidArgumentException;
use OCA\Mail\Account;
use OCA\Mail\Db\MailboxMapper;
use OCA\Mail\Db\MessageMapper;
use OCP\ICache;

/**
* This class is inspired by Horde_Imap_Client_Cache_Backend_Cache of the Horde Project
*/
class Cache extends Horde_Imap_Client_Cache_Backend {
/** Cache structure version. */
public const VERSION = 3;

/**
* The cache object.
*/
protected ICache $_cache;
public const VERSION = 4;

/**
* The working data for the current pageload. All changes take place to
Expand All @@ -52,26 +49,24 @@ class Cache extends Horde_Imap_Client_Cache_Backend {
*/
protected array $_update = [];

/**
* Constructor.
*
* @param array $params Configuration parameters:
*/
public function __construct(array $params = []) {
// Default parameters.
$params = array_merge([
'lifetime' => 604800,
'slicesize' => 50
], array_filter($params));

if (!isset($params['cacheob'])) {
throw new InvalidArgumentException('Missing cacheob parameter.');
}

foreach (['lifetime', 'slicesize'] as $val) {
$params[$val] = intval($params[$val]);
}

/** @var int[]|null **/
private ?array $cachedUids = null;

private ?int $uidvalid = null;

public function __construct(
private MessageMapper $messageMapper,
private MailboxMapper $mailboxMapper,
private Account $account,
private ICache $_cache,
int $lifetime = 604800,
int $slicesize = 50,
) {
$params = [
'lifetime' => $lifetime,
'slicesize' => $slicesize,
'cacheob' => $this->_cache,
];
parent::__construct($params);
}

Expand Down Expand Up @@ -164,13 +159,23 @@ public function get($mailbox, $uids, $fields, $uidvalid) {
return $ret;
}

/** {@inheritDoc} */
public function getCachedUids($mailbox, $uidvalid) {
$this->_loadSliceMap($mailbox, $uidvalid);
return array_unique(array_merge(
array_keys($this->_slicemap[$mailbox]['s']),
(isset($this->_update[$mailbox]) ? $this->_update[$mailbox]['add'] : [])
));
public function getCachedUids($mailbox, $uidvalid): array {
// Delete cached data of mailbox if uidvalid has changed
if ($this->uidvalid !== null && $uidvalid !== null && $this->uidvalid !== $uidvalid) {
$this->_deleteMailbox($mailbox);
}

// Refresh cached uids lazily
if ($this->cachedUids === null) {
$mailboxEntity = $this->mailboxMapper->find($this->account, $mailbox);
$this->cachedUids = $this->messageMapper->findAllUids($mailboxEntity);
}

if ($this->uidvalid === null && $uidvalid !== null) {
$this->uidvalid = $uidvalid;
}

return array_merge([], $this->cachedUids);
}

/**
Expand Down Expand Up @@ -235,12 +240,13 @@ public function setMetaData($mailbox, $data) {
$this->_toUpdate($mailbox, 'slicemap', true);
}

/**
* {@inheritDoc}
*
* @return void
*/
public function deleteMsgs($mailbox, $uids) {
public function deleteMsgs($mailbox, $uids): void {
// Delete uids from the db cache
$mailboxEntity = $this->mailboxMapper->find($this->account, $mailbox);
$this->messageMapper->deleteByUid($mailboxEntity, ...$uids);
$this->cachedUids = array_diff($this->cachedUids, $uids);

// Delete uids from the memory cache
$this->_loadSliceMap($mailbox);

$slicemap = &$this->_slicemap[$mailbox];
Expand Down Expand Up @@ -298,6 +304,8 @@ public function deleteMailbox($mailbox) {
public function clear($lifetime) {
$this->_cache->clear();
$this->_data = $this->_loaded = $this->_slicemap = $this->_update = [];
$this->cachedUids = null;
$this->uidvalid = null;
}

/**
Expand Down Expand Up @@ -339,6 +347,9 @@ protected function _deleteMailbox($mbox): void {
$this->_slicemap[$mbox],
$this->_update[$mbox]
);

$this->cachedUids = null;
$this->uidvalid = null;
}

/**
Expand Down

0 comments on commit f57cc11

Please sign in to comment.