/** * Checks index/thread validity */ private function validate($mailbox, $index, &$exists = true) { $object = $index['object']; $is_thread = is_a($object, 'rcube_result_thread'); // sanity check if (empty($object)) { return false; } $index['validated'] = true; // Get mailbox data (UIDVALIDITY, counters, etc.) for status check $mbox_data = $this->imap->folder_data($mailbox); // @TODO: Think about skipping validation checks. // If we could check only every 10 minutes, we would be able to skip // expensive checks, mailbox selection or even IMAP connection, this would require // additional logic to force cache invalidation in some cases // and many rcube_imap changes to connect when needed // Check UIDVALIDITY if ($index['validity'] != $mbox_data['UIDVALIDITY']) { $this->clear($mailbox); $exists = false; return false; } // Folder is empty but cache isn't if (empty($mbox_data['EXISTS'])) { if (!$object->is_empty()) { $this->clear($mailbox); $exists = false; return false; } } else { if ($object->is_empty()) { unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); return false; } } // Validation flag if (!$is_thread && empty($index['valid'])) { unset($this->icache[$mailbox]['index']); return false; } // Index was created with different skip_deleted setting if ($this->skip_deleted != $index['deleted']) { return false; } // Check HIGHESTMODSEQ if (!empty($index['modseq']) && !empty($mbox_data['HIGHESTMODSEQ']) && $index['modseq'] == $mbox_data['HIGHESTMODSEQ']) { return true; } // Check UIDNEXT if ($index['uidnext'] != $mbox_data['UIDNEXT']) { unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); return false; } // @TODO: find better validity check for threaded index if ($is_thread) { // check messages number... if (!$this->skip_deleted && $mbox_data['EXISTS'] != $object->count_messages()) { return false; } return true; } // The rest of checks, more expensive if (!empty($this->skip_deleted)) { // compare counts if available if (!empty($mbox_data['UNDELETED']) && $mbox_data['UNDELETED']->count() != $object->count()) { return false; } // compare UID sets if (!empty($mbox_data['UNDELETED'])) { $uids_new = $mbox_data['UNDELETED']->get(); $uids_old = $object->get(); if (count($uids_new) != count($uids_old)) { return false; } sort($uids_new, SORT_NUMERIC); sort($uids_old, SORT_NUMERIC); if ($uids_old != $uids_new) { return false; } } else { // get all undeleted messages excluding cached UIDs $ids = $this->imap->search_once($mailbox, 'ALL UNDELETED NOT UID ' . rcube_imap_generic::compressMessageSet($object->get())); if (!$ids->is_empty()) { return false; } } } else { // check messages number... if ($mbox_data['EXISTS'] != $object->count()) { return false; } // ... and max UID if ($object->max() != $this->imap->id2uid($mbox_data['EXISTS'], $mailbox)) { return false; } } return true; }